From aa2877b2fb45611d8cadeaff5687717c2bedeaa0 Mon Sep 17 00:00:00 2001 From: Wu Sheng Date: Thu, 14 Mar 2019 15:50:22 +0800 Subject: [PATCH 1/5] Finish the prototype of async mode in Java agent core APIs. --- .../core/context/AbstractTracerContext.java | 31 +++++---- .../apm/agent/core/context/AsyncSpan.java | 55 +++++++++++++++ .../agent/core/context/ContextManager.java | 19 ++++-- .../core/context/IgnoredTracerContext.java | 8 +++ .../agent/core/context/TracingContext.java | 67 +++++++++++++------ .../core/context/trace/AbstractSpan.java | 3 +- .../context/trace/AbstractTracingSpan.java | 31 ++++++--- .../agent/core/context/trace/NoopSpan.java | 8 +++ .../guides/Java-Plugin-Development-Guide.md | 36 ++++++++++ 9 files changed, 210 insertions(+), 48 deletions(-) create mode 100644 apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java index a7c5453b1..1b3a93bee 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java @@ -16,7 +16,6 @@ * */ - package org.apache.skywalking.apm.agent.core.context; import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; @@ -28,41 +27,38 @@ import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; */ public interface AbstractTracerContext { /** - * Prepare for the cross-process propagation. - * How to initialize the carrier, depends on the implementation. + * Prepare for the cross-process propagation. How to initialize the carrier, depends on the implementation. * * @param carrier to carry the context for crossing process. */ void inject(ContextCarrier carrier); /** - * Build the reference between this segment and a cross-process segment. - * How to build, depends on the implementation. + * Build the reference between this segment and a cross-process segment. How to build, depends on the + * implementation. * * @param carrier carried the context from a cross-process segment. */ void extract(ContextCarrier carrier); /** - * Capture a snapshot for cross-thread propagation. - * It's a similar concept with ActiveSpan.Continuation in OpenTracing-java - * How to build, depends on the implementation. + * Capture a snapshot for cross-thread propagation. It's a similar concept with ActiveSpan.Continuation in + * OpenTracing-java How to build, depends on the implementation. * * @return the {@link ContextSnapshot} , which includes the reference context. */ ContextSnapshot capture(); /** - * Build the reference between this segment and a cross-thread segment. - * How to build, depends on the implementation. + * Build the reference between this segment and a cross-thread segment. How to build, depends on the + * implementation. * * @param snapshot from {@link #capture()} in the parent thread. */ void continued(ContextSnapshot snapshot); /** - * Get the global trace id, if needEnhance. - * How to build, depends on the implementation. + * Get the global trace id, if needEnhance. How to build, depends on the implementation. * * @return the string represents the id. */ @@ -105,4 +101,15 @@ public interface AbstractTracerContext { */ void stopSpan(AbstractSpan span); + /** + * Notify this context, current span is going to be finished async in another thread. + */ + AbstractTracerContext awaitFinishAsync(); + + /** + * The given span could be stopped officially. + * + * @param span to be stopped. + */ + void asyncStop(AsyncSpan span); } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java new file mode 100644 index 000000000..f667f59c5 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.agent.core.context; + +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; + +/** + * Span could use these APIs to active and extend its lift cycle across thread. + * + * This is typical used in async plugin, especially RPC plugins. + * + * @author wusheng + */ +public interface AsyncSpan { + /** + * The span finish at current tracing context, but the current span is still alive, until {@link #asyncFinish} + * called. + * + * This method must be called
+ * 1. In original thread(tracing context). + * 2. Current span is active span. + * + * During alive, tags, logs and attributes of the span could be changed, in any thread. + * + * The execution times of {@link #prepareForAsync} and {@link #asyncFinish()} must match. + * + * @return the current span + */ + AbstractSpan prepareForAsync(); + + /** + * Notify the span, it could be finished. + * + * The execution times of {@link #prepareForAsync} and {@link #asyncFinish()} must match. + * + * @return the current span + */ + AbstractSpan asyncFinish(); +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java index aeaa708d2..378602b9b 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java @@ -18,14 +18,11 @@ package org.apache.skywalking.apm.agent.core.context; -import org.apache.skywalking.apm.agent.core.boot.BootService; -import org.apache.skywalking.apm.agent.core.boot.ServiceManager; +import org.apache.skywalking.apm.agent.core.boot.*; import org.apache.skywalking.apm.agent.core.conf.RemoteDownstreamConfig; -import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; -import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; +import org.apache.skywalking.apm.agent.core.context.trace.*; import org.apache.skywalking.apm.agent.core.dictionary.DictionaryUtil; -import org.apache.skywalking.apm.agent.core.logging.api.ILog; -import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.logging.api.*; import org.apache.skywalking.apm.agent.core.sampling.SamplingService; import org.apache.skywalking.apm.util.StringUtil; @@ -59,7 +56,7 @@ public class ContextManager implements TracingContextListener, BootService, Igno } else { if (RemoteDownstreamConfig.Agent.SERVICE_ID != DictionaryUtil.nullValue() && RemoteDownstreamConfig.Agent.SERVICE_INSTANCE_ID != DictionaryUtil.nullValue() - ) { + ) { context = EXTEND_SERVICE.createTraceContext(operationName, forceSampling); } else { /** @@ -152,6 +149,14 @@ public class ContextManager implements TracingContextListener, BootService, Igno } } + public static AbstractTracerContext awaitFinishAsync(AbstractSpan span) { + AbstractSpan activeSpan = activeSpan(); + if (span != activeSpan) { + throw new RuntimeException("Span is not the active in current context."); + } + return get().awaitFinishAsync(); + } + public static AbstractSpan activeSpan() { return get().activeSpan(); } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java index fd115e566..cef591eec 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java @@ -95,6 +95,14 @@ public class IgnoredTracerContext implements AbstractTracerContext { } } + @Override public AbstractTracerContext awaitFinishAsync() { + return this; + } + + @Override public void asyncStop(AsyncSpan span) { + + } + public static class ListenerManager { private static List LISTENERS = new LinkedList(); diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java index df35adabd..66f90cc94 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java @@ -18,25 +18,14 @@ package org.apache.skywalking.apm.agent.core.context; -import java.util.LinkedList; -import java.util.List; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; import org.apache.skywalking.apm.agent.core.boot.ServiceManager; import org.apache.skywalking.apm.agent.core.conf.Config; -import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; -import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; -import org.apache.skywalking.apm.agent.core.context.trace.EntrySpan; -import org.apache.skywalking.apm.agent.core.context.trace.ExitSpan; -import org.apache.skywalking.apm.agent.core.context.trace.LocalSpan; -import org.apache.skywalking.apm.agent.core.context.trace.NoopExitSpan; -import org.apache.skywalking.apm.agent.core.context.trace.NoopSpan; -import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; -import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef; -import org.apache.skywalking.apm.agent.core.context.trace.WithPeerInfo; -import org.apache.skywalking.apm.agent.core.dictionary.DictionaryManager; -import org.apache.skywalking.apm.agent.core.dictionary.DictionaryUtil; -import org.apache.skywalking.apm.agent.core.dictionary.PossibleFound; -import org.apache.skywalking.apm.agent.core.logging.api.ILog; -import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.context.trace.*; +import org.apache.skywalking.apm.agent.core.dictionary.*; +import org.apache.skywalking.apm.agent.core.logging.api.*; import org.apache.skywalking.apm.agent.core.sampling.SamplingService; import org.apache.skywalking.apm.util.StringUtil; @@ -80,6 +69,13 @@ public class TracingContext implements AbstractTracerContext { */ private int spanIdGenerator; + /** + * The counter indicates + */ + private AtomicInteger asyncSpanCounter; + private volatile boolean isRunningInAsyncMode; + private ReentrantLock asyncFinishLock; + /** * Initialize all fields with default value. */ @@ -89,6 +85,9 @@ public class TracingContext implements AbstractTracerContext { if (samplingService == null) { samplingService = ServiceManager.INSTANCE.findService(SamplingService.class); } + asyncSpanCounter = new AtomicInteger(0); + isRunningInAsyncMode = false; + asyncFinishLock = new ReentrantLock(); } /** @@ -407,11 +406,41 @@ public class TracingContext implements AbstractTracerContext { throw new IllegalStateException("Stopping the unexpected span = " + span); } - if (activeSpanStack.isEmpty()) { - this.finish(); + if (checkFinishConditions()) { + finish(); } } + @Override public AbstractTracerContext awaitFinishAsync() { + isRunningInAsyncMode = true; + asyncSpanCounter.addAndGet(1); + return this; + } + + @Override public void asyncStop(AsyncSpan span) { + asyncSpanCounter.addAndGet(-1); + + if (checkFinishConditions()) { + finish(); + } + } + + private boolean checkFinishConditions() { + if (isRunningInAsyncMode) { + asyncFinishLock.lock(); + } + try { + if (activeSpanStack.isEmpty() && asyncSpanCounter.get() == 0) { + return true; + } + } finally { + if (isRunningInAsyncMode) { + asyncFinishLock.unlock(); + } + } + return false; + } + /** * Finish this context, and notify all {@link TracingContextListener}s, managed by {@link * TracingContext.ListenerManager} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java index 17e8aefb7..00858967c 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java @@ -19,6 +19,7 @@ package org.apache.skywalking.apm.agent.core.context.trace; import java.util.Map; +import org.apache.skywalking.apm.agent.core.context.AsyncSpan; import org.apache.skywalking.apm.agent.core.context.tag.AbstractTag; import org.apache.skywalking.apm.network.trace.component.Component; import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; @@ -28,7 +29,7 @@ import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; * * @author wusheng */ -public interface AbstractSpan { +public interface AbstractSpan extends AsyncSpan { /** * Set the component id, which defines in {@link ComponentsDefine} * diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java index 803ce1b48..e05e8458a 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java @@ -18,15 +18,10 @@ package org.apache.skywalking.apm.agent.core.context.trace; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import org.apache.skywalking.apm.agent.core.context.tag.AbstractTag; -import org.apache.skywalking.apm.agent.core.context.tag.StringTag; -import org.apache.skywalking.apm.agent.core.context.util.KeyValuePair; -import org.apache.skywalking.apm.agent.core.context.util.TagValuePair; -import org.apache.skywalking.apm.agent.core.context.util.ThrowableTransformer; +import java.util.*; +import org.apache.skywalking.apm.agent.core.context.*; +import org.apache.skywalking.apm.agent.core.context.tag.*; +import org.apache.skywalking.apm.agent.core.context.util.*; import org.apache.skywalking.apm.agent.core.dictionary.DictionaryUtil; import org.apache.skywalking.apm.network.language.agent.SpanType; import org.apache.skywalking.apm.network.language.agent.v2.SpanObjectV2; @@ -45,6 +40,9 @@ public abstract class AbstractTracingSpan implements AbstractSpan { protected String operationName; protected int operationId; protected SpanLayer layer; + protected boolean isInAsyncMode = false; + protected volatile AbstractTracerContext context; + /** * The start time of this Span. */ @@ -322,4 +320,19 @@ public abstract class AbstractTracingSpan implements AbstractSpan { refs.add(ref); } } + + @Override public AbstractSpan prepareForAsync() { + context = ContextManager.awaitFinishAsync(this); + return this; + } + + @Override public AbstractSpan asyncFinish() { + if (!isInAsyncMode) { + throw new RuntimeException("Span is not in async mode, please use '#prepareForAsync' to active."); + } + + this.endTime = System.currentTimeMillis(); + context.asyncStop(this); + return this; + } } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopSpan.java index 774ebca69..d91a813fb 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopSpan.java @@ -115,4 +115,12 @@ public class NoopSpan implements AbstractSpan { @Override public AbstractSpan setPeer(String remotePeer) { return this; } + + @Override public AbstractSpan prepareForAsync() { + return this; + } + + @Override public AbstractSpan asyncFinish() { + return this; + } } diff --git a/docs/en/guides/Java-Plugin-Development-Guide.md b/docs/en/guides/Java-Plugin-Development-Guide.md index fd6ed452f..992770700 100644 --- a/docs/en/guides/Java-Plugin-Development-Guide.md +++ b/docs/en/guides/Java-Plugin-Development-Guide.md @@ -160,6 +160,42 @@ SpanLayer is the catalog of span. Here are 5 values: Component IDs are defined and reserved by SkyWalking project. For component name/ID extension, please follow [cComponent library definition and extension](Component-library-settings.md) document. +### Advanced APIs +#### Async Span APIs +There is a set of advanced APIs in Span, which work specific for async scenario. When tags, logs, attributes(including end time) of the span +needs to set in another thread, you should use these APIs. + +```java + /** + * The span finish at current tracing context, but the current span is still alive, until {@link #asyncFinish} + * called. + * + * This method must be called
+ * 1. In original thread(tracing context). + * 2. Current span is active span. + * + * During alive, tags, logs and attributes of the span could be changed, in any thread. + * + * The execution times of {@link #prepareForAsync} and {@link #asyncFinish()} must match. + * + * @return the current span + */ + AbstractSpan prepareForAsync(); + + /** + * Notify the span, it could be finished. + * + * The execution times of {@link #prepareForAsync} and {@link #asyncFinish()} must match. + * + * @return the current span + */ + AbstractSpan asyncFinish(); +``` +1. Call `#prepareForAsync` in original context. +1. Propagate the span to any other thread. +1. After all set, call `#asyncFinish` in any thread. +1. Tracing context will be finished and report to backend when all spans's `#prepareForAsync` finished(Judged by count of API execution). + ## Develop a plugin ### Abstract The basic method to trace is intercepting a Java method, by using byte code manipulation tech and AOP concept. From b3e043569c3d7bd1594ea19e6804bc1be2fa82cd Mon Sep 17 00:00:00 2001 From: Wu Sheng Date: Thu, 14 Mar 2019 16:11:07 +0800 Subject: [PATCH 2/5] Fix two javadoc --- .../apm/agent/core/context/AbstractTracerContext.java | 2 ++ .../apache/skywalking/apm/agent/core/context/AsyncSpan.java | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java index 1b3a93bee..e9e1ed0d8 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java @@ -103,6 +103,8 @@ public interface AbstractTracerContext { /** * Notify this context, current span is going to be finished async in another thread. + * + * @return The current context */ AbstractTracerContext awaitFinishAsync(); diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java index f667f59c5..8b3e81dd7 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java @@ -32,7 +32,8 @@ public interface AsyncSpan { * The span finish at current tracing context, but the current span is still alive, until {@link #asyncFinish} * called. * - * This method must be called
+ * This method must be called + * * 1. In original thread(tracing context). * 2. Current span is active span. * From 930e73f1a1dcec26eb64fdfe042c2a73b44efeaf Mon Sep 17 00:00:00 2001 From: Wu Sheng Date: Thu, 14 Mar 2019 20:37:38 +0800 Subject: [PATCH 3/5] Finish the context based on #stopSpan result, rather than listener. --- .../core/context/AbstractTracerContext.java | 3 ++- .../apm/agent/core/context/AsyncSpan.java | 2 +- .../apm/agent/core/context/ContextManager.java | 18 ++++-------------- .../context/ContextManagerExtendService.java | 9 +-------- .../core/context/IgnoredTracerContext.java | 14 ++++++-------- .../apm/agent/core/context/TracingContext.java | 4 +++- 6 files changed, 17 insertions(+), 33 deletions(-) diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java index e9e1ed0d8..4b3cd2d68 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java @@ -98,8 +98,9 @@ public interface AbstractTracerContext { * Finish the given span, and the given span should be the active span of current tracing context(stack) * * @param span to finish + * @return true when context should be clear. */ - void stopSpan(AbstractSpan span); + boolean stopSpan(AbstractSpan span); /** * Notify this context, current span is going to be finished async in another thread. diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java index 8b3e81dd7..8e2483e23 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AsyncSpan.java @@ -33,7 +33,7 @@ public interface AsyncSpan { * called. * * This method must be called - * + * * 1. In original thread(tracing context). * 2. Current span is active span. * diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java index 378602b9b..2dbdb3574 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java @@ -36,7 +36,7 @@ import org.apache.skywalking.apm.util.StringUtil; * * @author wusheng */ -public class ContextManager implements TracingContextListener, BootService, IgnoreTracerContextListener { +public class ContextManager implements BootService { private static final ILog logger = LogManager.getLogger(ContextManager.class); private static ThreadLocal CONTEXT = new ThreadLocal(); private static ThreadLocal RUNTIME_CONTEXT = new ThreadLocal(); @@ -166,7 +166,9 @@ public class ContextManager implements TracingContextListener, BootService, Igno } public static void stopSpan(AbstractSpan span) { - get().stopSpan(span); + if (get().stopSpan(span)) { + CONTEXT.remove(); + } } @Override @@ -176,8 +178,6 @@ public class ContextManager implements TracingContextListener, BootService, Igno @Override public void boot() { - ContextManagerExtendService service = ServiceManager.INSTANCE.findService(ContextManagerExtendService.class); - service.registerListeners(this); } @Override @@ -189,16 +189,6 @@ public class ContextManager implements TracingContextListener, BootService, Igno } - @Override - public void afterFinished(TraceSegment traceSegment) { - CONTEXT.remove(); - } - - @Override - public void afterFinished(IgnoredTracerContext traceSegment) { - CONTEXT.remove(); - } - public static boolean isActive() { return get() != null; } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManagerExtendService.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManagerExtendService.java index f97853af8..d25e915f0 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManagerExtendService.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManagerExtendService.java @@ -18,9 +18,7 @@ package org.apache.skywalking.apm.agent.core.context; -import org.apache.skywalking.apm.agent.core.boot.BootService; -import org.apache.skywalking.apm.agent.core.boot.DefaultImplementor; -import org.apache.skywalking.apm.agent.core.boot.ServiceManager; +import org.apache.skywalking.apm.agent.core.boot.*; import org.apache.skywalking.apm.agent.core.conf.Config; import org.apache.skywalking.apm.agent.core.sampling.SamplingService; @@ -45,11 +43,6 @@ public class ContextManagerExtendService implements BootService { } - public void registerListeners(ContextManager manager) { - TracingContext.ListenerManager.add(manager); - IgnoredTracerContext.ListenerManager.add(manager); - } - public AbstractTracerContext createTraceContext(String operationName, boolean forceSampling) { AbstractTracerContext context; int suffixIdx = operationName.lastIndexOf("."); diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java index cef591eec..59bc05cd4 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java @@ -16,17 +16,14 @@ * */ - package org.apache.skywalking.apm.agent.core.context; -import java.util.LinkedList; -import java.util.List; -import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; -import org.apache.skywalking.apm.agent.core.context.trace.NoopSpan; +import java.util.*; +import org.apache.skywalking.apm.agent.core.context.trace.*; /** - * The IgnoredTracerContext represent a context should be ignored. - * So it just maintains the stack with an integer depth field. + * The IgnoredTracerContext represent a context should be ignored. So it just maintains the stack with an + * integer depth field. * * All operations through this will be ignored, and keep the memory and gc cost as low as possible. * @@ -88,11 +85,12 @@ public class IgnoredTracerContext implements AbstractTracerContext { } @Override - public void stopSpan(AbstractSpan span) { + public boolean stopSpan(AbstractSpan span) { stackDepth--; if (stackDepth == 0) { ListenerManager.notifyFinish(this); } + return stackDepth == 0; } @Override public AbstractTracerContext awaitFinishAsync() { diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java index 66f90cc94..773907339 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java @@ -391,7 +391,7 @@ public class TracingContext implements AbstractTracerContext { * @param span to finish */ @Override - public void stopSpan(AbstractSpan span) { + public boolean stopSpan(AbstractSpan span) { AbstractSpan lastSpan = peek(); if (lastSpan == span) { if (lastSpan instanceof AbstractTracingSpan) { @@ -409,6 +409,8 @@ public class TracingContext implements AbstractTracerContext { if (checkFinishConditions()) { finish(); } + + return activeSpanStack.isEmpty(); } @Override public AbstractTracerContext awaitFinishAsync() { From 584cd540d40846f742003c5586289b0b49ffe46d Mon Sep 17 00:00:00 2001 From: Wu Sheng Date: Thu, 14 Mar 2019 20:58:00 +0800 Subject: [PATCH 4/5] Fix test cases. --- .../skywalking/apm/agent/core/boot/ServiceManagerTest.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/boot/ServiceManagerTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/boot/ServiceManagerTest.java index afe858d44..462234950 100644 --- a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/boot/ServiceManagerTest.java +++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/boot/ServiceManagerTest.java @@ -69,16 +69,13 @@ public class ServiceManagerTest { private void assertIgnoreTracingContextListener() throws Exception { List listeners = getFieldValue(IgnoredTracerContext.ListenerManager.class, "LISTENERS"); - assertThat(listeners.size(), is(1)); - - assertThat(listeners.contains(ServiceManager.INSTANCE.findService(ContextManager.class)), is(true)); + assertThat(listeners.size(), is(0)); } private void assertTracingContextListener() throws Exception { List listeners = getFieldValue(TracingContext.ListenerManager.class, "LISTENERS"); - assertThat(listeners.size(), is(2)); + assertThat(listeners.size(), is(1)); - assertThat(listeners.contains(ServiceManager.INSTANCE.findService(ContextManager.class)), is(true)); assertThat(listeners.contains(ServiceManager.INSTANCE.findService(TraceSegmentServiceClient.class)), is(true)); } From ad375891b4bba61060f440add46f7b5af610c27c Mon Sep 17 00:00:00 2001 From: Brandon Fergerson Date: Sat, 16 Mar 2019 08:21:36 +0800 Subject: [PATCH 5/5] Update apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java Fix isInAsyncMode never be set. Co-Authored-By: wu-sheng --- .../apm/agent/core/context/trace/AbstractTracingSpan.java | 1 + 1 file changed, 1 insertion(+) diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java index e05e8458a..4c14aa2b1 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java @@ -323,6 +323,7 @@ public abstract class AbstractTracingSpan implements AbstractSpan { @Override public AbstractSpan prepareForAsync() { context = ContextManager.awaitFinishAsync(this); + isInAsyncMode = true; return this; }