JAX-RS: add code.namespace and code.function attributes (#2805)

This commit is contained in:
Lauri Tulmin 2021-04-14 22:58:03 +03:00 committed by GitHub
parent 437547d949
commit d1ff1e12ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 11 deletions

View File

@ -6,12 +6,14 @@
package io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.servlet.ServletContextPath;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.instrumentation.api.tracer.ServerSpan;
import io.opentelemetry.javaagent.instrumentation.api.ClassHierarchyIterable;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
@ -49,7 +51,17 @@ public class JaxRsAnnotationsTracer extends BaseTracer {
updateServerSpanName(parentContext, serverSpan, pathBasedSpanName);
}
return startSpan(parentContext, spanName, SpanKind.INTERNAL);
SpanBuilder spanBuilder = spanBuilder(parentContext, spanName, SpanKind.INTERNAL);
setCodeAttributes(spanBuilder, target, method);
Span span = spanBuilder.startSpan();
return parentContext.with(span);
}
private void setCodeAttributes(SpanBuilder spanBuilder, Class<?> target, Method method) {
spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, target.getName());
if (method != null) {
spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, method.getName());
}
}
private void updateServerSpanName(Context context, Span span, String spanName) {

View File

@ -8,6 +8,7 @@ import static io.opentelemetry.instrumentation.test.utils.ClassUtils.getClassNam
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderServerTrace
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.HEAD
@ -21,12 +22,13 @@ class JaxRsAnnotations1InstrumentationTest extends AgentInstrumentationSpecifica
def "instrumentation can be used as root span and resource is set to METHOD PATH"() {
setup:
new Jax() {
def jax = new Jax() {
@POST
@Path("/a")
void call() {
}
}.call()
}
jax.call()
expect:
assertTraces(1) {
@ -34,6 +36,8 @@ class JaxRsAnnotations1InstrumentationTest extends AgentInstrumentationSpecifica
span(0) {
name "/a"
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" jax.getClass().getName()
"${SemanticAttributes.CODE_FUNCTION.key}" "call"
}
}
}
@ -61,6 +65,8 @@ class JaxRsAnnotations1InstrumentationTest extends AgentInstrumentationSpecifica
name "${className}.call"
childOf span(0)
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" obj.getClass().getName()
"${SemanticAttributes.CODE_FUNCTION.key}" "call"
}
}
}

View File

@ -9,6 +9,7 @@ import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderSer
import io.dropwizard.testing.junit.ResourceTestRule
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import org.junit.ClassRule
import spock.lang.Shared
import spock.lang.Unroll
@ -47,6 +48,8 @@ class JerseyTest extends AgentInstrumentationSpecification {
childOf span(0)
name controllerName
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" ~/Resource[$]Test*/
"${SemanticAttributes.CODE_FUNCTION.key}" "hello"
}
}
}
@ -83,6 +86,8 @@ class JerseyTest extends AgentInstrumentationSpecification {
name controller1Name
kind INTERNAL
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" ~/Resource[$]Test*/
"${SemanticAttributes.CODE_FUNCTION.key}" "nested"
}
}
}

View File

@ -8,11 +8,13 @@ package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0;
import static io.opentelemetry.api.trace.SpanKind.INTERNAL;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.servlet.ServletContextPath;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.instrumentation.api.tracer.ServerSpan;
import io.opentelemetry.javaagent.instrumentation.api.ClassHierarchyIterable;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
@ -48,7 +50,9 @@ public class JaxRsAnnotationsTracer extends BaseTracer {
// We create span and immediately update its name
// We do that in order to reuse logic inside updateSpanNames method, which is used externally as
// well.
Span span = spanBuilder(parentContext, "jax-rs.request", INTERNAL).startSpan();
SpanBuilder spanBuilder = spanBuilder(parentContext, "jax-rs.request", INTERNAL);
setCodeAttributes(spanBuilder, target, method);
Span span = spanBuilder.startSpan();
updateSpanNames(
parentContext, span, ServerSpan.fromContextOrNull(parentContext), target, method);
return parentContext.with(span);
@ -56,7 +60,14 @@ public class JaxRsAnnotationsTracer extends BaseTracer {
public void updateSpanNames(
Context context, Span span, Span serverSpan, Class<?> target, Method method) {
String pathBasedSpanName = ServletContextPath.prepend(context, getPathSpanName(target, method));
String pathBasedSpanName = getPathSpanName(target, method);
// If path based name is empty skip prepending context path so that path based name would
// remain as an empty string for which we skip updating span name. Path base span name is
// empty when method and class don't have a jax-rs path annotation, this can happen when
// creating an "abort" span, see RequestContextHelper.
if (!pathBasedSpanName.isEmpty()) {
pathBasedSpanName = ServletContextPath.prepend(context, pathBasedSpanName);
}
if (serverSpan == null) {
updateSpanName(span, pathBasedSpanName);
} else {
@ -71,6 +82,13 @@ public class JaxRsAnnotationsTracer extends BaseTracer {
}
}
private void setCodeAttributes(SpanBuilder spanBuilder, Class<?> target, Method method) {
spanBuilder.setAttribute(SemanticAttributes.CODE_NAMESPACE, target.getName());
if (method != null) {
spanBuilder.setAttribute(SemanticAttributes.CODE_FUNCTION, method.getName());
}
}
/**
* Returns the span name given a JaxRS annotated method. Results are cached so this method can be
* called multiple times without significantly impacting performance.

View File

@ -8,6 +8,7 @@ import static io.opentelemetry.instrumentation.test.utils.ClassUtils.getClassNam
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderServerTrace
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.HEAD
@ -21,12 +22,13 @@ abstract class JaxRsAnnotationsInstrumentationTest extends AgentInstrumentationS
def "instrumentation can be used as root span and resource is set to METHOD PATH"() {
setup:
new Jax() {
def jax = new Jax() {
@POST
@Path("/a")
void call() {
}
}.call()
}
jax.call()
expect:
assertTraces(1) {
@ -34,6 +36,8 @@ abstract class JaxRsAnnotationsInstrumentationTest extends AgentInstrumentationS
span(0) {
name "/a"
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" jax.getClass().getName()
"${SemanticAttributes.CODE_FUNCTION.key}" "call"
}
}
}
@ -61,6 +65,8 @@ abstract class JaxRsAnnotationsInstrumentationTest extends AgentInstrumentationS
name "${className}.call"
childOf span(0)
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" obj.getClass().getName()
"${SemanticAttributes.CODE_FUNCTION.key}" "call"
}
}
}

View File

@ -8,6 +8,7 @@ import static io.opentelemetry.api.trace.SpanKind.SERVER
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderServerTrace
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import javax.ws.rs.container.ContainerRequestContext
import javax.ws.rs.container.ContainerRequestFilter
import javax.ws.rs.container.PreMatching
@ -83,8 +84,15 @@ abstract class JaxRsFilterTest extends AgentInstrumentationSpecification {
span(1) {
childOf span(0)
name controllerName
if (!runsOnServer()) {
if (abortPrematch) {
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" "JaxRsFilterTest\$PrematchRequestFilter"
"${SemanticAttributes.CODE_FUNCTION.key}" "filter"
}
} else {
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" ~/Resource[$]Test*/
"${SemanticAttributes.CODE_FUNCTION.key}" "hello"
}
}
}
@ -135,9 +143,9 @@ abstract class JaxRsFilterTest extends AgentInstrumentationSpecification {
childOf span(0)
name controller1Name
kind INTERNAL
if (!runsOnServer()) {
attributes {
}
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" ~/Resource[$]Test*/
"${SemanticAttributes.CODE_FUNCTION.key}" "nested"
}
}
}

View File

@ -222,6 +222,8 @@ abstract class JaxRsHttpServerTest<S> extends HttpServerTest<S> implements Agent
}
childOf((SpanData) parent)
attributes {
"${SemanticAttributes.CODE_NAMESPACE.key}" "JaxRsTestResource"
"${SemanticAttributes.CODE_FUNCTION.key}" methodName
if (isCancelled) {
"jaxrs.canceled" true
}