Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use URL path template when tracing REST clients where possible #39534

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void testPropagatorCustomizer_NoPropagation() {

List<SpanData> spans = spanExporter.getFinishedSpanItems(2);
SpanData clientSpan = getSpanByKindAndParentId(spans, SpanKind.CLIENT, "0000000000000000");
assertEquals("GET", clientSpan.getName());
assertEquals("GET /hello", clientSpan.getName());

// There is a parent id, therefore propagation is working.
SpanData serverSpan = getSpanByKindAndParentId(spans, SpanKind.SERVER, clientSpan.getSpanId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void client() {
List<SpanData> spans = spanExporter.getFinishedSpanItems(2);

SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000");
assertEquals("GET", client.getName());
assertEquals("GET /hello", client.getName());
assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE);
assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD);
assertSemanticAttribute(client, uri.toString() + "hello", HTTP_URL);
Expand All @@ -96,7 +96,7 @@ void spanNameWithoutQueryString() {

SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000");
assertEquals(CLIENT, client.getKind());
assertEquals("GET", client.getName());
assertEquals("GET /hello", client.getName());
assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE);
assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD);
assertSemanticAttribute(client, uri.toString() + "hello?query=1", HTTP_URL);
Expand Down Expand Up @@ -132,7 +132,7 @@ void path() {

SpanData client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000");
assertEquals(CLIENT, client.getKind());
assertEquals("GET", client.getName());
assertEquals("GET /hello/{path}", client.getName());
assertSemanticAttribute(client, (long) HTTP_OK, HTTP_STATUS_CODE);
assertSemanticAttribute(client, HttpMethod.GET, HTTP_METHOD);
assertSemanticAttribute(client, uri.toString() + "hello/another", HTTP_URL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.context.propagation.TextMapSetter;
Expand All @@ -41,6 +42,7 @@ public class OpenTelemetryClientFilter implements ClientRequestFilter, ClientRes
public static final String REST_CLIENT_OTEL_SPAN_CLIENT_CONTEXT = "otel.span.client.context";
public static final String REST_CLIENT_OTEL_SPAN_CLIENT_PARENT_CONTEXT = "otel.span.client.parentContext";
public static final String REST_CLIENT_OTEL_SPAN_CLIENT_SCOPE = "otel.span.client.scope";
private static final String URL_PATH_TEMPLATE_KEY = "UrlPathTemplate";

/**
* Property stored in the Client Request context to retrieve the captured Vert.x context.
Expand Down Expand Up @@ -118,6 +120,11 @@ public void filter(final ClientRequestContext request, final ClientResponseConte

Context spanContext = (Context) request.getProperty(REST_CLIENT_OTEL_SPAN_CLIENT_CONTEXT);
try {
String pathTemplate = (String) request.getProperty(URL_PATH_TEMPLATE_KEY);
if (pathTemplate != null && !pathTemplate.isEmpty()) {
Span.fromContext(spanContext)
.updateName(request.getMethod() + " " + pathTemplate);
}
instrumenter.end(spanContext, request, response, null);
} finally {
scope.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.netty.handler.codec.http.HttpResponseStatus;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapSetter;
Expand All @@ -30,6 +31,7 @@
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
import io.opentelemetry.semconv.SemanticAttributes;
import io.quarkus.opentelemetry.runtime.config.runtime.SemconvStabilityType;
import io.smallrye.common.vertx.VertxContext;
import io.vertx.core.Context;
import io.vertx.core.MultiMap;
import io.vertx.core.http.HttpHeaders;
Expand All @@ -42,7 +44,9 @@
import io.vertx.core.net.SocketAddress;
import io.vertx.core.spi.observability.HttpRequest;
import io.vertx.core.spi.observability.HttpResponse;
import io.vertx.core.spi.tracing.SpanKind;
import io.vertx.core.spi.tracing.TagExtractor;
import io.vertx.core.tracing.TracingPolicy;

public class HttpInstrumenterVertxTracer implements InstrumenterVertxTracer<HttpRequest, HttpResponse> {
private final Instrumenter<HttpRequest, HttpResponse> serverInstrumenter;
Expand Down Expand Up @@ -102,6 +106,31 @@ public <R> void sendResponse(
InstrumenterVertxTracer.super.sendResponse(context, response, spanOperation, failure, tagExtractor);
}

@Override
public <R> OpenTelemetryVertxTracer.SpanOperation sendRequest(Context context,
SpanKind kind,
TracingPolicy policy,
R request,
String operation,
BiConsumer<String, String> headers,
TagExtractor<R> tagExtractor) {
OpenTelemetryVertxTracer.SpanOperation spanOperation = InstrumenterVertxTracer.super.sendRequest(context, kind, policy,
request,
operation, headers, tagExtractor);
if (spanOperation != null) {
Context runningCtx = spanOperation.getContext();
if (VertxContext.isDuplicatedContext(runningCtx)) {
String pathTemplate = runningCtx.getLocal("ClientUrlPathTemplate");
if (pathTemplate != null && !pathTemplate.isEmpty()) {
Span.fromContext(spanOperation.getSpanContext())
.updateName(((HttpRequest) spanOperation.getRequest()).method().name() + " " + pathTemplate);
}
}
}

return spanOperation;
}

@Override
public HttpRequest writableHeaders(
final HttpRequest request, final BiConsumer<String, String> headers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ public ClientObservabilityHandler(String templatePath) {
@Override
public void handle(RestClientRequestContext requestContext) throws Exception {
requestContext.getClientFilterProperties().put("UrlPathTemplate", templatePath);
requestContext.getOrCreateClientRequestContext().getContext().putLocal("ClientUrlPathTemplate", templatePath);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void get() {
// First span is the client call. It does not have a parent span.
Map<String, Object> client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000");
assertEquals(SpanKind.CLIENT.toString(), client.get("kind"));
assertEquals("GET", client.get("name"));
assertEquals("GET /reactive", client.get("name"));
assertEquals(HTTP_OK, ((Map<?, ?>) client.get("attributes")).get(HTTP_STATUS_CODE.getKey()));
assertEquals(HttpMethod.GET.name(), ((Map<?, ?>) client.get("attributes")).get(HTTP_METHOD.getKey()));

Expand Down Expand Up @@ -92,7 +92,7 @@ void post() {
// First span is the client call. It does not have a parent span.
Map<String, Object> client = getSpanByKindAndParentId(spans, CLIENT, "0000000000000000");
assertEquals(SpanKind.CLIENT.toString(), client.get("kind"));
assertEquals("POST", client.get("name"));
assertEquals("POST /reactive", client.get("name"));
assertEquals(HTTP_OK, ((Map<?, ?>) client.get("attributes")).get(HTTP_STATUS_CODE.getKey()));
assertEquals(HttpMethod.POST.name(), ((Map<?, ?>) client.get("attributes")).get(HTTP_METHOD.getKey()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void testGeneratedSpansUsingRestClientReactive() {

// We should get one client span, from the internal method.
Map<String, Object> server = getSpanByKindAndParentId(spans, CLIENT, client.get("spanId"));
assertEquals("GET", server.get("name"));
assertEquals("GET /stub", server.get("name"));
}

@Startup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ void testEmptyClientPath() {
Map<String, Object> client = getSpanByKindAndParentId(spans, CLIENT, server.get("spanId"));
assertEquals(CLIENT.toString(), client.get("kind"));
verifyResource(client);
assertEquals("GET", client.get("name"));
assertEquals("GET /", client.get("name"));
assertEquals(SpanKind.CLIENT.toString(), client.get("kind"));
assertTrue((Boolean) client.get("ended"));
assertTrue((Boolean) client.get("parent_valid"));
Expand Down Expand Up @@ -206,7 +206,7 @@ void testSlashClientPath() {

Map<String, Object> client = getSpanByKindAndParentId(spans, CLIENT, server.get("spanId"));
assertEquals(CLIENT.toString(), client.get("kind"));
assertEquals("GET", client.get("name"));
assertEquals("GET /", client.get("name"));
assertEquals(SpanKind.CLIENT.toString(), client.get("kind"));
assertTrue((Boolean) client.get("ended"));
assertTrue((Boolean) client.get("parent_valid"));
Expand Down Expand Up @@ -261,7 +261,7 @@ void testBaggagePath() {

Map<String, Object> client = getSpanByKindAndParentId(spans, CLIENT, server.get("spanId"));
assertEquals(CLIENT.toString(), client.get("kind"));
assertEquals("GET", client.get("name"));
assertEquals("GET /from-baggage", client.get("name"));
assertEquals("http://localhost:8081/from-baggage", client.get("attr_http.url"));
assertEquals("200", client.get("attr_http.status_code"));
assertEquals(client.get("parentSpanId"), server.get("spanId"));
Expand Down Expand Up @@ -467,7 +467,7 @@ void testClientTracing() {
assertNotNull(server.get("attr_user_agent.original"));

Map<String, Object> client = getSpanByKindAndParentId(spans, CLIENT, server.get("spanId"));
assertEquals("GET", client.get("name"));
assertEquals("GET /client/pong/{message}", client.get("name"));
assertEquals(SpanKind.CLIENT.toString(), client.get("kind"));
assertTrue((Boolean) client.get("ended"));
assertTrue((Boolean) client.get("parent_valid"));
Expand Down Expand Up @@ -530,7 +530,7 @@ void testAsyncClientTracing() {
assertNotNull(server.get("attr_user_agent.original"));

Map<String, Object> client = getSpanByKindAndParentId(spans, CLIENT, server.get("spanId"));
assertEquals("GET", client.get("name"));
assertEquals("GET /client/pong/{message}", client.get("name"));
assertEquals(SpanKind.CLIENT.toString(), client.get("kind"));
assertTrue((Boolean) client.get("ended"));
assertTrue((Boolean) client.get("parent_valid"));
Expand Down Expand Up @@ -602,7 +602,7 @@ void testClientTracingWithInterceptor() {
assertEquals("one", fromInterceptor.get("attr_message"));

Map<String, Object> client = getSpanByKindAndParentId(spans, CLIENT, fromInterceptor.get("spanId"));
assertEquals("GET", client.get("name"));
assertEquals("GET /client/pong/{message}", client.get("name"));
assertEquals(SpanKind.CLIENT.toString(), client.get("kind"));
assertTrue((Boolean) client.get("ended"));
assertTrue((Boolean) client.get("parent_valid"));
Expand Down
Loading