make spring indy-ready (#14183)
Co-authored-by: Lauri Tulmin <tulmin@gmail.com>
This commit is contained in:
parent
f1fa49f31f
commit
57301cade1
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.SpringBatchInstrumentationConfig.shouldTraceItems;
|
||||||
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.getChunkContext;
|
||||||
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.itemInstrumenter;
|
||||||
|
|
||||||
|
import io.opentelemetry.context.Context;
|
||||||
|
import io.opentelemetry.context.Scope;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||||
|
|
||||||
|
public final class AdviceScope {
|
||||||
|
private final Context context;
|
||||||
|
private final String item;
|
||||||
|
private final Scope scope;
|
||||||
|
|
||||||
|
private AdviceScope(Context context, Scope scope, String item) {
|
||||||
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(String itemOperationName) {
|
||||||
|
Context parentContext = Context.current();
|
||||||
|
ChunkContext chunkContext = getChunkContext(parentContext);
|
||||||
|
if (chunkContext == null || !shouldTraceItems()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String item = ItemSingletons.itemName(chunkContext, itemOperationName);
|
||||||
|
if (!itemInstrumenter().shouldStart(parentContext, item)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Context context = itemInstrumenter().start(parentContext, item);
|
||||||
|
return new AdviceScope(context, context.makeCurrent(), item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exit(@Nullable Throwable thrown) {
|
||||||
|
scope.close();
|
||||||
|
itemInstrumenter().end(context, item, null, thrown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.chunk.StepBuilderInstrumentation;
|
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.chunk.StepBuilderInstrumentation;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ChunkOrientedTaskletInstrumentation;
|
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ChunkOrientedTaskletInstrumentation;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.JsrChunkProcessorInstrumentation;
|
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.JsrChunkProcessorInstrumentation;
|
||||||
|
|
@ -25,7 +26,8 @@ import java.util.List;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringBatchInstrumentationModule extends InstrumentationModule {
|
public class SpringBatchInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
public SpringBatchInstrumentationModule() {
|
public SpringBatchInstrumentationModule() {
|
||||||
super("spring-batch", "spring-batch-3.0");
|
super("spring-batch", "spring-batch-3.0");
|
||||||
}
|
}
|
||||||
|
|
@ -59,4 +61,9 @@ public class SpringBatchInstrumentationModule extends InstrumentationModule {
|
||||||
// TODO: replace this with an experimental flag
|
// TODO: replace this with an experimental flag
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,11 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
|
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.util.VirtualField;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.ContextAndScope;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
|
||||||
import org.springframework.batch.core.step.builder.AbstractTaskletStepBuilder;
|
import org.springframework.batch.core.step.builder.AbstractTaskletStepBuilder;
|
||||||
|
|
||||||
public class StepBuilderInstrumentation implements TypeInstrumentation {
|
public class StepBuilderInstrumentation implements TypeInstrumentation {
|
||||||
|
|
@ -43,10 +40,7 @@ public class StepBuilderInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(@Advice.This AbstractTaskletStepBuilder<?> stepBuilder) {
|
public static void onEnter(@Advice.This AbstractTaskletStepBuilder<?> stepBuilder) {
|
||||||
VirtualField<ChunkContext, ContextAndScope> chunkExecutionVirtualField =
|
stepBuilder.listener(new TracingChunkExecutionListener(stepBuilder.getClass()));
|
||||||
VirtualField.find(ChunkContext.class, ContextAndScope.class);
|
|
||||||
stepBuilder.listener(
|
|
||||||
new TracingChunkExecutionListener(chunkExecutionVirtualField, stepBuilder.getClass()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.chunk;
|
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.chunk;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.rootContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.SpringBatchInstrumentationConfig.shouldCreateRootSpanForChunk;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.SpringBatchInstrumentationConfig.shouldCreateRootSpanForChunk;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.chunk.ChunkSingletons.chunkInstrumenter;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.chunk.ChunkSingletons.chunkInstrumenter;
|
||||||
|
|
||||||
|
|
@ -20,19 +18,18 @@ import org.springframework.batch.core.scope.context.ChunkContext;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
public final class TracingChunkExecutionListener implements ChunkListener, Ordered {
|
public final class TracingChunkExecutionListener implements ChunkListener, Ordered {
|
||||||
private final VirtualField<ChunkContext, ContextAndScope> executionVirtualField;
|
private static final VirtualField<ChunkContext, ContextAndScope> CONTEXT_AND_SCOPE =
|
||||||
|
VirtualField.find(ChunkContext.class, ContextAndScope.class);
|
||||||
private final Class<?> builderClass;
|
private final Class<?> builderClass;
|
||||||
private ChunkContextAndBuilder chunkContextAndBuilder;
|
private ChunkContextAndBuilder chunkContextAndBuilder;
|
||||||
|
|
||||||
public TracingChunkExecutionListener(
|
public TracingChunkExecutionListener(Class<?> builderClass) {
|
||||||
VirtualField<ChunkContext, ContextAndScope> executionVirtualField, Class<?> builderClass) {
|
|
||||||
this.executionVirtualField = executionVirtualField;
|
|
||||||
this.builderClass = builderClass;
|
this.builderClass = builderClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeChunk(ChunkContext chunkContext) {
|
public void beforeChunk(ChunkContext chunkContext) {
|
||||||
Context parentContext = shouldCreateRootSpanForChunk() ? rootContext() : currentContext();
|
Context parentContext = shouldCreateRootSpanForChunk() ? Context.root() : Context.current();
|
||||||
chunkContextAndBuilder = new ChunkContextAndBuilder(chunkContext, builderClass);
|
chunkContextAndBuilder = new ChunkContextAndBuilder(chunkContext, builderClass);
|
||||||
if (!chunkInstrumenter().shouldStart(parentContext, chunkContextAndBuilder)) {
|
if (!chunkInstrumenter().shouldStart(parentContext, chunkContextAndBuilder)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -41,7 +38,7 @@ public final class TracingChunkExecutionListener implements ChunkListener, Order
|
||||||
Context context = chunkInstrumenter().start(parentContext, chunkContextAndBuilder);
|
Context context = chunkInstrumenter().start(parentContext, chunkContextAndBuilder);
|
||||||
// beforeJob & afterJob always execute on the same thread
|
// beforeJob & afterJob always execute on the same thread
|
||||||
Scope scope = context.makeCurrent();
|
Scope scope = context.makeCurrent();
|
||||||
executionVirtualField.set(chunkContext, new ContextAndScope(context, scope));
|
CONTEXT_AND_SCOPE.set(chunkContext, new ContextAndScope(context, scope));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -57,12 +54,12 @@ public final class TracingChunkExecutionListener implements ChunkListener, Order
|
||||||
}
|
}
|
||||||
|
|
||||||
private void end(ChunkContext chunkContext, @Nullable Throwable throwable) {
|
private void end(ChunkContext chunkContext, @Nullable Throwable throwable) {
|
||||||
ContextAndScope contextAndScope = executionVirtualField.get(chunkContext);
|
ContextAndScope contextAndScope = CONTEXT_AND_SCOPE.get(chunkContext);
|
||||||
if (contextAndScope == null) {
|
if (contextAndScope == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
executionVirtualField.set(chunkContext, null);
|
CONTEXT_AND_SCOPE.set(chunkContext, null);
|
||||||
contextAndScope.closeScope();
|
contextAndScope.closeScope();
|
||||||
chunkInstrumenter().end(contextAndScope.getContext(), chunkContextAndBuilder, null, throwable);
|
chunkInstrumenter().end(contextAndScope.getContext(), chunkContextAndBuilder, null, throwable);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -44,17 +45,18 @@ public class ChunkOrientedTaskletInstrumentation implements TypeInstrumentation
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class ExecuteAdvice {
|
public static class ExecuteAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static Scope onEnter(@Advice.Argument(1) ChunkContext chunkContext) {
|
||||||
@Advice.Argument(1) ChunkContext chunkContext, @Advice.Local("otelScope") Scope scope) {
|
if (!shouldTraceItems()) {
|
||||||
if (shouldTraceItems()) {
|
return null;
|
||||||
Context context = startChunk(currentContext(), chunkContext);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
Context context = startChunk(currentContext(), chunkContext);
|
||||||
|
return context.makeCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onExit(@Advice.Local("otelScope") Scope scope) {
|
public static void onExit(@Advice.Enter @Nullable Scope scope) {
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
scope.close();
|
scope.close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,20 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item;
|
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.SpringBatchInstrumentationConfig.shouldTraceItems;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_PROCESS;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_PROCESS;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_READ;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_READ;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_WRITE;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_WRITE;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.getChunkContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.itemInstrumenter;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
|
||||||
import io.opentelemetry.context.Scope;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.AdviceScope;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
|
||||||
|
|
||||||
public class JsrChunkProcessorInstrumentation implements TypeInstrumentation {
|
public class JsrChunkProcessorInstrumentation implements TypeInstrumentation {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -47,114 +42,57 @@ public class JsrChunkProcessorInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class ProvideAdvice {
|
public static class ProvideAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static AdviceScope onEnter() {
|
||||||
@Advice.Local("otelContext") Context context,
|
return AdviceScope.enter(ITEM_OPERATION_READ);
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Local("otelItem") String item) {
|
|
||||||
Context parentContext = currentContext();
|
|
||||||
ChunkContext chunkContext = getChunkContext(parentContext);
|
|
||||||
if (chunkContext == null || !shouldTraceItems()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = ItemSingletons.itemName(chunkContext, ITEM_OPERATION_READ);
|
|
||||||
if (!itemInstrumenter().shouldStart(parentContext, item)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context = itemInstrumenter().start(parentContext, item);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onExit(
|
public static void onExit(
|
||||||
@Advice.Thrown Throwable thrown,
|
@Advice.Thrown @Nullable Throwable thrown,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope,
|
if (adviceScope != null) {
|
||||||
@Advice.Local("otelItem") String item) {
|
adviceScope.exit(thrown);
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.close();
|
|
||||||
itemInstrumenter().end(context, item, null, thrown);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class TransformAdvice {
|
public static class TransformAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static AdviceScope onEnter() {
|
||||||
@Advice.Local("otelContext") Context context,
|
return AdviceScope.enter(ITEM_OPERATION_PROCESS);
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Local("otelItem") String item) {
|
|
||||||
Context parentContext = currentContext();
|
|
||||||
ChunkContext chunkContext = getChunkContext(parentContext);
|
|
||||||
if (chunkContext == null || !shouldTraceItems()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = ItemSingletons.itemName(chunkContext, ITEM_OPERATION_PROCESS);
|
|
||||||
if (!itemInstrumenter().shouldStart(parentContext, item)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context = itemInstrumenter().start(parentContext, item);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onExit(
|
public static void onExit(
|
||||||
@Advice.Thrown Throwable thrown,
|
@Advice.Thrown @Nullable Throwable thrown,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope,
|
if (adviceScope != null) {
|
||||||
@Advice.Local("otelItem") String item) {
|
adviceScope.exit(thrown);
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.close();
|
|
||||||
itemInstrumenter().end(context, item, null, thrown);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class PersistAdvice {
|
public static class PersistAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static AdviceScope onEnter() {
|
||||||
@Advice.Local("otelContext") Context context,
|
return AdviceScope.enter(ITEM_OPERATION_WRITE);
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Local("otelItem") String item) {
|
|
||||||
Context parentContext = currentContext();
|
|
||||||
ChunkContext chunkContext = getChunkContext(parentContext);
|
|
||||||
if (chunkContext == null || !shouldTraceItems()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = ItemSingletons.itemName(chunkContext, ITEM_OPERATION_WRITE);
|
|
||||||
if (!itemInstrumenter().shouldStart(parentContext, item)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context = itemInstrumenter().start(parentContext, item);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onExit(
|
public static void onExit(
|
||||||
@Advice.Thrown Throwable thrown,
|
@Advice.Thrown @Nullable Throwable thrown,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope,
|
if (adviceScope != null) {
|
||||||
@Advice.Local("otelItem") String item) {
|
adviceScope.exit(thrown);
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.close();
|
|
||||||
itemInstrumenter().end(context, item, null, thrown);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,19 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item;
|
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.SpringBatchInstrumentationConfig.shouldTraceItems;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_PROCESS;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_PROCESS;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_WRITE;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_WRITE;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.getChunkContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.itemInstrumenter;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
|
||||||
import io.opentelemetry.context.Scope;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.AdviceScope;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
|
||||||
import org.springframework.batch.item.ItemProcessor;
|
import org.springframework.batch.item.ItemProcessor;
|
||||||
import org.springframework.batch.item.ItemWriter;
|
import org.springframework.batch.item.ItemWriter;
|
||||||
|
|
||||||
|
|
@ -45,78 +40,40 @@ public class SimpleChunkProcessorInstrumentation implements TypeInstrumentation
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class ProcessAdvice {
|
public static class ProcessAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static AdviceScope onEnter(
|
||||||
@Advice.FieldValue("itemProcessor") ItemProcessor<?, ?> itemProcessor,
|
@Advice.FieldValue("itemProcessor") ItemProcessor<?, ?> itemProcessor) {
|
||||||
@Advice.Local("otelContext") Context context,
|
return AdviceScope.enter(ITEM_OPERATION_PROCESS);
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Local("otelItem") String item) {
|
|
||||||
Context parentContext = currentContext();
|
|
||||||
ChunkContext chunkContext = getChunkContext(parentContext);
|
|
||||||
if (chunkContext == null || !shouldTraceItems()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = ItemSingletons.itemName(chunkContext, ITEM_OPERATION_PROCESS);
|
|
||||||
if (!itemInstrumenter().shouldStart(parentContext, item)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context = itemInstrumenter().start(parentContext, item);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onExit(
|
public static void onExit(
|
||||||
@Advice.Thrown Throwable thrown,
|
@Advice.Thrown @Nullable Throwable thrown,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope,
|
if (adviceScope != null) {
|
||||||
@Advice.Local("otelItem") String item) {
|
adviceScope.exit(thrown);
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.close();
|
|
||||||
itemInstrumenter().end(context, item, null, thrown);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class WriteAdvice {
|
public static class WriteAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static AdviceScope onEnter(@Advice.FieldValue("itemWriter") ItemWriter<?> itemWriter) {
|
||||||
@Advice.FieldValue("itemWriter") ItemWriter<?> itemWriter,
|
return AdviceScope.enter(ITEM_OPERATION_WRITE);
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Local("otelItem") String item) {
|
|
||||||
Context parentContext = currentContext();
|
|
||||||
ChunkContext chunkContext = getChunkContext(parentContext);
|
|
||||||
if (chunkContext == null || itemWriter == null || !shouldTraceItems()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = ItemSingletons.itemName(chunkContext, ITEM_OPERATION_WRITE);
|
|
||||||
if (!itemInstrumenter().shouldStart(parentContext, item)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context = itemInstrumenter().start(parentContext, item);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onExit(
|
public static void onExit(
|
||||||
@Advice.Thrown Throwable thrown,
|
@Advice.Thrown @Nullable Throwable thrown,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Local("otelItem") String item) {
|
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.close();
|
if (adviceScope != null) {
|
||||||
itemInstrumenter().end(context, item, null, thrown);
|
adviceScope.exit(thrown);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,18 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item;
|
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.SpringBatchInstrumentationConfig.shouldTraceItems;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_READ;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.ITEM_OPERATION_READ;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.getChunkContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.item.ItemSingletons.itemInstrumenter;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
|
||||||
import io.opentelemetry.context.Scope;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.AdviceScope;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
|
||||||
|
|
||||||
// item read instrumentation *cannot* use ItemReadListener: sometimes afterRead() is not called
|
// item read instrumentation *cannot* use ItemReadListener: sometimes afterRead() is not called
|
||||||
// after beforeRead(), using listener here would cause unfinished spans/scopes
|
// after beforeRead(), using listener here would cause unfinished spans/scopes
|
||||||
|
|
@ -41,38 +36,19 @@ public class SimpleChunkProviderInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class ReadAdvice {
|
public static class ReadAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static AdviceScope onEnter() {
|
||||||
@Advice.Local("otelContext") Context context,
|
return AdviceScope.enter(ITEM_OPERATION_READ);
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Local("otelItem") String item) {
|
|
||||||
Context parentContext = currentContext();
|
|
||||||
ChunkContext chunkContext = getChunkContext(parentContext);
|
|
||||||
if (chunkContext == null || !shouldTraceItems()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = ItemSingletons.itemName(chunkContext, ITEM_OPERATION_READ);
|
|
||||||
if (!itemInstrumenter().shouldStart(parentContext, item)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context = itemInstrumenter().start(parentContext, item);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onExit(
|
public static void onExit(
|
||||||
@Advice.Thrown Throwable thrown,
|
@Advice.Thrown @Nullable Throwable thrown,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope,
|
if (adviceScope != null) {
|
||||||
@Advice.Local("otelItem") String item) {
|
adviceScope.exit(thrown);
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.close();
|
|
||||||
itemInstrumenter().end(context, item, null, thrown);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,11 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.util.VirtualField;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.ContextAndScope;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.batch.core.JobExecution;
|
|
||||||
import org.springframework.batch.core.job.builder.JobBuilderHelper;
|
import org.springframework.batch.core.job.builder.JobBuilderHelper;
|
||||||
|
|
||||||
public class JobBuilderHelperInstrumentation implements TypeInstrumentation {
|
public class JobBuilderHelperInstrumentation implements TypeInstrumentation {
|
||||||
|
|
@ -42,9 +39,7 @@ public class JobBuilderHelperInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(@Advice.This JobBuilderHelper<?> jobBuilder) {
|
public static void onEnter(@Advice.This JobBuilderHelper<?> jobBuilder) {
|
||||||
VirtualField<JobExecution, ContextAndScope> executionVirtualField =
|
jobBuilder.listener(new TracingJobExecutionListener());
|
||||||
VirtualField.find(JobExecution.class, ContextAndScope.class);
|
|
||||||
jobBuilder.listener(new TracingJobExecutionListener(executionVirtualField));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,14 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.util.VirtualField;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.ContextAndScope;
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.batch.core.JobExecution;
|
|
||||||
import org.springframework.batch.core.JobExecutionListener;
|
|
||||||
import org.springframework.batch.core.jsr.configuration.xml.JobFactoryBean;
|
import org.springframework.batch.core.jsr.configuration.xml.JobFactoryBean;
|
||||||
|
|
||||||
public class JobFactoryBeanInstrumentation implements TypeInstrumentation {
|
public class JobFactoryBeanInstrumentation implements TypeInstrumentation {
|
||||||
|
|
@ -55,20 +54,17 @@ public class JobFactoryBeanInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class SetListenersAdvice {
|
public static class SetListenersAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToArguments(@ToArgument(0))
|
||||||
|
@Advice.AssignReturned.AsScalar
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(@Advice.Argument(value = 0, readOnly = false) Object[] listeners) {
|
public static Object[] onEnter(@Advice.Argument(0) @Nullable Object[] listeners) {
|
||||||
VirtualField<JobExecution, ContextAndScope> executionVirtualField =
|
|
||||||
VirtualField.find(JobExecution.class, ContextAndScope.class);
|
|
||||||
JobExecutionListener tracingListener = new TracingJobExecutionListener(executionVirtualField);
|
|
||||||
|
|
||||||
if (listeners == null) {
|
if (listeners == null) {
|
||||||
listeners = new Object[] {tracingListener};
|
return new Object[] {new TracingJobExecutionListener()};
|
||||||
} else {
|
|
||||||
Object[] newListeners = new Object[listeners.length + 1];
|
|
||||||
newListeners[0] = tracingListener;
|
|
||||||
System.arraycopy(listeners, 0, newListeners, 1, listeners.length);
|
|
||||||
listeners = newListeners;
|
|
||||||
}
|
}
|
||||||
|
Object[] newListeners = new Object[listeners.length + 1];
|
||||||
|
newListeners[0] = new TracingJobExecutionListener();
|
||||||
|
System.arraycopy(listeners, 0, newListeners, 1, listeners.length);
|
||||||
|
return newListeners;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,14 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.util.VirtualField;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.ContextAndScope;
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.batch.core.JobExecution;
|
|
||||||
import org.springframework.batch.core.JobExecutionListener;
|
import org.springframework.batch.core.JobExecutionListener;
|
||||||
import org.springframework.batch.core.configuration.xml.JobParserJobFactoryBean;
|
import org.springframework.batch.core.configuration.xml.JobParserJobFactoryBean;
|
||||||
|
|
||||||
|
|
@ -55,21 +55,18 @@ public class JobParserJobFactoryBeanInstrumentation implements TypeInstrumentati
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class SetListenersAdvice {
|
public static class SetListenersAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToArguments(@ToArgument(0))
|
||||||
|
@Advice.AssignReturned.AsScalar
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static JobExecutionListener[] onEnter(
|
||||||
@Advice.Argument(value = 0, readOnly = false) JobExecutionListener[] listeners) {
|
@Advice.Argument(0) @Nullable JobExecutionListener[] listeners) {
|
||||||
VirtualField<JobExecution, ContextAndScope> executionVirtualField =
|
|
||||||
VirtualField.find(JobExecution.class, ContextAndScope.class);
|
|
||||||
JobExecutionListener tracingListener = new TracingJobExecutionListener(executionVirtualField);
|
|
||||||
|
|
||||||
if (listeners == null) {
|
if (listeners == null) {
|
||||||
listeners = new JobExecutionListener[] {tracingListener};
|
return new JobExecutionListener[] {new TracingJobExecutionListener()};
|
||||||
} else {
|
|
||||||
JobExecutionListener[] newListeners = new JobExecutionListener[listeners.length + 1];
|
|
||||||
newListeners[0] = tracingListener;
|
|
||||||
System.arraycopy(listeners, 0, newListeners, 1, listeners.length);
|
|
||||||
listeners = newListeners;
|
|
||||||
}
|
}
|
||||||
|
JobExecutionListener[] newListeners = new JobExecutionListener[listeners.length + 1];
|
||||||
|
newListeners[0] = new TracingJobExecutionListener();
|
||||||
|
System.arraycopy(listeners, 0, newListeners, 1, listeners.length);
|
||||||
|
return newListeners;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.job;
|
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.job;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.job.JobSingletons.jobInstrumenter;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.job.JobSingletons.jobInstrumenter;
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
|
|
@ -18,16 +17,14 @@ import org.springframework.batch.core.JobExecutionListener;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
public final class TracingJobExecutionListener implements JobExecutionListener, Ordered {
|
public final class TracingJobExecutionListener implements JobExecutionListener, Ordered {
|
||||||
private final VirtualField<JobExecution, ContextAndScope> executionVirtualField;
|
private static final VirtualField<JobExecution, ContextAndScope> CONTEXT_AND_SCOPE =
|
||||||
|
VirtualField.find(JobExecution.class, ContextAndScope.class);
|
||||||
|
|
||||||
public TracingJobExecutionListener(
|
public TracingJobExecutionListener() {}
|
||||||
VirtualField<JobExecution, ContextAndScope> executionVirtualField) {
|
|
||||||
this.executionVirtualField = executionVirtualField;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeJob(JobExecution jobExecution) {
|
public void beforeJob(JobExecution jobExecution) {
|
||||||
Context parentContext = currentContext();
|
Context parentContext = Context.current();
|
||||||
if (!jobInstrumenter().shouldStart(parentContext, jobExecution)) {
|
if (!jobInstrumenter().shouldStart(parentContext, jobExecution)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -35,16 +32,16 @@ public final class TracingJobExecutionListener implements JobExecutionListener,
|
||||||
Context context = jobInstrumenter().start(parentContext, jobExecution);
|
Context context = jobInstrumenter().start(parentContext, jobExecution);
|
||||||
// beforeJob & afterJob always execute on the same thread
|
// beforeJob & afterJob always execute on the same thread
|
||||||
Scope scope = context.makeCurrent();
|
Scope scope = context.makeCurrent();
|
||||||
executionVirtualField.set(jobExecution, new ContextAndScope(context, scope));
|
CONTEXT_AND_SCOPE.set(jobExecution, new ContextAndScope(context, scope));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterJob(JobExecution jobExecution) {
|
public void afterJob(JobExecution jobExecution) {
|
||||||
ContextAndScope contextAndScope = executionVirtualField.get(jobExecution);
|
ContextAndScope contextAndScope = CONTEXT_AND_SCOPE.get(jobExecution);
|
||||||
if (contextAndScope == null) {
|
if (contextAndScope == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
executionVirtualField.set(jobExecution, null);
|
CONTEXT_AND_SCOPE.set(jobExecution, null);
|
||||||
contextAndScope.closeScope();
|
contextAndScope.closeScope();
|
||||||
jobInstrumenter().end(contextAndScope.getContext(), jobExecution, null, null);
|
jobInstrumenter().end(contextAndScope.getContext(), jobExecution, null, null);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,11 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.util.VirtualField;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.ContextAndScope;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.batch.core.StepExecution;
|
|
||||||
import org.springframework.batch.core.step.builder.StepBuilderHelper;
|
import org.springframework.batch.core.step.builder.StepBuilderHelper;
|
||||||
|
|
||||||
public class StepBuilderHelperInstrumentation implements TypeInstrumentation {
|
public class StepBuilderHelperInstrumentation implements TypeInstrumentation {
|
||||||
|
|
@ -41,9 +38,7 @@ public class StepBuilderHelperInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(@Advice.This StepBuilderHelper<?> stepBuilder) {
|
public static void onEnter(@Advice.This StepBuilderHelper<?> stepBuilder) {
|
||||||
VirtualField<StepExecution, ContextAndScope> executionVirtualField =
|
stepBuilder.listener(new TracingStepExecutionListener());
|
||||||
VirtualField.find(StepExecution.class, ContextAndScope.class);
|
|
||||||
stepBuilder.listener(new TracingStepExecutionListener(executionVirtualField));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.step;
|
package io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.step;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.step.StepSingletons.stepInstrumenter;
|
import static io.opentelemetry.javaagent.instrumentation.spring.batch.v3_0.step.StepSingletons.stepInstrumenter;
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
|
|
@ -19,16 +18,14 @@ import org.springframework.batch.core.StepExecutionListener;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
public final class TracingStepExecutionListener implements StepExecutionListener, Ordered {
|
public final class TracingStepExecutionListener implements StepExecutionListener, Ordered {
|
||||||
private final VirtualField<StepExecution, ContextAndScope> executionVirtualField;
|
private static final VirtualField<StepExecution, ContextAndScope> CONTEXT_AND_SCOPE =
|
||||||
|
VirtualField.find(StepExecution.class, ContextAndScope.class);
|
||||||
|
|
||||||
public TracingStepExecutionListener(
|
public TracingStepExecutionListener() {}
|
||||||
VirtualField<StepExecution, ContextAndScope> executionVirtualField) {
|
|
||||||
this.executionVirtualField = executionVirtualField;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeStep(StepExecution stepExecution) {
|
public void beforeStep(StepExecution stepExecution) {
|
||||||
Context parentContext = currentContext();
|
Context parentContext = Context.current();
|
||||||
if (!stepInstrumenter().shouldStart(parentContext, stepExecution)) {
|
if (!stepInstrumenter().shouldStart(parentContext, stepExecution)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -36,17 +33,17 @@ public final class TracingStepExecutionListener implements StepExecutionListener
|
||||||
Context context = stepInstrumenter().start(parentContext, stepExecution);
|
Context context = stepInstrumenter().start(parentContext, stepExecution);
|
||||||
// beforeStep & afterStep always execute on the same thread
|
// beforeStep & afterStep always execute on the same thread
|
||||||
Scope scope = context.makeCurrent();
|
Scope scope = context.makeCurrent();
|
||||||
executionVirtualField.set(stepExecution, new ContextAndScope(context, scope));
|
CONTEXT_AND_SCOPE.set(stepExecution, new ContextAndScope(context, scope));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||||
ContextAndScope contextAndScope = executionVirtualField.get(stepExecution);
|
ContextAndScope contextAndScope = CONTEXT_AND_SCOPE.get(stepExecution);
|
||||||
if (contextAndScope == null) {
|
if (contextAndScope == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
executionVirtualField.set(stepExecution, null);
|
CONTEXT_AND_SCOPE.set(stepExecution, null);
|
||||||
contextAndScope.closeScope();
|
contextAndScope.closeScope();
|
||||||
stepInstrumenter().end(contextAndScope.getContext(), stepExecution, null, null);
|
stepInstrumenter().end(contextAndScope.getContext(), stepExecution, null, null);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
|
|
@ -33,8 +34,10 @@ public class AutoConfigurationImportSelectorInstrumentation implements TypeInstr
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class GetCandidateConfigurationsAdvice {
|
public static class GetCandidateConfigurationsAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToReturned
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||||
public static void onExit(@Advice.Return(readOnly = false) List<String> configurations) {
|
public static List<String> onExit(@Advice.Return List<String> originalConfigurations) {
|
||||||
|
List<String> configurations = originalConfigurations;
|
||||||
if (configurations.contains(
|
if (configurations.contains(
|
||||||
"org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration")) {
|
"org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration")) {
|
||||||
List<String> configs = new ArrayList<>(configurations.size() + 1);
|
List<String> configs = new ArrayList<>(configurations.size() + 1);
|
||||||
|
|
@ -44,6 +47,7 @@ public class AutoConfigurationImportSelectorInstrumentation implements TypeInstr
|
||||||
configs.add(OpenTelemetryMeterRegistryAutoConfiguration.class.getName());
|
configs.add(OpenTelemetryMeterRegistryAutoConfiguration.class.getName());
|
||||||
configurations = configs;
|
configurations = configs;
|
||||||
}
|
}
|
||||||
|
return configurations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,4 +69,9 @@ public class SpringBootActuatorInstrumentationModule extends InstrumentationModu
|
||||||
// produces a lot of metrics that are already captured - e.g. JVM memory usage
|
// produces a lot of metrics that are already captured - e.g. JVM memory usage
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,9 @@ public class SpringAwsSqsInstrumentationModule extends InstrumentationModule
|
||||||
new AcknowledgementExecutionContextInstrumentation(),
|
new AcknowledgementExecutionContextInstrumentation(),
|
||||||
new MessageHeaderUtilsInstrumentation());
|
new MessageHeaderUtilsInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
|
|
@ -32,9 +33,10 @@ public class SqsTemplateInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class GetQueueAttributesAdvice {
|
public static class GetQueueAttributesAdvice {
|
||||||
|
@AssignReturned.ToReturned
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||||
public static void methodExit(@Advice.Return(readOnly = false) CompletableFuture<?> result) {
|
public static CompletableFuture<?> methodExit(@Advice.Return CompletableFuture<?> result) {
|
||||||
result = CompletableFutureWrapper.wrap(result, Java8BytecodeBridge.currentContext());
|
return CompletableFutureWrapper.wrap(result, Java8BytecodeBridge.currentContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,14 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringJmsInstrumentationModule extends InstrumentationModule {
|
public class SpringJmsInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
|
|
||||||
public SpringJmsInstrumentationModule() {
|
public SpringJmsInstrumentationModule() {
|
||||||
super("spring-jms", "spring-jms-2.0");
|
super("spring-jms", "spring-jms-2.0");
|
||||||
|
|
@ -34,4 +36,9 @@ public class SpringJmsInstrumentationModule extends InstrumentationModule {
|
||||||
new JmsDestinationAccessorInstrumentation(),
|
new JmsDestinationAccessorInstrumentation(),
|
||||||
new AbstractPollingMessageListenerContainerInstrumentation());
|
new AbstractPollingMessageListenerContainerInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,12 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
|
||||||
import io.opentelemetry.javaagent.bootstrap.jms.JmsReceiveContextHolder;
|
import io.opentelemetry.javaagent.bootstrap.jms.JmsReceiveContextHolder;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.jms.MessageWithDestination;
|
import io.opentelemetry.javaagent.instrumentation.jms.MessageWithDestination;
|
||||||
import io.opentelemetry.javaagent.instrumentation.jms.v1_1.JavaxMessageAdapter;
|
import io.opentelemetry.javaagent.instrumentation.jms.v1_1.JavaxMessageAdapter;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.jms.Message;
|
import javax.jms.Message;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
|
@ -52,39 +52,53 @@ public class SpringJmsMessageListenerInstrumentation implements TypeInstrumentat
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class MessageListenerAdvice {
|
public static class MessageListenerAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void onEnter(
|
private final MessageWithDestination request;
|
||||||
@Advice.Argument(0) Message message,
|
private final Context context;
|
||||||
@Advice.Local("otelRequest") MessageWithDestination request,
|
private final Scope scope;
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
|
|
||||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
private AdviceScope(MessageWithDestination request, Context context, Scope scope) {
|
||||||
|
this.request = request;
|
||||||
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(Message message) {
|
||||||
|
Context parentContext = Context.current();
|
||||||
Context receiveContext = JmsReceiveContextHolder.getReceiveContext(parentContext);
|
Context receiveContext = JmsReceiveContextHolder.getReceiveContext(parentContext);
|
||||||
if (receiveContext != null) {
|
if (receiveContext != null) {
|
||||||
parentContext = receiveContext;
|
parentContext = receiveContext;
|
||||||
}
|
}
|
||||||
request = MessageWithDestination.create(JavaxMessageAdapter.create(message), null);
|
|
||||||
|
MessageWithDestination request =
|
||||||
|
MessageWithDestination.create(JavaxMessageAdapter.create(message), null);
|
||||||
|
|
||||||
if (!listenerInstrumenter().shouldStart(parentContext, request)) {
|
if (!listenerInstrumenter().shouldStart(parentContext, request)) {
|
||||||
return;
|
return null;
|
||||||
|
}
|
||||||
|
Context context = listenerInstrumenter().start(parentContext, request);
|
||||||
|
return new AdviceScope(request, context, context.makeCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
context = listenerInstrumenter().start(parentContext, request);
|
public void exit(Throwable throwable) {
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
|
||||||
public static void stopSpan(
|
|
||||||
@Advice.Local("otelRequest") MessageWithDestination request,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Thrown Throwable throwable) {
|
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scope.close();
|
scope.close();
|
||||||
listenerInstrumenter().end(context, request, null, throwable);
|
listenerInstrumenter().end(context, request, null, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(@Advice.Argument(0) Message message) {
|
||||||
|
return AdviceScope.enter(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
|
public static void stopSpan(
|
||||||
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
|
if (adviceScope != null) {
|
||||||
|
adviceScope.exit(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,13 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringJmsInstrumentationModule extends InstrumentationModule {
|
public class SpringJmsInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
|
|
||||||
public SpringJmsInstrumentationModule() {
|
public SpringJmsInstrumentationModule() {
|
||||||
super("spring-jms", "spring-jms-6.0");
|
super("spring-jms", "spring-jms-6.0");
|
||||||
|
|
@ -35,4 +37,9 @@ public class SpringJmsInstrumentationModule extends InstrumentationModule {
|
||||||
new JmsDestinationAccessorInstrumentation(),
|
new JmsDestinationAccessorInstrumentation(),
|
||||||
new AbstractPollingMessageListenerContainerInstrumentation());
|
new AbstractPollingMessageListenerContainerInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,13 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
|
||||||
import io.opentelemetry.javaagent.bootstrap.jms.JmsReceiveContextHolder;
|
import io.opentelemetry.javaagent.bootstrap.jms.JmsReceiveContextHolder;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.jms.MessageWithDestination;
|
import io.opentelemetry.javaagent.instrumentation.jms.MessageWithDestination;
|
||||||
import io.opentelemetry.javaagent.instrumentation.jms.v3_0.JakartaMessageAdapter;
|
import io.opentelemetry.javaagent.instrumentation.jms.v3_0.JakartaMessageAdapter;
|
||||||
import jakarta.jms.Message;
|
import jakarta.jms.Message;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -52,39 +52,54 @@ public class SpringJmsMessageListenerInstrumentation implements TypeInstrumentat
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class MessageListenerAdvice {
|
public static class MessageListenerAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void onEnter(
|
private final MessageWithDestination request;
|
||||||
@Advice.Argument(0) Message message,
|
private final Context context;
|
||||||
@Advice.Local("otelRequest") MessageWithDestination request,
|
private final Scope scope;
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
|
|
||||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
private AdviceScope(MessageWithDestination request, Context context, Scope scope) {
|
||||||
|
this.request = request;
|
||||||
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(Message message) {
|
||||||
|
Context parentContext = Context.current();
|
||||||
Context receiveContext = JmsReceiveContextHolder.getReceiveContext(parentContext);
|
Context receiveContext = JmsReceiveContextHolder.getReceiveContext(parentContext);
|
||||||
if (receiveContext != null) {
|
if (receiveContext != null) {
|
||||||
parentContext = receiveContext;
|
parentContext = receiveContext;
|
||||||
}
|
}
|
||||||
request = MessageWithDestination.create(JakartaMessageAdapter.create(message), null);
|
MessageWithDestination request =
|
||||||
|
MessageWithDestination.create(JakartaMessageAdapter.create(message), null);
|
||||||
|
|
||||||
if (!listenerInstrumenter().shouldStart(parentContext, request)) {
|
if (!listenerInstrumenter().shouldStart(parentContext, request)) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = listenerInstrumenter().start(parentContext, request);
|
Context context = listenerInstrumenter().start(parentContext, request);
|
||||||
scope = context.makeCurrent();
|
return new AdviceScope(request, context, context.makeCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
public void exit(Throwable throwable) {
|
||||||
public static void stopSpan(
|
|
||||||
@Advice.Local("otelRequest") MessageWithDestination request,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope,
|
|
||||||
@Advice.Thrown Throwable throwable) {
|
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scope.close();
|
scope.close();
|
||||||
listenerInstrumenter().end(context, request, null, throwable);
|
listenerInstrumenter().end(context, request, null, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(@Advice.Argument(0) Message message) {
|
||||||
|
return AdviceScope.enter(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
|
public static void stopSpan(
|
||||||
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
|
if (adviceScope != null) {
|
||||||
|
adviceScope.exit(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.kafka.listener.RecordInterceptor;
|
import org.springframework.kafka.listener.RecordInterceptor;
|
||||||
|
|
@ -43,9 +44,11 @@ public class AbstractMessageListenerContainerInstrumentation implements TypeInst
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class GetRecordInterceptorAdvice {
|
public static class GetRecordInterceptorAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToReturned
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||||
public static <K, V> void onExit(
|
public static <K, V> RecordInterceptor<K, V> onExit(
|
||||||
@Advice.Return(readOnly = false) RecordInterceptor<K, V> interceptor) {
|
@Advice.Return RecordInterceptor<K, V> originalInterceptor) {
|
||||||
|
RecordInterceptor<K, V> interceptor = originalInterceptor;
|
||||||
|
|
||||||
if (interceptor == null
|
if (interceptor == null
|
||||||
|| !interceptor
|
|| !interceptor
|
||||||
|
|
@ -55,6 +58,7 @@ public class AbstractMessageListenerContainerInstrumentation implements TypeInst
|
||||||
"io.opentelemetry.instrumentation.spring.kafka.v2_7.InstrumentedRecordInterceptor")) {
|
"io.opentelemetry.instrumentation.spring.kafka.v2_7.InstrumentedRecordInterceptor")) {
|
||||||
interceptor = telemetry().createRecordInterceptor(interceptor);
|
interceptor = telemetry().createRecordInterceptor(interceptor);
|
||||||
}
|
}
|
||||||
|
return interceptor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import io.opentelemetry.javaagent.bootstrap.kafka.KafkaClientsConsumerProcessTra
|
||||||
import io.opentelemetry.javaagent.bootstrap.spring.SpringSchedulingTaskTracing;
|
import io.opentelemetry.javaagent.bootstrap.spring.SpringSchedulingTaskTracing;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -77,37 +78,53 @@ public class ListenerConsumerInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class InvokeBatchAdvice {
|
public static class InvokeBatchAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void onEnter(
|
private final KafkaReceiveRequest request;
|
||||||
@Advice.Argument(0) ConsumerRecords<?, ?> records,
|
private final Context context;
|
||||||
@Advice.FieldValue("consumer") Consumer<?, ?> consumer,
|
private final Scope scope;
|
||||||
@Advice.Local("otelRequest") KafkaReceiveRequest request,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
private AdviceScope(KafkaReceiveRequest request, Context context, Scope scope) {
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
this.request = request;
|
||||||
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(ConsumerRecords<?, ?> records, Consumer<?, ?> consumer) {
|
||||||
KafkaConsumerContext consumerContext = KafkaConsumerContextUtil.get(records);
|
KafkaConsumerContext consumerContext = KafkaConsumerContextUtil.get(records);
|
||||||
Context receiveContext = consumerContext.getContext();
|
Context receiveContext = consumerContext.getContext();
|
||||||
|
|
||||||
// use the receive CONSUMER span as parent if it's available
|
// use the receive CONSUMER span as parent if it's available
|
||||||
Context parentContext = receiveContext != null ? receiveContext : Context.current();
|
Context parentContext = receiveContext != null ? receiveContext : Context.current();
|
||||||
|
KafkaReceiveRequest request = KafkaReceiveRequest.create(records, consumer);
|
||||||
|
|
||||||
request = KafkaReceiveRequest.create(records, consumer);
|
if (!batchProcessInstrumenter().shouldStart(parentContext, request)) {
|
||||||
if (batchProcessInstrumenter().shouldStart(parentContext, request)) {
|
return null;
|
||||||
context = batchProcessInstrumenter().start(parentContext, request);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
Context context = batchProcessInstrumenter().start(parentContext, request);
|
||||||
|
return new AdviceScope(request, context, context.makeCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
public void exit(@Nullable Throwable throwable) {
|
||||||
public static void onExit(
|
|
||||||
@Advice.Thrown Throwable throwable,
|
|
||||||
@Advice.Local("otelRequest") KafkaReceiveRequest request,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scope.close();
|
scope.close();
|
||||||
batchProcessInstrumenter().end(context, request, null, throwable);
|
batchProcessInstrumenter().end(context, request, null, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(
|
||||||
|
@Advice.Argument(0) ConsumerRecords<?, ?> records,
|
||||||
|
@Advice.FieldValue("consumer") Consumer<?, ?> consumer) {
|
||||||
|
return AdviceScope.enter(records, consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
|
public static void onExit(
|
||||||
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
|
if (adviceScope != null) {
|
||||||
|
adviceScope.exit(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,12 @@ import static java.util.Arrays.asList;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringKafkaInstrumentationModule extends InstrumentationModule {
|
public class SpringKafkaInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
public SpringKafkaInstrumentationModule() {
|
public SpringKafkaInstrumentationModule() {
|
||||||
super("spring-kafka", "spring-kafka-2.7");
|
super("spring-kafka", "spring-kafka-2.7");
|
||||||
}
|
}
|
||||||
|
|
@ -24,4 +26,9 @@ public class SpringKafkaInstrumentationModule extends InstrumentationModule {
|
||||||
new AbstractMessageListenerContainerInstrumentation(),
|
new AbstractMessageListenerContainerInstrumentation(),
|
||||||
new ListenerConsumerInstrumentation());
|
new ListenerConsumerInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.pulsar.v2_8.VirtualFieldStore;
|
import io.opentelemetry.javaagent.instrumentation.pulsar.v2_8.VirtualFieldStore;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -38,29 +39,40 @@ public class DefaultPulsarMessageListenerContainerInstrumentation implements Typ
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class DispatchMessageToListenerAdvice {
|
public static class DispatchMessageToListenerAdvice {
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void onEnter(
|
private final Context context;
|
||||||
@Advice.Argument(0) Message<?> message,
|
private final Scope scope;
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
public AdviceScope(Context context, Scope scope) {
|
||||||
Context parentContext = VirtualFieldStore.extract(message);
|
this.context = context;
|
||||||
if (instrumenter().shouldStart(parentContext, message)) {
|
this.scope = scope;
|
||||||
context = instrumenter().start(parentContext, message);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void exit(@Nullable Throwable throwable, Message<?> message) {
|
||||||
|
scope.close();
|
||||||
|
instrumenter().end(context, message, null, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(@Advice.Argument(0) Message<?> message) {
|
||||||
|
Context parentContext = VirtualFieldStore.extract(message);
|
||||||
|
if (!instrumenter().shouldStart(parentContext, message)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Context context = instrumenter().start(parentContext, message);
|
||||||
|
return new AdviceScope(context, context.makeCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onExit(
|
public static void onExit(
|
||||||
@Advice.Argument(0) Message<?> message,
|
@Advice.Argument(0) Message<?> message,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
@Advice.Local("otelScope") Scope scope,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Thrown Throwable throwable) {
|
if (adviceScope != null) {
|
||||||
if (scope == null) {
|
adviceScope.exit(throwable, message);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
scope.close();
|
|
||||||
instrumenter().end(context, message, null, throwable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,13 @@ import static java.util.Collections.singletonList;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringPulsarInstrumentationModule extends InstrumentationModule {
|
public class SpringPulsarInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
public SpringPulsarInstrumentationModule() {
|
public SpringPulsarInstrumentationModule() {
|
||||||
super("spring-pulsar", "spring-pulsar-1.0");
|
super("spring-pulsar", "spring-pulsar-1.0");
|
||||||
}
|
}
|
||||||
|
|
@ -31,4 +33,9 @@ public class SpringPulsarInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new DefaultPulsarMessageListenerContainerInstrumentation());
|
return singletonList(new DefaultPulsarMessageListenerContainerInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -40,34 +41,46 @@ public class AbstractMessageListenerContainerInstrumentation implements TypeInst
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class InvokeListenerAdvice {
|
public static class InvokeListenerAdvice {
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
|
||||||
public static void onEnter(
|
public static class AdviceScope {
|
||||||
@Advice.Argument(1) Object data,
|
private final Context context;
|
||||||
@Advice.Local("otelContext") Context context,
|
private final Scope scope;
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
if (!(data instanceof Message)) {
|
public AdviceScope(Context context, Scope scope) {
|
||||||
return;
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void exit(@Nullable Throwable throwable, Message message) {
|
||||||
|
scope.close();
|
||||||
|
instrumenter().end(context, message, null, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(@Advice.Argument(1) Object data) {
|
||||||
|
if (!(data instanceof Message)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||||
Message message = (Message) data;
|
Message message = (Message) data;
|
||||||
if (instrumenter().shouldStart(parentContext, message)) {
|
if (!instrumenter().shouldStart(parentContext, message)) {
|
||||||
context = instrumenter().start(parentContext, message);
|
return null;
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
Context context = instrumenter().start(parentContext, message);
|
||||||
|
return new AdviceScope(context, context.makeCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
|
||||||
public static void onEnter(
|
public static void onEnter(
|
||||||
@Advice.Argument(1) Object data,
|
@Advice.Argument(1) Object data,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
@Advice.Local("otelScope") Scope scope,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Thrown Throwable throwable) {
|
if (adviceScope == null || !(data instanceof Message)) {
|
||||||
if (scope == null || !(data instanceof Message)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scope.close();
|
adviceScope.exit(throwable, (Message) data);
|
||||||
instrumenter().end(context, (Message) data, null, throwable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,12 @@ import static java.util.Collections.singletonList;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringRabbitInstrumentationModule extends InstrumentationModule {
|
public class SpringRabbitInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
public SpringRabbitInstrumentationModule() {
|
public SpringRabbitInstrumentationModule() {
|
||||||
super("spring-rabbit", "spring-rabbit-1.0");
|
super("spring-rabbit", "spring-rabbit-1.0");
|
||||||
}
|
}
|
||||||
|
|
@ -22,4 +24,9 @@ public class SpringRabbitInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return singletonList(new AbstractMessageListenerContainerInstrumentation());
|
return singletonList(new AbstractMessageListenerContainerInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,14 @@ import static java.util.Arrays.asList;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.rmi.v4_0.client.ClientInstrumentation;
|
import io.opentelemetry.javaagent.instrumentation.spring.rmi.v4_0.client.ClientInstrumentation;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.rmi.v4_0.server.ServerInstrumentation;
|
import io.opentelemetry.javaagent.instrumentation.spring.rmi.v4_0.server.ServerInstrumentation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringRmiInstrumentationModule extends InstrumentationModule {
|
public class SpringRmiInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
|
|
||||||
public SpringRmiInstrumentationModule() {
|
public SpringRmiInstrumentationModule() {
|
||||||
super("spring-rmi", "spring-rmi-4.0");
|
super("spring-rmi", "spring-rmi-4.0");
|
||||||
|
|
@ -25,4 +27,9 @@ public class SpringRmiInstrumentationModule extends InstrumentationModule {
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(new ClientInstrumentation(), new ServerInstrumentation());
|
return asList(new ClientInstrumentation(), new ServerInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -42,35 +43,42 @@ public class ClientInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class InvokeMethodAdvice {
|
public static class InvokeMethodAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void onEnter(
|
private final Method method;
|
||||||
@Advice.Argument(0) MethodInvocation methodInv,
|
private final Context context;
|
||||||
@Advice.Local("method") Method method,
|
private final Scope scope;
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
|
|
||||||
method = methodInv.getMethod();
|
public AdviceScope(Method method, Context context, Scope scope) {
|
||||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
this.method = method;
|
||||||
if (!clientInstrumenter().shouldStart(parentContext, method)) {
|
this.context = context;
|
||||||
return;
|
this.scope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = clientInstrumenter().start(parentContext, method);
|
public void exit(@Nullable Throwable throwable) {
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
|
||||||
public static void stopSpan(
|
|
||||||
@Advice.Local("method") Method method,
|
|
||||||
@Advice.Thrown Throwable throwable,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
|
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scope.close();
|
scope.close();
|
||||||
clientInstrumenter().end(context, method, null, throwable);
|
clientInstrumenter().end(context, method, null, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(@Advice.Argument(0) MethodInvocation methodInv) {
|
||||||
|
Method method = methodInv.getMethod();
|
||||||
|
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||||
|
if (!clientInstrumenter().shouldStart(parentContext, method)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Context context = clientInstrumenter().start(parentContext, method);
|
||||||
|
return new AdviceScope(method, context, context.makeCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
|
public static void stopSpan(
|
||||||
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
|
if (adviceScope != null) {
|
||||||
|
adviceScope.exit(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import io.opentelemetry.instrumentation.api.incubator.semconv.util.ClassAndMetho
|
||||||
import io.opentelemetry.javaagent.bootstrap.CallDepth;
|
import io.opentelemetry.javaagent.bootstrap.CallDepth;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -24,6 +25,7 @@ import org.springframework.remoting.rmi.RmiBasedExporter;
|
||||||
import org.springframework.remoting.support.RemoteInvocation;
|
import org.springframework.remoting.support.RemoteInvocation;
|
||||||
|
|
||||||
public class ServerInstrumentation implements TypeInstrumentation {
|
public class ServerInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
return named("org.springframework.remoting.rmi.RmiBasedExporter");
|
return named("org.springframework.remoting.rmi.RmiBasedExporter");
|
||||||
|
|
@ -41,49 +43,59 @@ public class ServerInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class InvokeMethodAdvice {
|
public static class InvokeMethodAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void onEnter(
|
private final CallDepth callDepth;
|
||||||
@Advice.This RmiBasedExporter thisObject,
|
private final ClassAndMethod request;
|
||||||
@Advice.Argument(0) RemoteInvocation remoteInv,
|
private final Context context;
|
||||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
private final Scope scope;
|
||||||
@Advice.Local("otelRequest") ClassAndMethod request,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
|
|
||||||
callDepth = CallDepth.forClass(RmiBasedExporter.class);
|
private AdviceScope(
|
||||||
|
CallDepth callDepth, ClassAndMethod request, Context context, Scope scope) {
|
||||||
|
this.callDepth = callDepth;
|
||||||
|
this.request = request;
|
||||||
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AdviceScope enter(
|
||||||
|
CallDepth callDepth, RmiBasedExporter rmiExporter, RemoteInvocation remoteInvocation) {
|
||||||
if (callDepth.getAndIncrement() > 0) {
|
if (callDepth.getAndIncrement() > 0) {
|
||||||
return;
|
return new AdviceScope(callDepth, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context parentContext = THREAD_LOCAL_CONTEXT.getAndResetContext();
|
Context parentContext = THREAD_LOCAL_CONTEXT.getAndResetContext();
|
||||||
Class<?> serverClass = thisObject.getService().getClass();
|
Class<?> serverClass = rmiExporter.getService().getClass();
|
||||||
String methodName = remoteInv.getMethodName();
|
String methodName = remoteInvocation.getMethodName();
|
||||||
request = ClassAndMethod.create(serverClass, methodName);
|
ClassAndMethod request = ClassAndMethod.create(serverClass, methodName);
|
||||||
|
|
||||||
if (!serverInstrumenter().shouldStart(parentContext, request)) {
|
if (!serverInstrumenter().shouldStart(parentContext, request)) {
|
||||||
return;
|
return new AdviceScope(callDepth, request, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
context = serverInstrumenter().start(parentContext, request);
|
Context context = serverInstrumenter().start(parentContext, request);
|
||||||
scope = context.makeCurrent();
|
return new AdviceScope(callDepth, request, context, context.makeCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
public void exit(@Nullable Throwable throwable) {
|
||||||
public static void stopSpan(
|
if (callDepth.decrementAndGet() > 0 || scope == null) {
|
||||||
@Advice.Thrown Throwable throwable,
|
|
||||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
|
||||||
@Advice.Local("otelRequest") ClassAndMethod request,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
|
|
||||||
if (callDepth.decrementAndGet() > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (scope == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scope.close();
|
scope.close();
|
||||||
serverInstrumenter().end(context, request, null, throwable);
|
serverInstrumenter().end(context, request, null, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(
|
||||||
|
@Advice.This RmiBasedExporter thisObject, @Advice.Argument(0) RemoteInvocation remoteInv) {
|
||||||
|
return AdviceScope.enter(CallDepth.forClass(RmiBasedExporter.class), thisObject, remoteInv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
|
public static void stopSpan(
|
||||||
|
@Advice.Thrown @Nullable Throwable throwable, @Advice.Enter AdviceScope adviceScope) {
|
||||||
|
adviceScope.exit(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.util.ErrorHandler;
|
import org.springframework.util.ErrorHandler;
|
||||||
|
|
@ -39,12 +41,14 @@ public class DelegatingErrorHandlingRunnableInstrumentation implements TypeInstr
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class WrapErrorHandlerAdvice {
|
public static class WrapErrorHandlerAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToArguments(@ToArgument(1))
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onEnter(
|
public static ErrorHandler onEnter(@Advice.Argument(1) ErrorHandler originalErrorHandler) {
|
||||||
@Advice.Argument(value = 1, readOnly = false) ErrorHandler errorHandler) {
|
ErrorHandler errorHandler = originalErrorHandler;
|
||||||
if (errorHandler != null) {
|
if (errorHandler != null) {
|
||||||
errorHandler = new ErrorHandlerWrapper(errorHandler);
|
errorHandler = new ErrorHandlerWrapper(errorHandler);
|
||||||
}
|
}
|
||||||
|
return errorHandler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,12 @@ import static java.util.Arrays.asList;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringSchedulingInstrumentationModule extends InstrumentationModule {
|
public class SpringSchedulingInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
|
|
||||||
public SpringSchedulingInstrumentationModule() {
|
public SpringSchedulingInstrumentationModule() {
|
||||||
super("spring-scheduling", "spring-scheduling-3.1");
|
super("spring-scheduling", "spring-scheduling-3.1");
|
||||||
|
|
@ -24,4 +26,9 @@ public class SpringSchedulingInstrumentationModule extends InstrumentationModule
|
||||||
return asList(
|
return asList(
|
||||||
new TaskSchedulerInstrumentation(), new DelegatingErrorHandlingRunnableInstrumentation());
|
new TaskSchedulerInstrumentation(), new DelegatingErrorHandlingRunnableInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import io.opentelemetry.javaagent.bootstrap.spring.SpringSchedulingTaskTracing;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
||||||
|
|
@ -49,11 +51,14 @@ public class TaskSchedulerInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class ScheduleMethodAdvice {
|
public static class ScheduleMethodAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToArguments(@ToArgument(0))
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static void onSchedule(@Advice.Argument(value = 0, readOnly = false) Runnable runnable) {
|
public static Runnable onSchedule(@Advice.Argument(0) Runnable originalRunnable) {
|
||||||
|
Runnable runnable = originalRunnable;
|
||||||
if (SpringSchedulingTaskTracing.wrappingEnabled()) {
|
if (SpringSchedulingTaskTracing.wrappingEnabled()) {
|
||||||
runnable = SpringSchedulingRunnableWrapper.wrapIfNeeded(runnable);
|
runnable = SpringSchedulingRunnableWrapper.wrapIfNeeded(runnable);
|
||||||
}
|
}
|
||||||
|
return runnable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
@ -45,28 +46,31 @@ public class DispatcherHandlerInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class HandleAdvice {
|
public static class HandleAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToReturned
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void methodExit(
|
public static Mono<Void> methodExit(
|
||||||
@Advice.Thrown Throwable throwable,
|
@Advice.Thrown Throwable throwable,
|
||||||
@Advice.Argument(0) ServerWebExchange exchange,
|
@Advice.Argument(0) ServerWebExchange exchange,
|
||||||
@Advice.Return(readOnly = false) Mono<Void> mono) {
|
@Advice.Return Mono<Void> originalMono) {
|
||||||
|
Mono<Void> mono = originalMono;
|
||||||
if (mono != null) {
|
if (mono != null) {
|
||||||
// note: it seems like this code should go in @OnMethodExit of
|
// note: it seems like this code should go in @OnMethodExit of
|
||||||
// HandlerAdapterInstrumentation.HandleAdvice instead, but for some reason "GET to bad
|
// HandlerAdapterInstrumentation.HandleAdvice instead, but for some reason "GET to bad
|
||||||
// endpoint annotation API fail Mono" test fails with that placement
|
// endpoint annotation API fail Mono" test fails with that placement
|
||||||
mono = AdviceUtils.end(mono, exchange);
|
mono = AdviceUtils.end(mono, exchange);
|
||||||
}
|
}
|
||||||
|
return mono;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class HandleResultAdvice {
|
public static class HandleResultAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToReturned
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
@Advice.OnMethodExit(suppress = Throwable.class)
|
||||||
public static void methodExit(
|
public static Mono<Void> methodExit(
|
||||||
@Advice.Argument(0) ServerWebExchange exchange,
|
@Advice.Argument(0) ServerWebExchange exchange, @Advice.Return Mono<Void> mono) {
|
||||||
@Advice.Return(readOnly = false) Mono<Void> mono) {
|
return AdviceUtils.wrapMono(mono, exchange.getAttribute(AdviceUtils.CONTEXT));
|
||||||
mono = AdviceUtils.wrapMono(mono, exchange.getAttribute(AdviceUtils.CONTEXT));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute;
|
||||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource;
|
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.web.reactive.HandlerResult;
|
import org.springframework.web.reactive.HandlerResult;
|
||||||
|
|
@ -58,45 +60,43 @@ public class HandlerAdapterInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class HandleAdvice {
|
public static class HandleAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void methodEnter(
|
private final Context context;
|
||||||
@Advice.Argument(0) ServerWebExchange exchange,
|
private final Scope scope;
|
||||||
@Advice.Argument(1) Object handler,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
|
|
||||||
|
private AdviceScope(Context context, Scope scope) {
|
||||||
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(ServerWebExchange exchange, Object handler) {
|
||||||
Context parentContext = Context.current();
|
Context parentContext = Context.current();
|
||||||
|
|
||||||
// HttpRouteSource.CONTROLLER has useFirst true, and it will update http.route only once
|
// HttpRouteSource.CONTROLLER has useFirst true, and it will update http.route only once
|
||||||
// using the last portion of the nested path.
|
// using the last portion of the nested path.
|
||||||
// HttpRouteSource.NESTED_CONTROLLER has useFirst false, and it will make http.route updated
|
// HttpRouteSource.NESTED_CONTROLLER has useFirst false, and it will make http.route updated
|
||||||
// twice: 1st using the last portion of the nested path, 2nd time using the full nested path.
|
// twice: 1st using the last portion of the nested path, 2nd time using the full nested
|
||||||
|
// path.
|
||||||
HttpServerRoute.update(
|
HttpServerRoute.update(
|
||||||
parentContext, HttpServerRouteSource.NESTED_CONTROLLER, httpRouteGetter(), exchange);
|
parentContext, HttpServerRouteSource.NESTED_CONTROLLER, httpRouteGetter(), exchange);
|
||||||
|
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!instrumenter().shouldStart(parentContext, handler)) {
|
if (!instrumenter().shouldStart(parentContext, handler)) {
|
||||||
return;
|
return null;
|
||||||
|
}
|
||||||
|
Context context = instrumenter().start(parentContext, handler);
|
||||||
|
return new AdviceScope(context, context.makeCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
context = instrumenter().start(parentContext, handler);
|
public Mono<HandlerResult> exit(
|
||||||
scope = context.makeCurrent();
|
Throwable throwable,
|
||||||
}
|
ServerWebExchange exchange,
|
||||||
|
Object handler,
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
Mono<HandlerResult> mono) {
|
||||||
public static void methodExit(
|
|
||||||
@Advice.Return(readOnly = false) Mono<HandlerResult> mono,
|
|
||||||
@Advice.Argument(0) ServerWebExchange exchange,
|
|
||||||
@Advice.Argument(1) Object handler,
|
|
||||||
@Advice.Thrown Throwable throwable,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scope.close();
|
scope.close();
|
||||||
|
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
|
|
@ -109,6 +109,31 @@ public class HandlerAdapterInstrumentation implements TypeInstrumentation {
|
||||||
// the Mono is already wrapped at this point, but doesn't read the ON_SPAN_END until
|
// the Mono is already wrapped at this point, but doesn't read the ON_SPAN_END until
|
||||||
// the Mono is resolved, which is after this point
|
// the Mono is resolved, which is after this point
|
||||||
}
|
}
|
||||||
|
return mono;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope methodEnter(
|
||||||
|
@Advice.Argument(0) ServerWebExchange exchange, @Advice.Argument(1) Object handler) {
|
||||||
|
return AdviceScope.enter(exchange, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssignReturned.ToReturned
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
|
public static Mono<HandlerResult> methodExit(
|
||||||
|
@Advice.Return Mono<HandlerResult> mono,
|
||||||
|
@Advice.Argument(0) ServerWebExchange exchange,
|
||||||
|
@Advice.Argument(1) Object handler,
|
||||||
|
@Advice.Thrown Throwable throwable,
|
||||||
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
|
|
||||||
|
if (adviceScope == null) {
|
||||||
|
return mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
return adviceScope.exit(throwable, exchange, handler, mono);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.asm.Advice.AssignReturned;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
import org.springframework.web.reactive.function.server.HandlerFunction;
|
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||||
|
|
@ -61,14 +62,16 @@ public class RouterFunctionInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class RouteAdvice {
|
public static class RouteAdvice {
|
||||||
|
|
||||||
|
@AssignReturned.ToReturned
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void methodExit(
|
public static Mono<HandlerFunction<?>> methodExit(
|
||||||
@Advice.This RouterFunction<?> thiz,
|
@Advice.This RouterFunction<?> thiz,
|
||||||
@Advice.Return(readOnly = false) Mono<HandlerFunction<?>> result,
|
@Advice.Return Mono<HandlerFunction<?>> result,
|
||||||
@Advice.Thrown Throwable throwable) {
|
@Advice.Thrown Throwable throwable) {
|
||||||
if (throwable == null) {
|
if (throwable == null) {
|
||||||
result = result.doOnNext(new RouteOnSuccess(thiz));
|
return result.doOnNext(new RouteOnSuccess(thiz));
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,12 @@ import static java.util.Arrays.asList;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class WebfluxServerInstrumentationModule extends InstrumentationModule {
|
public class WebfluxServerInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
|
|
||||||
public WebfluxServerInstrumentationModule() {
|
public WebfluxServerInstrumentationModule() {
|
||||||
super("spring-webflux", "spring-webflux-5.0", "spring-webflux-server");
|
super("spring-webflux", "spring-webflux-5.0", "spring-webflux-server");
|
||||||
|
|
@ -26,4 +28,9 @@ public class WebfluxServerInstrumentationModule extends InstrumentationModule {
|
||||||
new HandlerAdapterInstrumentation(),
|
new HandlerAdapterInstrumentation(),
|
||||||
new RouterFunctionInstrumentation());
|
new RouterFunctionInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import io.opentelemetry.instrumentation.netty.v4_1.internal.ServerContext;
|
||||||
import io.opentelemetry.instrumentation.netty.v4_1.internal.ServerContexts;
|
import io.opentelemetry.instrumentation.netty.v4_1.internal.ServerContexts;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -35,6 +36,7 @@ public class ContextHandlerInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class CreateOperationsAdvice {
|
public static class CreateOperationsAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static Scope onEnter(@Advice.Argument(0) Channel channel) {
|
public static Scope onEnter(@Advice.Argument(0) Channel channel) {
|
||||||
// set context to the first unprocessed request
|
// set context to the first unprocessed request
|
||||||
|
|
@ -46,7 +48,7 @@ public class ContextHandlerInstrumentation implements TypeInstrumentation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void onExit(@Advice.Enter Scope scope) {
|
public static void onExit(@Advice.Enter @Nullable Scope scope) {
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
scope.close();
|
scope.close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import io.opentelemetry.instrumentation.netty.v4_1.internal.ServerContext;
|
||||||
import io.opentelemetry.instrumentation.netty.v4_1.internal.ServerContexts;
|
import io.opentelemetry.instrumentation.netty.v4_1.internal.ServerContexts;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -35,6 +36,7 @@ public class HttpTrafficHandlerInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class RunAdvice {
|
public static class RunAdvice {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
public static Scope onEnter(
|
public static Scope onEnter(
|
||||||
@Advice.FieldValue("ctx") ChannelHandlerContext channelHandlerContext) {
|
@Advice.FieldValue("ctx") ChannelHandlerContext channelHandlerContext) {
|
||||||
|
|
@ -47,7 +49,7 @@ public class HttpTrafficHandlerInstrumentation implements TypeInstrumentation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void onExit(@Advice.Enter Scope scope) {
|
public static void onExit(@Advice.Enter @Nullable Scope scope) {
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
scope.close();
|
scope.close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.webmvc.v3_1;
|
package io.opentelemetry.javaagent.instrumentation.spring.webmvc.v3_1;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.webmvc.v3_1.SpringWebMvcSingletons.modelAndViewInstrumenter;
|
import static io.opentelemetry.javaagent.instrumentation.spring.webmvc.v3_1.SpringWebMvcSingletons.modelAndViewInstrumenter;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
||||||
|
|
@ -19,6 +18,7 @@ import io.opentelemetry.javaagent.bootstrap.InstrumentationProxyHelper;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -76,29 +76,45 @@ public class DispatcherServletInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class RenderAdvice {
|
public static class RenderAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void onEnter(
|
private final Context context;
|
||||||
@Advice.Argument(0) ModelAndView mv,
|
private final Scope scope;
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
private AdviceScope(Context context, Scope scope) {
|
||||||
Context parentContext = currentContext();
|
this.context = context;
|
||||||
if (modelAndViewInstrumenter().shouldStart(parentContext, mv)) {
|
this.scope = scope;
|
||||||
context = modelAndViewInstrumenter().start(parentContext, mv);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(ModelAndView mv) {
|
||||||
|
Context parentContext = Context.current();
|
||||||
|
if (!modelAndViewInstrumenter().shouldStart(parentContext, mv)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Context context = modelAndViewInstrumenter().start(parentContext, mv);
|
||||||
|
return new AdviceScope(context, context.makeCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exit(ModelAndView mv, @Nullable Throwable throwable) {
|
||||||
|
scope.close();
|
||||||
|
modelAndViewInstrumenter().end(context, mv, null, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(@Advice.Argument(0) ModelAndView mv) {
|
||||||
|
return AdviceScope.enter(mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void stopSpan(
|
public static void stopSpan(
|
||||||
@Advice.Argument(0) ModelAndView mv,
|
@Advice.Argument(0) ModelAndView mv,
|
||||||
@Advice.Thrown Throwable throwable,
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
if (adviceScope != null) {
|
||||||
if (scope == null) {
|
adviceScope.exit(mv, throwable);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
scope.close();
|
|
||||||
modelAndViewInstrumenter().end(context, mv, null, throwable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,14 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute;
|
||||||
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.webmvc.IsGrailsHandler;
|
import io.opentelemetry.javaagent.instrumentation.spring.webmvc.IsGrailsHandler;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
|
@ -54,23 +55,28 @@ public class HandlerAdapterInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class ControllerAdvice {
|
public static class ControllerAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void nameResourceAndStartSpan(
|
private final Context context;
|
||||||
@Advice.Argument(0) HttpServletRequest request,
|
private final Scope scope;
|
||||||
@Advice.Argument(2) Object handler,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
public AdviceScope(Context context, Scope scope) {
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(HttpServletRequest request, Object handler) {
|
||||||
// TODO (trask) should there be a way to customize Instrumenter.shouldStart()?
|
// TODO (trask) should there be a way to customize Instrumenter.shouldStart()?
|
||||||
if (IsGrailsHandler.isGrailsHandler(handler)) {
|
if (IsGrailsHandler.isGrailsHandler(handler)) {
|
||||||
// skip creating handler span for grails, grails instrumentation will take care of it
|
// skip creating handler span for grails, grails instrumentation will take care of it
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
Context parentContext = Context.current();
|
||||||
|
|
||||||
// don't start a new top-level span
|
// don't start a new top-level span
|
||||||
if (!Java8BytecodeBridge.spanFromContext(parentContext).getSpanContext().isValid()) {
|
if (!Span.fromContext(parentContext).getSpanContext().isValid()) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name the parent span based on the matching pattern
|
// Name the parent span based on the matching pattern
|
||||||
|
|
@ -78,25 +84,36 @@ public class HandlerAdapterInstrumentation implements TypeInstrumentation {
|
||||||
parentContext, CONTROLLER, SpringWebMvcServerSpanNaming.SERVER_SPAN_NAME, request);
|
parentContext, CONTROLLER, SpringWebMvcServerSpanNaming.SERVER_SPAN_NAME, request);
|
||||||
|
|
||||||
if (!handlerInstrumenter().shouldStart(parentContext, handler)) {
|
if (!handlerInstrumenter().shouldStart(parentContext, handler)) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now create a span for handler/controller execution.
|
// Now create a span for handler/controller execution.
|
||||||
context = handlerInstrumenter().start(parentContext, handler);
|
Context context = handlerInstrumenter().start(parentContext, handler);
|
||||||
scope = context.makeCurrent();
|
return new AdviceScope(context, context.makeCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exit(Object handler, @Nullable Throwable throwable) {
|
||||||
|
scope.close();
|
||||||
|
handlerInstrumenter().end(context, handler, null, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope nameResourceAndStartSpan(
|
||||||
|
@Advice.Argument(0) HttpServletRequest request, @Advice.Argument(2) Object handler) {
|
||||||
|
return AdviceScope.enter(request, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void stopSpan(
|
public static void stopSpan(
|
||||||
@Advice.Argument(2) Object handler,
|
@Advice.Argument(2) Object handler,
|
||||||
@Advice.Thrown Throwable throwable,
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
if (scope == null) {
|
if (adviceScope != null) {
|
||||||
return;
|
adviceScope.exit(handler, throwable);
|
||||||
}
|
}
|
||||||
scope.close();
|
|
||||||
handlerInstrumenter().end(context, handler, null, throwable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,9 @@ public class SpringWebMvcInstrumentationModule extends InstrumentationModule
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(new DispatcherServletInstrumentation(), new HandlerAdapterInstrumentation());
|
return asList(new DispatcherServletInstrumentation(), new HandlerAdapterInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.webmvc.v6_0;
|
package io.opentelemetry.javaagent.instrumentation.spring.webmvc.v6_0;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.webmvc.v6_0.SpringWebMvcSingletons.modelAndViewInstrumenter;
|
import static io.opentelemetry.javaagent.instrumentation.spring.webmvc.v6_0.SpringWebMvcSingletons.modelAndViewInstrumenter;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
|
||||||
|
|
@ -19,6 +18,7 @@ import io.opentelemetry.javaagent.bootstrap.InstrumentationProxyHelper;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -77,29 +77,45 @@ public class DispatcherServletInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class RenderAdvice {
|
public static class RenderAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void onEnter(
|
private final Context context;
|
||||||
@Advice.Argument(0) ModelAndView mv,
|
private final Scope scope;
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
private AdviceScope(Context context, Scope scope) {
|
||||||
Context parentContext = currentContext();
|
this.context = context;
|
||||||
if (modelAndViewInstrumenter().shouldStart(parentContext, mv)) {
|
this.scope = scope;
|
||||||
context = modelAndViewInstrumenter().start(parentContext, mv);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(ModelAndView mv) {
|
||||||
|
Context parentContext = Context.current();
|
||||||
|
if (!modelAndViewInstrumenter().shouldStart(parentContext, mv)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Context context = modelAndViewInstrumenter().start(parentContext, mv);
|
||||||
|
return new AdviceScope(context, context.makeCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exit(ModelAndView mv, @Nullable Throwable throwable) {
|
||||||
|
scope.close();
|
||||||
|
modelAndViewInstrumenter().end(context, mv, null, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope onEnter(@Advice.Argument(0) ModelAndView mv) {
|
||||||
|
return AdviceScope.enter(mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void stopSpan(
|
public static void stopSpan(
|
||||||
@Advice.Argument(0) ModelAndView mv,
|
@Advice.Argument(0) ModelAndView mv,
|
||||||
@Advice.Thrown Throwable throwable,
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
if (adviceScope != null) {
|
||||||
if (scope == null) {
|
adviceScope.exit(mv, throwable);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
scope.close();
|
|
||||||
modelAndViewInstrumenter().end(context, mv, null, throwable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,15 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.trace.Span;
|
||||||
import io.opentelemetry.context.Context;
|
import io.opentelemetry.context.Context;
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute;
|
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute;
|
||||||
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
import io.opentelemetry.javaagent.instrumentation.spring.webmvc.IsGrailsHandler;
|
import io.opentelemetry.javaagent.instrumentation.spring.webmvc.IsGrailsHandler;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -54,23 +55,28 @@ public class HandlerAdapterInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class ControllerAdvice {
|
public static class ControllerAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void nameResourceAndStartSpan(
|
private final Context context;
|
||||||
@Advice.Argument(0) HttpServletRequest request,
|
private final Scope scope;
|
||||||
@Advice.Argument(2) Object handler,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
private AdviceScope(Context context, Scope scope) {
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static AdviceScope enter(HttpServletRequest request, Object handler) {
|
||||||
// TODO (trask) should there be a way to customize Instrumenter.shouldStart()?
|
// TODO (trask) should there be a way to customize Instrumenter.shouldStart()?
|
||||||
if (IsGrailsHandler.isGrailsHandler(handler)) {
|
if (IsGrailsHandler.isGrailsHandler(handler)) {
|
||||||
// skip creating handler span for grails, grails instrumentation will take care of it
|
// skip creating handler span for grails, grails instrumentation will take care of it
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
Context parentContext = Context.current();
|
||||||
|
|
||||||
// don't start a new top-level span
|
// don't start a new top-level span
|
||||||
if (!Java8BytecodeBridge.spanFromContext(parentContext).getSpanContext().isValid()) {
|
if (!Span.fromContext(parentContext).getSpanContext().isValid()) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name the parent span based on the matching pattern
|
// Name the parent span based on the matching pattern
|
||||||
|
|
@ -78,25 +84,35 @@ public class HandlerAdapterInstrumentation implements TypeInstrumentation {
|
||||||
parentContext, CONTROLLER, SpringWebMvcServerSpanNaming.SERVER_SPAN_NAME, request);
|
parentContext, CONTROLLER, SpringWebMvcServerSpanNaming.SERVER_SPAN_NAME, request);
|
||||||
|
|
||||||
if (!handlerInstrumenter().shouldStart(parentContext, handler)) {
|
if (!handlerInstrumenter().shouldStart(parentContext, handler)) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now create a span for handler/controller execution.
|
// Now create a span for handler/controller execution.
|
||||||
context = handlerInstrumenter().start(parentContext, handler);
|
Context context = handlerInstrumenter().start(parentContext, handler);
|
||||||
scope = context.makeCurrent();
|
return new AdviceScope(context, context.makeCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exit(Object handler, @Nullable Throwable throwable) {
|
||||||
|
scope.close();
|
||||||
|
handlerInstrumenter().end(context, handler, null, throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope nameResourceAndStartSpan(
|
||||||
|
@Advice.Argument(0) HttpServletRequest request, @Advice.Argument(2) Object handler) {
|
||||||
|
return AdviceScope.enter(request, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void stopSpan(
|
public static void stopSpan(
|
||||||
@Advice.Argument(2) Object handler,
|
@Advice.Argument(2) Object handler,
|
||||||
@Advice.Thrown Throwable throwable,
|
@Advice.Thrown @Nullable Throwable throwable,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Enter @Nullable AdviceScope adviceScope) {
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
if (adviceScope != null) {
|
||||||
if (scope == null) {
|
adviceScope.exit(handler, throwable);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
scope.close();
|
|
||||||
handlerInstrumenter().end(context, handler, null, throwable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,9 @@ public class SpringWebMvcInstrumentationModule extends InstrumentationModule
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
return asList(new DispatcherServletInstrumentation(), new HandlerAdapterInstrumentation());
|
return asList(new DispatcherServletInstrumentation(), new HandlerAdapterInstrumentation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.spring.ws.v2_0;
|
package io.opentelemetry.javaagent.instrumentation.spring.ws.v2_0;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.spring.ws.v2_0.SpringWsSingletons.instrumenter;
|
import static io.opentelemetry.javaagent.instrumentation.spring.ws.v2_0.SpringWsSingletons.instrumenter;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.declaresMethod;
|
import static net.bytebuddy.matcher.ElementMatchers.declaresMethod;
|
||||||
|
|
@ -18,6 +17,7 @@ import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.javaagent.bootstrap.CallDepth;
|
import io.opentelemetry.javaagent.bootstrap.CallDepth;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
|
@ -51,42 +51,58 @@ public class AnnotatedMethodInstrumentation implements TypeInstrumentation {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class AnnotatedMethodAdvice {
|
public static class AnnotatedMethodAdvice {
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
public static class AdviceScope {
|
||||||
public static void startSpan(
|
private final CallDepth callDepth;
|
||||||
@Advice.Origin("#t") Class<?> codeClass,
|
private final SpringWsRequest request;
|
||||||
@Advice.Origin("#m") String methodName,
|
private final Context context;
|
||||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
private final Scope scope;
|
||||||
@Advice.Local("otelRequest") SpringWsRequest request,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
private AdviceScope(
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
CallDepth callDepth, SpringWsRequest request, Context context, Scope scope) {
|
||||||
callDepth = CallDepth.forClass(PayloadRoot.class);
|
this.callDepth = callDepth;
|
||||||
|
this.request = request;
|
||||||
|
this.context = context;
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AdviceScope enter(CallDepth callDepth, Class<?> codeClass, String methodName) {
|
||||||
if (callDepth.getAndIncrement() > 0) {
|
if (callDepth.getAndIncrement() > 0) {
|
||||||
return;
|
return new AdviceScope(callDepth, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context parentContext = currentContext();
|
Context parentContext = Context.current();
|
||||||
request = SpringWsRequest.create(codeClass, methodName);
|
SpringWsRequest request = SpringWsRequest.create(codeClass, methodName);
|
||||||
if (!instrumenter().shouldStart(parentContext, request)) {
|
if (!instrumenter().shouldStart(parentContext, request)) {
|
||||||
|
return new AdviceScope(callDepth, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Context context = instrumenter().start(parentContext, request);
|
||||||
|
return new AdviceScope(callDepth, request, context, parentContext.makeCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exit(@Nullable Throwable throwable) {
|
||||||
|
if (callDepth.decrementAndGet() > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (scope == null) {
|
||||||
context = instrumenter().start(parentContext, request);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
|
||||||
public static void stopSpan(
|
|
||||||
@Advice.Thrown Throwable throwable,
|
|
||||||
@Advice.Local("otelCallDepth") CallDepth callDepth,
|
|
||||||
@Advice.Local("otelRequest") SpringWsRequest request,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
if (callDepth.decrementAndGet() > 0 || scope == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.close();
|
scope.close();
|
||||||
instrumenter().end(context, request, null, throwable);
|
instrumenter().end(context, request, null, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static AdviceScope startSpan(
|
||||||
|
@Advice.Origin("#t") Class<?> codeClass, @Advice.Origin("#m") String methodName) {
|
||||||
|
CallDepth callDepth = CallDepth.forClass(PayloadRoot.class);
|
||||||
|
return AdviceScope.enter(callDepth, codeClass, methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
|
public static void stopSpan(
|
||||||
|
@Advice.Thrown @Nullable Throwable throwable, @Advice.Enter AdviceScope adviceScope) {
|
||||||
|
adviceScope.exit(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,14 @@ import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig;
|
import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
|
||||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
@AutoService(InstrumentationModule.class)
|
||||||
public class SpringWsInstrumentationModule extends InstrumentationModule {
|
public class SpringWsInstrumentationModule extends InstrumentationModule
|
||||||
|
implements ExperimentalInstrumentationModule {
|
||||||
public SpringWsInstrumentationModule() {
|
public SpringWsInstrumentationModule() {
|
||||||
super("spring-ws", "spring-ws-2.0");
|
super("spring-ws", "spring-ws-2.0");
|
||||||
}
|
}
|
||||||
|
|
@ -29,4 +31,9 @@ public class SpringWsInstrumentationModule extends InstrumentationModule {
|
||||||
// this instrumentation only produces controller telemetry
|
// this instrumentation only produces controller telemetry
|
||||||
return super.defaultEnabled(config) && ExperimentalConfig.get().controllerTelemetryEnabled();
|
return super.defaultEnabled(config) && ExperimentalConfig.get().controllerTelemetryEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIndyReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue