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