|
1 | 1 | package datadog.trace.instrumentation.play26; |
2 | 2 |
|
| 3 | +import static datadog.trace.api.gateway.Events.EVENTS; |
3 | 4 | import static datadog.trace.bootstrap.instrumentation.decorator.http.HttpResourceDecorator.HTTP_RESOURCE_DECORATOR; |
4 | 5 |
|
5 | 6 | import datadog.trace.api.Config; |
6 | 7 | import datadog.trace.api.cache.DDCache; |
7 | 8 | import datadog.trace.api.cache.DDCaches; |
| 9 | +import datadog.trace.api.gateway.CallbackProvider; |
| 10 | +import datadog.trace.api.gateway.RequestContext; |
| 11 | +import datadog.trace.api.gateway.RequestContextSlot; |
8 | 12 | import datadog.trace.bootstrap.instrumentation.api.AgentPropagation; |
9 | 13 | import datadog.trace.bootstrap.instrumentation.api.AgentSpan; |
10 | 14 | import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; |
11 | 15 | import datadog.trace.bootstrap.instrumentation.api.ResourceNamePriorities; |
12 | 16 | import datadog.trace.bootstrap.instrumentation.api.URIDataAdapter; |
| 17 | +import datadog.trace.bootstrap.instrumentation.api.URIUtils; |
13 | 18 | import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; |
14 | 19 | import datadog.trace.bootstrap.instrumentation.decorator.HttpServerDecorator; |
15 | 20 | import java.lang.invoke.MethodHandle; |
|
18 | 23 | import java.lang.reflect.InvocationTargetException; |
19 | 24 | import java.lang.reflect.UndeclaredThrowableException; |
20 | 25 | import java.util.concurrent.CompletionException; |
| 26 | +import java.util.function.BiConsumer; |
| 27 | +import org.slf4j.Logger; |
| 28 | +import org.slf4j.LoggerFactory; |
21 | 29 | import play.api.mvc.Headers; |
22 | 30 | import play.api.mvc.Request; |
23 | 31 | import play.api.mvc.Result; |
|
29 | 37 |
|
30 | 38 | public class PlayHttpServerDecorator |
31 | 39 | extends HttpServerDecorator<Request, Request, Result, Headers> { |
| 40 | + private static final Logger LOG = LoggerFactory.getLogger(PlayHttpServerDecorator.class); |
32 | 41 | public static final boolean REPORT_HTTP_STATUS = Config.get().getPlayReportHttpStatus(); |
33 | 42 | public static final CharSequence PLAY_REQUEST = UTF8BytesString.create("play.request"); |
34 | 43 | public static final CharSequence PLAY_ACTION = UTF8BytesString.create("play-action"); |
@@ -143,11 +152,35 @@ public AgentSpan onRequest( |
143 | 152 | PATH_CACHE.computeIfAbsent( |
144 | 153 | defOption.get().path(), p -> addMissingSlash(p, request.path())); |
145 | 154 | HTTP_RESOURCE_DECORATOR.withRoute(span, request.method(), path, true); |
| 155 | + dispatchRoute(span, path); |
146 | 156 | } |
147 | 157 | } |
148 | 158 | return span; |
149 | 159 | } |
150 | 160 |
|
| 161 | + /** |
| 162 | + * Play does not set the http.route in the local root span so we need to store it in the context |
| 163 | + * for API security |
| 164 | + */ |
| 165 | + private void dispatchRoute(final AgentSpan span, final CharSequence route) { |
| 166 | + try { |
| 167 | + final RequestContext ctx = span.getRequestContext(); |
| 168 | + if (ctx == null) { |
| 169 | + return; |
| 170 | + } |
| 171 | + final CallbackProvider cbp = tracer().getCallbackProvider(RequestContextSlot.APPSEC); |
| 172 | + if (cbp == null) { |
| 173 | + return; |
| 174 | + } |
| 175 | + final BiConsumer<RequestContext, String> cb = cbp.getCallback(EVENTS.httpRoute()); |
| 176 | + if (cb != null) { |
| 177 | + cb.accept(ctx, URIUtils.decode(route.toString())); |
| 178 | + } |
| 179 | + } catch (final Throwable t) { |
| 180 | + LOG.debug("Failed to dispatch route", t); |
| 181 | + } |
| 182 | + } |
| 183 | + |
151 | 184 | /* |
152 | 185 | This is a workaround to add a `/` if it is missing when using split routes. |
153 | 186 |
|
|
0 commit comments