From 1a501e87958bcef7227013007b601da6989e9652 Mon Sep 17 00:00:00 2001 From: kangji Date: Fri, 18 Feb 2022 18:28:52 +0900 Subject: [PATCH] [#8642] Disable async trace to limit span event --- .../profiler/context/AsyncChildTrace.java | 4 +- .../profiler/context/AsyncContextFactory.java | 4 +- .../profiler/context/AsyncTraceContext.java | 4 +- .../profiler/context/BaseTraceFactory.java | 2 +- .../pinpoint/profiler/context/CallStack.java | 4 +- .../profiler/context/DefaultAsyncContext.java | 22 ++- .../context/DefaultAsyncContextFactory.java | 8 +- .../context/DefaultAsyncTraceContext.java | 12 +- .../context/DefaultBaseTraceFactory.java | 23 +-- .../profiler/context/DefaultCallStack.java | 6 +- .../profiler/context/DefaultTrace.java | 4 +- .../context/DisableAsyncChildTrace.java | 155 ++++++++++++++++++ .../profiler/context/DisableSpanEvent.java | 9 + .../context/LoggingBaseTraceFactory.java | 6 +- .../profiler/context/SpanEventFactory.java | 19 +-- .../context/StatefulAsyncContext.java | 4 +- .../WrappedAsyncSpanEventRecorder.java | 3 +- .../recorder/WrappedSpanEventRecorder.java | 11 +- .../profiler/context/AsyncContextTest.java | 97 +++++++++++ .../profiler/context/CallStackTest.java | 12 +- .../context/DefaultAsyncContextTest.java | 11 ++ .../context/DefaultAsyncTraceContextTest.java | 96 +++++++++++ .../profiler/context/DisableTraceTest.java | 46 ++++++ .../context/SpanEventFactoryTest.java | 6 +- .../context/StatefulAsyncContextTest.java | 27 +++ 25 files changed, 525 insertions(+), 70 deletions(-) create mode 100644 profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableAsyncChildTrace.java create mode 100644 profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableSpanEvent.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/context/AsyncContextTest.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContextTest.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContextTest.java create mode 100644 profiler/src/test/java/com/navercorp/pinpoint/profiler/context/StatefulAsyncContextTest.java diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java index 6e768bb73f47..f3a5b56cf6ad 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java @@ -269,12 +269,12 @@ private SpanEvent newSpanEvent(int stackId) { @VisibleForTesting SpanEvent dummySpanEvent() { - return callStack.getFactory().dummyInstance(); + return callStack.getFactory().disableInstance(); } @VisibleForTesting boolean isDummySpanEvent(final SpanEvent spanEvent) { - return callStack.getFactory().isDummy(spanEvent); + return callStack.getFactory().isDisable(spanEvent); } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncContextFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncContextFactory.java index 4fa92e0da4d2..29debce17586 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncContextFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncContextFactory.java @@ -27,8 +27,8 @@ public interface AsyncContextFactory { AsyncId newAsyncId(); - AsyncContext newAsyncContext(TraceRoot traceRoot, AsyncId asyncId); + AsyncContext newAsyncContext(TraceRoot traceRoot, AsyncId asyncId, boolean canSampled); - AsyncContext newAsyncContext(TraceRoot traceRoot, AsyncId asyncId, AsyncState asyncState); + AsyncContext newAsyncContext(TraceRoot traceRoot, AsyncId asyncId, boolean canSampled, AsyncState asyncState); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncTraceContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncTraceContext.java index 606644069b01..670099402bab 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncTraceContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncTraceContext.java @@ -27,9 +27,9 @@ public interface AsyncTraceContext { // Reference continueAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence); - Reference continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId); + Reference continueAsyncContextTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId, boolean canSampled); - Trace newAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId); + Trace newAsyncContextTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId, boolean canSampled); Reference currentRawTraceObject(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/BaseTraceFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/BaseTraceFactory.java index 74fd41f6e9f2..992ff09b7d01 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/BaseTraceFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/BaseTraceFactory.java @@ -34,7 +34,7 @@ public interface BaseTraceFactory { @InterfaceAudience.LimitedPrivate("vert.x") Trace continueAsyncTraceObject(TraceId traceId); - Trace continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId); + Trace continueAsyncContextTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId, boolean canSampled); Trace newTraceObject(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java index 8da832deabc6..62ba0d2e35db 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java @@ -45,9 +45,9 @@ interface Factory { T newInstance(); - T dummyInstance(); + T disableInstance(); - boolean isDummy(T element); + boolean isDisable(T element); void markDepth(T element, int index); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContext.java index 3cf9eb65bf6f..283524e578ef 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContext.java @@ -38,19 +38,21 @@ public class DefaultAsyncContext implements AsyncContext { private final TraceRoot traceRoot; private final AsyncId asyncId; + private final boolean canSampled; private final AsyncTraceContext asyncTraceContext; private final int asyncMethodApiId; - public DefaultAsyncContext(AsyncTraceContext asyncTraceContext, TraceRoot traceRoot, AsyncId asyncId, int asyncMethodApiId) { + public DefaultAsyncContext(AsyncTraceContext asyncTraceContext, TraceRoot traceRoot, AsyncId asyncId, int asyncMethodApiId, boolean canSampled) { this.asyncTraceContext = Objects.requireNonNull(asyncTraceContext, "asyncTraceContext"); this.traceRoot = Objects.requireNonNull(traceRoot, "traceRoot"); this.asyncId = Objects.requireNonNull(asyncId, "asyncId"); this.asyncMethodApiId = asyncMethodApiId; + this.canSampled = canSampled; } @@ -71,14 +73,14 @@ public Trace continueAsyncTraceObject() { return null; } - return newAsyncTrace(reference); + return newAsyncContextTrace(reference); } - private Trace newAsyncTrace(Reference reference) { + private Trace newAsyncContextTrace(Reference reference) { // final int asyncId = this.asyncId.getAsyncId(); // final short asyncSequence = this.asyncId.nextAsyncSequence(); final LocalAsyncId localAsyncId = this.asyncId.nextLocalAsyncId(); - final Trace asyncTrace = asyncTraceContext.newAsyncTraceObject(traceRoot, localAsyncId); + final Trace asyncTrace = asyncTraceContext.newAsyncContextTraceObject(traceRoot, localAsyncId, canSampled); bind(reference, asyncTrace); @@ -104,10 +106,16 @@ private Trace newAsyncTrace(Reference reference) { // first block. final SpanEventRecorder recorder = asyncTrace.currentSpanEventRecorder(); - recorder.recordServiceType(ServiceType.ASYNC); - recorder.recordApiId(asyncMethodApiId); - return asyncTrace; + if (recorder != null) { + recorder.recordServiceType(ServiceType.ASYNC); + recorder.recordApiId(asyncMethodApiId); + } + + if (asyncTrace.canSampled()) { + return asyncTrace; + } + return null; } private void bind(Reference reference, Trace asyncTrace) { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContextFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContextFactory.java index e4bc0a220973..22fdcbb11375 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContextFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContextFactory.java @@ -55,20 +55,20 @@ public AsyncId newAsyncId() { } @Override - public AsyncContext newAsyncContext(TraceRoot traceRoot, AsyncId asyncId) { + public AsyncContext newAsyncContext(TraceRoot traceRoot, AsyncId asyncId, boolean canSampled) { Objects.requireNonNull(traceRoot, "traceRoot"); Objects.requireNonNull(asyncId, "asyncId"); - return new DefaultAsyncContext(asyncTraceContext, traceRoot, asyncId, this.asyncMethodApiId); + return new DefaultAsyncContext(asyncTraceContext, traceRoot, asyncId, this.asyncMethodApiId, canSampled); } @Override - public AsyncContext newAsyncContext(TraceRoot traceRoot, AsyncId asyncId, AsyncState asyncState) { + public AsyncContext newAsyncContext(TraceRoot traceRoot, AsyncId asyncId, boolean canSampled, AsyncState asyncState) { Objects.requireNonNull(traceRoot, "traceRoot"); Objects.requireNonNull(asyncId, "asyncId"); Objects.requireNonNull(asyncState, "asyncState"); - return new StatefulAsyncContext(asyncTraceContext, traceRoot, asyncId, asyncMethodApiId, asyncState); + return new StatefulAsyncContext(asyncTraceContext, traceRoot, asyncId, asyncMethodApiId, asyncState, canSampled); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContext.java index 2a84fb20e3a5..a1a6c44c4d76 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContext.java @@ -43,27 +43,25 @@ public DefaultAsyncTraceContext(Provider baseTraceFactoryProvi } @Override - public Reference continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId) { + public Reference continueAsyncContextTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId, boolean canSampled) { final Reference reference = checkAndGet(); - final BaseTraceFactory baseTraceFactory = baseTraceFactoryProvider.get(); - final Trace trace = baseTraceFactory.continueAsyncTraceObject(traceRoot, localAsyncId); + final Trace trace = newAsyncContextTraceObject(traceRoot, localAsyncId, canSampled); bind(reference, trace); return reference; } @Override - public Trace newAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId) { + public Trace newAsyncContextTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId, boolean canSampled) { final BaseTraceFactory baseTraceFactory = baseTraceFactoryProvider.get(); - return baseTraceFactory.continueAsyncTraceObject(traceRoot, localAsyncId); + return baseTraceFactory.continueAsyncContextTraceObject(traceRoot, localAsyncId, canSampled); } @Override public Reference currentRawTraceObject() { - final Reference reference = binder.get(); - return reference; + return binder.get(); } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java index 14ee341f591b..0346ab4f322a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java @@ -128,21 +128,24 @@ public Trace newTraceObject() { // internal async trace. @Override - public Trace continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId) { - - final SpanChunkFactory spanChunkFactory = new AsyncSpanChunkFactory(traceRoot, localAsyncId); - final Storage storage = storageFactory.createStorage(spanChunkFactory); + public Trace continueAsyncContextTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId, boolean canSampled) { + if (canSampled) { + final SpanChunkFactory spanChunkFactory = new AsyncSpanChunkFactory(traceRoot, localAsyncId); + final Storage storage = storageFactory.createStorage(spanChunkFactory); - final CallStack callStack = callStackFactory.newCallStack(); + final CallStack callStack = callStackFactory.newCallStack(); - final boolean samplingEnable = true; - final SpanRecorder spanRecorder = recorderFactory.newTraceRootSpanRecorder(traceRoot, samplingEnable); + final boolean samplingEnable = true; + final SpanRecorder spanRecorder = recorderFactory.newTraceRootSpanRecorder(traceRoot, samplingEnable); - final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(traceRoot); + final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(traceRoot); - final Trace asyncTrace = new AsyncChildTrace(traceRoot, callStack, storage, samplingEnable, spanRecorder, wrappedSpanEventRecorder, localAsyncId); + final Trace asyncTrace = new AsyncChildTrace(traceRoot, callStack, storage, samplingEnable, spanRecorder, wrappedSpanEventRecorder, localAsyncId); - return asyncTrace; + return asyncTrace; + } else { + return new DisableAsyncChildTrace(traceRoot, localAsyncId); + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java index b4f83a682bfe..0a35515257a8 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java @@ -105,7 +105,7 @@ private void checkExtend(final int size) { public T pop() { if (isOverflow() && overflowIndex > 0) { overflowIndex--; - return factory.dummyInstance(); + return factory.disableInstance(); } final T spanEvent = peek(); @@ -123,7 +123,7 @@ public T peek() { } if (isOverflow() && overflowIndex > 0) { - return factory.dummyInstance(); + return factory.disableInstance(); } return stack[index - 1]; } @@ -168,7 +168,7 @@ private boolean isSequenceOverflow() { @Override public T newInstance() { if (isOverflow()) { - return factory.dummyInstance(); + return factory.disableInstance(); } else { return factory.newInstance(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java index ace666c83e24..bd8a4cd662f4 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java @@ -281,12 +281,12 @@ private SpanEvent newSpanEvent(int stackId) { @VisibleForTesting SpanEvent dummySpanEvent() { - return callStack.getFactory().dummyInstance(); + return callStack.getFactory().disableInstance(); } @VisibleForTesting boolean isDummySpanEvent(final SpanEvent spanEvent) { - return callStack.getFactory().isDummy(spanEvent); + return callStack.getFactory().isDisable(spanEvent); } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableAsyncChildTrace.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableAsyncChildTrace.java new file mode 100644 index 000000000000..9c03b4ce8525 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableAsyncChildTrace.java @@ -0,0 +1,155 @@ +/* + * Copyright 2022 NAVER Corp. + * + * Licensed 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 com.navercorp.pinpoint.profiler.context; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.scope.DefaultTraceScopePool; + +import java.util.Objects; + +public class DisableAsyncChildTrace implements Trace { + // private static final int ASYNC_BEGIN_STACK_ID = 1001; + public static final String UNSUPPORTED_OPERATION = "disable async child trace"; + + private boolean closed = false; + + private DefaultTraceScopePool scopePool; + + private final TraceRoot traceRoot; + private final LocalAsyncId localAsyncId; + + public DisableAsyncChildTrace(final TraceRoot traceRoot, final LocalAsyncId localAsyncId) { + this.traceRoot = Objects.requireNonNull(traceRoot, "traceRoot"); + this.localAsyncId = Objects.requireNonNull(localAsyncId, "localAsyncId"); + } + + @Override + public SpanEventRecorder traceBlockBegin() { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION); + } + + @Override + public SpanEventRecorder traceBlockBegin(int stackId) { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION); + } + + @Override + public void traceBlockEnd() { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION); + } + + @Override + public void traceBlockEnd(int stackId) { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION); + } + + @Override + public boolean isRootStack() { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION); + } + + @Override + public int getCallStackFrameId() { + return 0; + } + + private TraceRoot getTraceRoot() { + return this.traceRoot; + } + + @Override + public long getId() { + return getTraceRoot().getLocalTransactionId(); + } + + @Override + public long getStartTime() { + return getTraceRoot().getTraceStartTime(); + } + + @Override + public TraceId getTraceId() { + return getTraceRoot().getTraceId(); + } + + @Override + public boolean canSampled() { + return false; + } + + @Override + public boolean isRoot() { + return this.getTraceId().isRoot(); + } + + @Override + public boolean isAsync() { + return true; + } + + @Override + public SpanRecorder getSpanRecorder() { + return null; + } + + @Override + public SpanEventRecorder currentSpanEventRecorder() { + return null; + } + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public void close() { + if (closed) { + return; + } + closed = true; + } + + @Override + public TraceScope getScope(String name) { + if (scopePool == null) { + return null; + } + return scopePool.get(name); + } + + @Override + public TraceScope addScope(String name) { + if (scopePool == null) { + scopePool = new DefaultTraceScopePool(); + } + return scopePool.add(name); + } + + @Override + public String toString() { + return "DisableAsyncChildTrace{" + + "traceRoot=" + getTraceRoot() + + ", localAsyncId=" + localAsyncId + + '}'; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableSpanEvent.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableSpanEvent.java new file mode 100644 index 000000000000..c9017642bfde --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableSpanEvent.java @@ -0,0 +1,9 @@ +package com.navercorp.pinpoint.profiler.context; + +public class DisableSpanEvent extends SpanEvent { + @Override + public String toString() { + return "DisableSpanEvent"; + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LoggingBaseTraceFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LoggingBaseTraceFactory.java index 6345795ee0a8..558e213727b8 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LoggingBaseTraceFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LoggingBaseTraceFactory.java @@ -72,12 +72,12 @@ public Trace continueAsyncTraceObject(TraceId traceId) { } @Override - public Trace continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId) { + public Trace continueAsyncContextTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId, boolean canSampled) { if (logger.isDebugEnabled()) { - logger.debug("continueAsyncTraceObject(traceRoot:{}, localAsyncId:{})", traceRoot, localAsyncId); + logger.debug("continueAsyncTraceObject(traceRoot:{}, localAsyncId:{}, canSampled:{})", traceRoot, localAsyncId, canSampled); } - return baseTraceFactory.continueAsyncTraceObject(traceRoot, localAsyncId); + return baseTraceFactory.continueAsyncContextTraceObject(traceRoot, localAsyncId, canSampled); } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventFactory.java index e801713b0439..9c233f27d92b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventFactory.java @@ -31,14 +31,17 @@ public SpanEvent newInstance() { } @Override - public SpanEvent dummyInstance() { - final SpanEvent spanEvent = new DummySpanEvent(); - return spanEvent; + public SpanEvent disableInstance() { + return new DisableSpanEvent(); } @Override - public boolean isDummy(SpanEvent element) { - return element instanceof DummySpanEvent; + public boolean isDisable(SpanEvent element) { + return isDisableSpanEvent(element); + } + + public static boolean isDisableSpanEvent(SpanEvent spanEvent) { + return spanEvent instanceof DisableSpanEvent; } @Override @@ -56,10 +59,4 @@ public String toString() { return "SpanEventFactory{}"; } - private static class DummySpanEvent extends SpanEvent { - @Override - public String toString() { - return "DummySpanEvent"; - } - } } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/StatefulAsyncContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/StatefulAsyncContext.java index b08ecbc1c404..14c2ecc8666c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/StatefulAsyncContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/StatefulAsyncContext.java @@ -30,8 +30,8 @@ public class StatefulAsyncContext extends DefaultAsyncContext implements AsyncSt private final AsyncState asyncState; - public StatefulAsyncContext(AsyncTraceContext asyncTraceContext, TraceRoot traceRoot, AsyncId asyncId, int asyncMethodApiId, AsyncState asyncState) { - super(asyncTraceContext, traceRoot, asyncId, asyncMethodApiId); + public StatefulAsyncContext(AsyncTraceContext asyncTraceContext, TraceRoot traceRoot, AsyncId asyncId, int asyncMethodApiId, AsyncState asyncState, boolean canSampled) { + super(asyncTraceContext, traceRoot, asyncId, asyncMethodApiId, canSampled); this.asyncState = Objects.requireNonNull(asyncState, "asyncState"); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedAsyncSpanEventRecorder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedAsyncSpanEventRecorder.java index 46ba2cb6cb5f..0fce37b8be51 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedAsyncSpanEventRecorder.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedAsyncSpanEventRecorder.java @@ -48,10 +48,11 @@ public AsyncContext recordNextAsyncContext(boolean asyncStateSupport) { if (asyncStateSupport) { final TraceRoot traceRoot = this.traceRoot; final AsyncId asyncIdObject = getNextAsyncId(); + final boolean isDisabled = isOverflowState(); final AsyncState asyncState = this.asyncState; asyncState.setup(); - final AsyncContext asyncContext = asyncContextFactory.newAsyncContext(traceRoot, asyncIdObject, asyncState); + final AsyncContext asyncContext = asyncContextFactory.newAsyncContext(traceRoot, asyncIdObject, isDisabled, asyncState); return asyncContext; } return recordNextAsyncContext(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorder.java index 2310a2ecbbf5..d84c38d76bed 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorder.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorder.java @@ -29,6 +29,7 @@ import com.navercorp.pinpoint.profiler.context.Annotation; import com.navercorp.pinpoint.profiler.context.AsyncContextFactory; import com.navercorp.pinpoint.profiler.context.AsyncId; +import com.navercorp.pinpoint.profiler.context.SpanEventFactory; import com.navercorp.pinpoint.profiler.context.annotation.Annotations; import com.navercorp.pinpoint.profiler.context.DefaultTrace; import com.navercorp.pinpoint.profiler.context.SpanEvent; @@ -124,8 +125,14 @@ public void recordNextSpanId(long nextSpanId) { public AsyncContext recordNextAsyncContext() { final TraceRoot traceRoot = this.traceRoot; final AsyncId asyncIdObject = getNextAsyncId(); - final AsyncContext asyncContext = asyncContextFactory.newAsyncContext(traceRoot, asyncIdObject); - return asyncContext; + // sequence or stack overflow + final boolean canSampled = isOverflowState(); + return asyncContextFactory.newAsyncContext(traceRoot, asyncIdObject, canSampled); + } + + // add more conditions to disable asynchronous invocation trace + protected boolean isOverflowState() { + return !SpanEventFactory.isDisableSpanEvent(spanEvent); } @Override diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/AsyncContextTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/AsyncContextTest.java new file mode 100644 index 000000000000..68fb7a78a0a8 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/AsyncContextTest.java @@ -0,0 +1,97 @@ +package com.navercorp.pinpoint.profiler.context; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.provider.BaseTraceFactoryProvider; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +@RunWith(MockitoJUnitRunner.class) +public abstract class AsyncContextTest { + @Mock + protected TraceRoot traceRoot; + @Mock + protected AsyncId asyncId; + + abstract AsyncContext newAsyncContext(final boolean canSampled); + + protected AsyncTraceContext newAsyncTraceContext() { + BaseTraceFactory baseTraceFactory = mock(DefaultBaseTraceFactory.class); + BaseTraceFactoryProvider baseTraceFactoryProvider = mock(BaseTraceFactoryProvider.class); + + when(baseTraceFactory.continueAsyncContextTraceObject(any(TraceRoot.class), any(LocalAsyncId.class), eq(true))) + .thenAnswer(new Answer() { + @Override + public Trace answer(InvocationOnMock invocationOnMock) { + Trace trace = mock(AsyncChildTrace.class); + when(trace.canSampled()).thenReturn(true); + return trace; + } + }); + when(baseTraceFactory.continueAsyncContextTraceObject(any(TraceRoot.class), any(LocalAsyncId.class), eq(false))) + .thenAnswer(new Answer() { + @Override + public Trace answer(InvocationOnMock invocationOnMock) { + return mock(DisableAsyncChildTrace.class); + } + }); + when(baseTraceFactoryProvider.get()).thenReturn(baseTraceFactory); + + return new DefaultAsyncTraceContext(baseTraceFactoryProvider, new ThreadLocalBinder()); + } + + @Before + public void setUp() { + LocalAsyncId localAsyncId = new DefaultLocalAsyncId(0, 0); + when(asyncId.nextLocalAsyncId()).thenReturn(localAsyncId); + } + + @Test + public void testAsyncTraceObject() { + AsyncContext enabledAsyncContext = newAsyncContext(true); + AsyncContext disabledAsyncContext = newAsyncContext(false); + + // at first, trace object must be null + assertNull(enabledAsyncContext.currentAsyncTraceObject()); + assertNull(disabledAsyncContext.currentAsyncTraceObject()); + + // invoke continueTraceObject + Trace enabledTrace = enabledAsyncContext.continueAsyncTraceObject(); + Trace disabledTrace = disabledAsyncContext.continueAsyncTraceObject(); + assertTrue(enabledTrace instanceof AsyncChildTrace); + assertNull(disabledTrace); + + // check current trace object + assertEquals(enabledTrace, enabledAsyncContext.currentAsyncTraceObject()); + assertNull(disabledAsyncContext.currentAsyncTraceObject()); + + // re-invocation of continueTraceObject must not change trace object + Trace anotherEnabledTrace = enabledAsyncContext.continueAsyncTraceObject(); + assertEquals(enabledTrace, anotherEnabledTrace); + } + + @Test + public void testClose() { + AsyncContext asyncContext = newAsyncContext(true); + + // invoke continueTraceObject + Trace trace = asyncContext.continueAsyncTraceObject(); + assertNotNull(trace); + + // close + asyncContext.close(); + assertNull(asyncContext.currentAsyncTraceObject()); + } +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/CallStackTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/CallStackTest.java index da45204766d3..cc846c5b264f 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/CallStackTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/CallStackTest.java @@ -111,7 +111,7 @@ public void newInstance() { callStack.push(spanEvent1); SpanEvent spanEvent2 = callStack.newInstance(); - Assert.assertTrue(callStack.getFactory().isDummy(spanEvent2)); + Assert.assertTrue(callStack.getFactory().isDisable(spanEvent2)); } @Test @@ -173,19 +173,19 @@ public void overflow2() { // overflow by sequence assertEquals(maxDepth - 1, callStack.getIndex()); assertTrue(callStack.isOverflow()); - assertFalse(callStack.getFactory().isDummy(callStack.peek())); + assertFalse(callStack.getFactory().isDisable(callStack.peek())); callStack.push(getSpanEvent()); assertEquals(maxDepth, callStack.getIndex()); - assertTrue(callStack.getFactory().isDummy(callStack.peek())); - assertTrue(callStack.getFactory().isDummy(callStack.pop())); + assertTrue(callStack.getFactory().isDisable(callStack.peek())); + assertTrue(callStack.getFactory().isDisable(callStack.pop())); for (int i = maxDepth - 1; i > 0; i--) { assertNotNull(callStack.peek()); - assertFalse(callStack.getFactory().isDummy(callStack.peek())); + assertFalse(callStack.getFactory().isDisable(callStack.peek())); SpanEvent element = callStack.pop(); assertNotNull(element); - assertFalse(callStack.getFactory().isDummy(element)); + assertFalse(callStack.getFactory().isDisable(element)); assertTrue(callStack.isOverflow()); } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContextTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContextTest.java new file mode 100644 index 000000000000..840d04ff436c --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContextTest.java @@ -0,0 +1,11 @@ +package com.navercorp.pinpoint.profiler.context; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; + +public class DefaultAsyncContextTest extends AsyncContextTest { + @Override + AsyncContext newAsyncContext(boolean canSampled) { + AsyncTraceContext asyncTraceContext = newAsyncTraceContext(); + return new DefaultAsyncContext(asyncTraceContext, traceRoot, asyncId, 0, canSampled); + } +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContextTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContextTest.java new file mode 100644 index 000000000000..83bbdda74f08 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContextTest.java @@ -0,0 +1,96 @@ +package com.navercorp.pinpoint.profiler.context; + +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.exception.PinpointException; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.provider.BaseTraceFactoryProvider; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class DefaultAsyncTraceContextTest { + private static final Reference EMPTY = DefaultReference.emptyReference(); + + @Mock + private TraceRoot traceRoot; + @Mock + private LocalAsyncId localAsyncId; + + protected AsyncTraceContext newAsyncTraceContext() { + BaseTraceFactory baseTraceFactory = mock(DefaultBaseTraceFactory.class); + BaseTraceFactoryProvider baseTraceFactoryProvider = mock(BaseTraceFactoryProvider.class); + + when(baseTraceFactory.continueAsyncContextTraceObject(any(TraceRoot.class), any(LocalAsyncId.class), eq(true))) + .thenAnswer(new Answer() { + @Override + public Trace answer(InvocationOnMock invocationOnMock) { + Trace trace = mock(AsyncChildTrace.class); + when(trace.canSampled()).thenReturn(true); + return trace; + } + }); + when(baseTraceFactory.continueAsyncContextTraceObject(any(TraceRoot.class), any(LocalAsyncId.class), eq(false))) + .thenAnswer(new Answer() { + @Override + public Trace answer(InvocationOnMock invocationOnMock) { + return mock(DisableAsyncChildTrace.class); + } + }); + when(baseTraceFactoryProvider.get()).thenReturn(baseTraceFactory); + + return new DefaultAsyncTraceContext(baseTraceFactoryProvider, new ThreadLocalBinder()); + } + + @Test + public void testNewAsyncTraceObject() { + AsyncTraceContext asyncTraceContext = newAsyncTraceContext(); + + // new trace object + Trace newTraceEnabled = asyncTraceContext.newAsyncContextTraceObject(traceRoot, localAsyncId, true); + assertTrue(newTraceEnabled instanceof AsyncChildTrace); + assertNull(asyncTraceContext.currentRawTraceObject().get()); + + Trace newTraceDisabled = asyncTraceContext.newAsyncContextTraceObject(traceRoot, localAsyncId, false); + assertTrue(newTraceDisabled instanceof DisableAsyncChildTrace); + assertNull(asyncTraceContext.currentRawTraceObject().get()); + } + + @Test + public void testAsyncTraceContext() { + AsyncTraceContext asyncTraceContext = newAsyncTraceContext(); + + // sampling enabled + Reference continueTraceEnabled = asyncTraceContext.continueAsyncContextTraceObject(traceRoot, localAsyncId, true); + assertTrue(continueTraceEnabled.get() instanceof AsyncChildTrace); + assertEquals(continueTraceEnabled, asyncTraceContext.currentRawTraceObject()); + assertEquals(continueTraceEnabled, asyncTraceContext.currentTraceObject()); + + // remove trace object + asyncTraceContext.removeTraceObject(); + assertNull(asyncTraceContext.currentRawTraceObject().get()); + + // sampling disabled + Reference continueTraceDisabled = asyncTraceContext.continueAsyncContextTraceObject(traceRoot, localAsyncId, false); + assertTrue(continueTraceDisabled.get() instanceof DisableAsyncChildTrace); + assertEquals(continueTraceDisabled, asyncTraceContext.currentRawTraceObject()); + assertEquals(EMPTY, asyncTraceContext.currentTraceObject()); + } + + @Test(expected = PinpointException.class) + public void testOverrideTrace() { + AsyncTraceContext asyncTraceContext = newAsyncTraceContext(); + + asyncTraceContext.continueAsyncContextTraceObject(traceRoot, localAsyncId, true); + asyncTraceContext.continueAsyncContextTraceObject(traceRoot, localAsyncId, false); + } +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DisableTraceTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DisableTraceTest.java index 59f0497c2d97..37ff628f3e1a 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DisableTraceTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DisableTraceTest.java @@ -1,7 +1,10 @@ package com.navercorp.pinpoint.profiler.context; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; import com.navercorp.pinpoint.profiler.context.active.ActiveTraceHandle; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; import org.junit.Assert; import org.junit.Test; @@ -11,19 +14,62 @@ public class DisableTraceTest { @Test public void testGetScope() { Trace trace = newTrace(); + Trace childTrace = newChildTrace(); Assert.assertNull(trace.addScope("empty")); + Assert.assertNull(childTrace.addScope("empty")); } @Test public void testAddScope() { Trace trace = newTrace(); + Trace childTrace = newChildTrace(); trace.addScope("aaa"); + childTrace.addScope("bbb"); Assert.assertNotNull(trace.getScope("aaa")); + Assert.assertNotNull(childTrace.getScope("bbb")); + } + + @Test + public void testSampled() { + Trace trace = newTrace(); + Trace childTrace = newChildTrace(); + + Assert.assertFalse(trace.canSampled()); + Assert.assertFalse(childTrace.canSampled()); + } + + @Test + public void testSpanRecorder() { + Trace trace = newTrace(); + Trace childTrace = newChildTrace(); + SpanRecorder spanRecorder = trace.getSpanRecorder(); + SpanRecorder childSpanRecorder = childTrace.getSpanRecorder(); + + Assert.assertNull(spanRecorder); + Assert.assertNull(childSpanRecorder); + } + + @Test + public void testCurrentSpanEventRecorder() { + Trace trace = newTrace(); + Trace childTrace = newChildTrace(); + SpanEventRecorder spanEventRecorder = trace.currentSpanEventRecorder(); + SpanEventRecorder childSpanEventRecorder = childTrace.currentSpanEventRecorder(); + + Assert.assertNull(spanEventRecorder); + Assert.assertNull(childSpanEventRecorder); } private Trace newTrace() { ActiveTraceHandle activeTraceHandle = mock(ActiveTraceHandle.class); return new DisableTrace(1, 2, activeTraceHandle); } + + private Trace newChildTrace() { + TraceRoot traceRoot = mock(TraceRoot.class); + LocalAsyncId localAsyncId = mock(LocalAsyncId.class); + + return new DisableAsyncChildTrace(traceRoot, localAsyncId); + } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventFactoryTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventFactoryTest.java index d8f60a4c4c77..874f6f6a8fa6 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventFactoryTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventFactoryTest.java @@ -51,10 +51,10 @@ public void setSequence() { @Test public void dummy() { SpanEventFactory factory = new SpanEventFactory(); - final SpanEvent dummy = factory.dummyInstance(); - assertTrue(factory.isDummy(dummy)); + final SpanEvent dummy = factory.disableInstance(); + assertTrue(factory.isDisable(dummy)); final SpanEvent spanEvent = factory.newInstance(); - assertFalse(factory.isDummy(spanEvent)); + assertFalse(factory.isDisable(spanEvent)); } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/StatefulAsyncContextTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/StatefulAsyncContextTest.java new file mode 100644 index 000000000000..fc5a54282a5b --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/StatefulAsyncContextTest.java @@ -0,0 +1,27 @@ +package com.navercorp.pinpoint.profiler.context; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.AsyncState; +import org.junit.Test; +import org.mockito.Mock; + +import static org.junit.Assert.assertEquals; + + +public class StatefulAsyncContextTest extends AsyncContextTest { + @Mock + private AsyncState asyncState; + + @Override + AsyncContext newAsyncContext(boolean canSampled) { + AsyncTraceContext asyncTraceContext = newAsyncTraceContext(); + return new StatefulAsyncContext(asyncTraceContext, traceRoot, asyncId, 0, asyncState, canSampled); + } + + @Test + public void testGetAsyncState() { + StatefulAsyncContext asyncContext = (StatefulAsyncContext) newAsyncContext(true); + + assertEquals(asyncState, asyncContext.getAsyncState()); + } +}