open-telemetry / open-telemetry/opentelemetry-java-instrumentation
Support for (auto) instrumentation for Spring Cloud Gateway MVC routes
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 2.6k
- Forks
- 1.2k
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 228
Description
Is your feature request related to a problem? Please describe.
Currently, it looks like "only" the reactive variant of Spring Cloud Gateway is natively supported by OpenTelemetry starter. In a recent project, we decided to go with the MVC variant, as in the advent of virtual threads, reactive approach was ruled out due to the complexities it introduces.
I was able to work around this by implementing a custom HandlerInterceptor:
package eu.eliagroup.gras.iam.gatekeeper.service.core.opentelemetry;
import static java.lang.String.format;
import static java.util.Optional.ofNullable;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import jakarta.annotation.Nonnull;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.val;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
/// The interceptor sets up the trace context for any given route.
///
/// It relies on the W3C Trace Context Propagator to extract the trace context from the request
/// headers.
///
/// After request completion, the trace- and span IDs get removed from the MDC.
@Component
@Order(HIGHEST_PRECEDENCE)
final class TraceContextInterceptor implements HandlerInterceptor {
private static final String TRACE_ID = "trace_id";
private static final String SPAN_ID = "span_id";
@Override
public boolean preHandle(
@Nonnull final HttpServletRequest request,
@Nonnull final HttpServletResponse response,
@Nonnull final Object handler) {
val extractedContext =
W3CTraceContextPropagator.getInstance()
.extract(Context.current(), request, new HeaderExtractor());
try (final var ignored = extractedContext.makeCurrent()) {
val currentSpan = Span.current();
currentSpan.updateName(
format("%s %s", request.getMethod().toUpperCase(), request.getRequestURI()));
final var spanContext = currentSpan.getSpanContext();
if (spanContext.isValid()) {
MDC.put(TRACE_ID, spanContext.getTraceId());
MDC.put(SPAN_ID, spanContext.getSpanId());
}
}
return true;
}
@Override
public void afterCompletion(
@Nonnull final HttpServletRequest request,
@Nonnull final HttpServletResponse response,
@Nonnull final Object handler,
final Exception ex) {
MDC.remove(TRACE_ID);
MDC.remove(SPAN_ID);
}
private static final class HeaderExtractor implements TextMapGetter<HttpServletRequest> {
@Override
public Iterable<String> keys(final HttpServletRequest carrier) {
return () -> carrier.getHeaderNames().asIterator();
}
@Override
public String get(final HttpServletRequest carrier, final String headerName) {
return ofNullable(carrier).map(c -> c.getHeader(headerName)).orElse(null);
}
}
}
TBH - the feature is not of high priority, yet I think it would be a nice addition.
Describe the solution you'd like
It would be nice if the starter instruments Gateway MVC routes automagically.
Describe alternatives you've considered
None.
Additional context
None.
Tip
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by comparing the starter's existing reactive Spring Cloud Gateway instrumentation with the MVC Gateway route handling, then inspect the relevant instrumentation entry points and tests. Done means MVC routes are automatically instrumented with trace context and route details, with coverage for the supported behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend, observability
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100