1616
1717package io .opentelemetry .instrumentation .hypertrace .servlet .v3_1 ;
1818
19- import static io .opentelemetry .javaagent .instrumentation .servlet .v3_0 .Servlet3HttpServerTracer .TRACER ;
2019import static io .opentelemetry .javaagent .tooling .ClassLoaderMatcher .hasClassesNamed ;
2120import static io .opentelemetry .javaagent .tooling .bytebuddy .matcher .AgentElementMatchers .safeHasSuperType ;
2221import static io .opentelemetry .javaagent .tooling .matcher .NameMatchers .namedOneOf ;
2625import static net .bytebuddy .matcher .ElementMatchers .takesArgument ;
2726
2827import com .google .auto .service .AutoService ;
29- import io .opentelemetry .instrumentation .hypertrace .servlet .common .ServletSpanDecorator ;
3028import io .opentelemetry .javaagent .tooling .Instrumenter ;
31- import io .opentelemetry .trace .Span ;
32- import java .util .Enumeration ;
33- import java .util .HashMap ;
3429import java .util .Map ;
35- import java .util .concurrent .atomic .AtomicBoolean ;
36- import javax .servlet .ServletRequest ;
37- import javax .servlet .ServletResponse ;
38- import javax .servlet .http .HttpServletRequest ;
39- import javax .servlet .http .HttpServletResponse ;
40- import net .bytebuddy .asm .Advice ;
4130import net .bytebuddy .description .method .MethodDescription ;
4231import net .bytebuddy .description .type .TypeDescription ;
4332import net .bytebuddy .matcher .ElementMatcher ;
44- import org .hypertrace .agent .blocking .BlockingProvider ;
45- import org .hypertrace .agent .blocking .BlockingResult ;
46- import org .hypertrace .agent .core .DynamicConfig ;
47- import org .hypertrace .agent .core .HypertraceSemanticAttributes ;
4833
4934/**
5035 * TODO https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/1395 is resolved
@@ -105,6 +90,7 @@ public String[] helperClassNames() {
10590 packageName + ".BufferingHttpServletRequest" ,
10691 packageName + ".BufferingHttpServletRequest$ServletInputStreamWrapper" ,
10792 packageName + ".BodyCaptureAsyncListener" ,
93+ packageName + ".Servlet31Advice" ,
10894 };
10995 }
11096
@@ -115,112 +101,6 @@ public Map<? extends ElementMatcher<? super MethodDescription>, String> transfor
115101 .and (takesArgument (0 , named ("javax.servlet.ServletRequest" )))
116102 .and (takesArgument (1 , named ("javax.servlet.ServletResponse" )))
117103 .and (isPublic ()),
118- FilterAdvice .class .getName ());
119- }
120-
121- public static class FilterAdvice {
122- // request attribute key injected at first filerChain.doFilter
123- private static final String ALREADY_LOADED = "__org.hypertrace.agent.on_start_executed" ;
124-
125- @ Advice .OnMethodEnter (suppress = Throwable .class , skipOn = BlockingResult .class )
126- public static Object start (
127- @ Advice .Argument (value = 0 , readOnly = false ) ServletRequest request ,
128- @ Advice .Argument (value = 1 , readOnly = false ) ServletResponse response ,
129- @ Advice .Local ("rootStart" ) Boolean rootStart ) {
130- if (!(request instanceof HttpServletRequest ) || !(response instanceof HttpServletResponse )) {
131- return null ;
132- }
133-
134- if (!DynamicConfig .isEnabled (InstrumentationName .INSTRUMENTATION_NAME )) {
135- return null ;
136- }
137-
138- // TODO run on every doFilter and check if user removed wrapper
139- // TODO what if user unwraps request and reads the body?
140-
141- // run the instrumentation only for the root FilterChain.doFilter()
142- if (request .getAttribute (ALREADY_LOADED ) != null ) {
143- return null ;
144- }
145- request .setAttribute (ALREADY_LOADED , true );
146-
147- HttpServletRequest httpRequest = (HttpServletRequest ) request ;
148- HttpServletResponse httpResponse = (HttpServletResponse ) response ;
149- Span currentSpan = TRACER .getCurrentSpan ();
150-
151- rootStart = true ;
152- response = new BufferingHttpServletResponse (httpResponse );
153- request = new BufferingHttpServletRequest (httpRequest , (HttpServletResponse ) response );
154-
155- ServletSpanDecorator .addSessionId (currentSpan , httpRequest );
156-
157- // set request headers
158- Enumeration <String > headerNames = httpRequest .getHeaderNames ();
159- Map <String , String > headers = new HashMap <>();
160- while (headerNames .hasMoreElements ()) {
161- String headerName = headerNames .nextElement ();
162- String headerValue = httpRequest .getHeader (headerName );
163- currentSpan .setAttribute (
164- HypertraceSemanticAttributes .httpRequestHeader (headerName ), headerValue );
165- headers .put (headerName , headerValue );
166- }
167- BlockingResult blockingResult = BlockingProvider .getBlockingEvaluator ().evaluate (headers );
168- currentSpan .setAttribute (
169- HypertraceSemanticAttributes .OPA_RESULT , blockingResult .blockExecution ());
170- if (blockingResult .blockExecution ()) {
171- httpResponse .setStatus (403 );
172- currentSpan .setAttribute (
173- HypertraceSemanticAttributes .OPA_REASON , blockingResult .getReason ());
174- return blockingResult ;
175- }
176- return null ;
177- }
178-
179- @ Advice .OnMethodExit (onThrowable = Throwable .class , suppress = Throwable .class )
180- public static void stopSpan (
181- @ Advice .Argument (0 ) ServletRequest request ,
182- @ Advice .Argument (1 ) ServletResponse response ,
183- @ Advice .Local ("rootStart" ) Boolean rootStart ) {
184- if (rootStart != null ) {
185- if (!(request instanceof BufferingHttpServletRequest )
186- || !(response instanceof BufferingHttpServletResponse )) {
187- return ;
188- }
189-
190- request .removeAttribute (ALREADY_LOADED );
191- Span currentSpan = TRACER .getCurrentSpan ();
192-
193- AtomicBoolean responseHandled = new AtomicBoolean (false );
194- if (request .isAsyncStarted ()) {
195- try {
196- request
197- .getAsyncContext ()
198- .addListener (new BodyCaptureAsyncListener (responseHandled , currentSpan ));
199- } catch (IllegalStateException e ) {
200- // org.eclipse.jetty.server.Request may throw an exception here if request became
201- // finished after check above. We just ignore that exception and move on.
202- }
203- }
204-
205- if (!request .isAsyncStarted () && responseHandled .compareAndSet (false , true )) {
206- BufferingHttpServletResponse bufferingResponse = (BufferingHttpServletResponse ) response ;
207- BufferingHttpServletRequest bufferingRequest = (BufferingHttpServletRequest ) request ;
208-
209- // set response headers
210- for (String headerName : bufferingResponse .getHeaderNames ()) {
211- String headerValue = bufferingResponse .getHeader (headerName );
212- currentSpan .setAttribute (
213- HypertraceSemanticAttributes .httpResponseHeader (headerName ), headerValue );
214- }
215- // Bodies are captured at the end after all user processing.
216- currentSpan .setAttribute (
217- HypertraceSemanticAttributes .HTTP_REQUEST_BODY ,
218- bufferingRequest .getBufferedBodyAsString ());
219- currentSpan .setAttribute (
220- HypertraceSemanticAttributes .HTTP_RESPONSE_BODY ,
221- bufferingResponse .getBufferAsString ());
222- }
223- }
224- }
104+ Servlet31Advice .class .getName ());
225105 }
226106}
0 commit comments