diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/ActionInvocationInstrumentation.java b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/ActionInvocationInstrumentation.java index a262311a69..a15a8fc934 100644 --- a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/ActionInvocationInstrumentation.java +++ b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/ActionInvocationInstrumentation.java @@ -5,9 +5,10 @@ package io.opentelemetry.javaagent.instrumentation.struts2; +import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTROLLER; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.instrumentation.struts2.Struts2Tracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.struts2.StrutsSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -15,6 +16,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named; import com.opensymphony.xwork2.ActionInvocation; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge; @@ -51,25 +53,32 @@ public class ActionInvocationInstrumentation implements TypeInstrumentation { @Advice.Local("otelScope") Scope scope) { Context parentContext = Java8BytecodeBridge.currentContext(); - context = tracer().startSpan(parentContext, actionInvocation); - scope = context.makeCurrent(); + ServerSpanNaming.updateServerSpanName( + parentContext, + CONTROLLER, + StrutsServerSpanNaming.getServerSpanNameSupplier( + parentContext, actionInvocation.getProxy())); - tracer().updateServerSpanName(parentContext, actionInvocation.getProxy()); + if (!instrumenter().shouldStart(parentContext, actionInvocation)) { + return; + } + + context = instrumenter().start(parentContext, actionInvocation); + scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void stopSpan( @Advice.Thrown Throwable throwable, + @Advice.This ActionInvocation actionInvocation, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { - if (scope != null) { - scope.close(); - } - if (throwable != null) { - tracer().endExceptionally(context, throwable); - } else { - tracer().end(context); + if (scope == null) { + return; } + scope.close(); + + instrumenter().end(context, actionInvocation, null, throwable); } } } diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2Tracer.java b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2Tracer.java deleted file mode 100644 index 944f090ab6..0000000000 --- a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2Tracer.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.struts2; - -import static io.opentelemetry.api.trace.SpanKind.INTERNAL; -import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTROLLER; - -import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.ActionProxy; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming; -import io.opentelemetry.instrumentation.api.servlet.ServletContextPath; -import io.opentelemetry.instrumentation.api.tracer.BaseTracer; -import io.opentelemetry.instrumentation.api.tracer.SpanNames; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; - -public class Struts2Tracer extends BaseTracer { - - private static final Struts2Tracer TRACER = new Struts2Tracer(); - - public static Struts2Tracer tracer() { - return TRACER; - } - - public Context startSpan(Context parentContext, ActionInvocation actionInvocation) { - Object action = actionInvocation.getAction(); - Class actionClass = action.getClass(); - - String method = actionInvocation.getProxy().getMethod(); - String spanName = SpanNames.fromMethod(actionClass, method); - - SpanBuilder strutsSpan = spanBuilder(parentContext, spanName, INTERNAL); - - strutsSpan.setAttribute(SemanticAttributes.CODE_NAMESPACE, actionClass.getName()); - if (method != null) { - strutsSpan.setAttribute(SemanticAttributes.CODE_FUNCTION, method); - } - - return parentContext.with(strutsSpan.startSpan()); - } - - // Handle cases where action parameters are encoded into URL path - public void updateServerSpanName(Context context, ActionProxy actionProxy) { - ServerSpanNaming.updateServerSpanName( - context, CONTROLLER, () -> getServerSpanName(context, actionProxy)); - } - - private static String getServerSpanName(Context context, ActionProxy actionProxy) { - // We take name from the config, because it contains the path pattern from the - // configuration. - String result = actionProxy.getConfig().getName(); - - String actionNamespace = actionProxy.getNamespace(); - if (actionNamespace != null && !actionNamespace.isEmpty()) { - if (actionNamespace.endsWith("/") || result.startsWith("/")) { - result = actionNamespace + result; - } else { - result = actionNamespace + "/" + result; - } - } - - if (!result.startsWith("/")) { - result = "/" + result; - } - - return ServletContextPath.prepend(context, result); - } - - @Override - protected String getInstrumentationName() { - return "io.opentelemetry.struts-2.3"; - } -} diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsCodeAttributesExtractor.java b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsCodeAttributesExtractor.java new file mode 100644 index 0000000000..09ff133674 --- /dev/null +++ b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsCodeAttributesExtractor.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts2; + +import com.opensymphony.xwork2.ActionInvocation; +import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class StrutsCodeAttributesExtractor extends CodeAttributesExtractor { + + @Override + protected Class codeClass(ActionInvocation actionInvocation) { + return actionInvocation.getAction().getClass(); + } + + @Override + protected String methodName(ActionInvocation actionInvocation) { + return actionInvocation.getProxy().getMethod(); + } + + @Override + protected @Nullable String filePath(ActionInvocation actionInvocation) { + return null; + } + + @Override + protected @Nullable Long lineNumber(ActionInvocation actionInvocation) { + return null; + } +} diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsServerSpanNaming.java b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsServerSpanNaming.java new file mode 100644 index 0000000000..696986748c --- /dev/null +++ b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsServerSpanNaming.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts2; + +import com.opensymphony.xwork2.ActionProxy; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.servlet.ServletContextPath; +import java.util.function.Supplier; + +public class StrutsServerSpanNaming { + + public static Supplier getServerSpanNameSupplier( + Context context, ActionProxy actionProxy) { + return () -> getServerSpanName(context, actionProxy); + } + + private static String getServerSpanName(Context context, ActionProxy actionProxy) { + // We take name from the config, because it contains the path pattern from the + // configuration. + String result = actionProxy.getConfig().getName(); + + String actionNamespace = actionProxy.getNamespace(); + if (actionNamespace != null && !actionNamespace.isEmpty()) { + if (actionNamespace.endsWith("/") || result.startsWith("/")) { + result = actionNamespace + result; + } else { + result = actionNamespace + "/" + result; + } + } + + if (!result.startsWith("/")) { + result = "/" + result; + } + + return ServletContextPath.prepend(context, result); + } +} diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsSingletons.java b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsSingletons.java new file mode 100644 index 0000000000..fae0a36f0a --- /dev/null +++ b/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsSingletons.java @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts2; + +import com.opensymphony.xwork2.ActionInvocation; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.code.CodeAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.code.CodeSpanNameExtractor; + +public class StrutsSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.struts-2.3"; + + private static final Instrumenter INSTRUMENTER; + + static { + CodeAttributesExtractor codeAttributes = + new StrutsCodeAttributesExtractor(); + INSTRUMENTER = + Instrumenter.newBuilder( + GlobalOpenTelemetry.get(), + INSTRUMENTATION_NAME, + CodeSpanNameExtractor.create(codeAttributes)) + .addAttributesExtractor(codeAttributes) + .newInstrumenter(); + } + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private StrutsSingletons() {} +}