16
16
17
17
package io .opentelemetry .instrumentation .hypertrace .servlet .v3_1 ;
18
18
19
- import static io .opentelemetry .javaagent .instrumentation .servlet .v3_0 .Servlet3HttpServerTracer .TRACER ;
20
19
import static io .opentelemetry .javaagent .tooling .ClassLoaderMatcher .hasClassesNamed ;
21
20
import static io .opentelemetry .javaagent .tooling .bytebuddy .matcher .AgentElementMatchers .safeHasSuperType ;
22
21
import static io .opentelemetry .javaagent .tooling .matcher .NameMatchers .namedOneOf ;
26
25
import static net .bytebuddy .matcher .ElementMatchers .takesArgument ;
27
26
28
27
import com .google .auto .service .AutoService ;
29
- import io .opentelemetry .instrumentation .hypertrace .servlet .common .ServletSpanDecorator ;
30
28
import io .opentelemetry .javaagent .tooling .Instrumenter ;
31
- import io .opentelemetry .trace .Span ;
32
- import java .util .Enumeration ;
33
- import java .util .HashMap ;
34
29
import 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 ;
41
30
import net .bytebuddy .description .method .MethodDescription ;
42
31
import net .bytebuddy .description .type .TypeDescription ;
43
32
import 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 ;
48
33
49
34
/**
50
35
* TODO https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/1395 is resolved
@@ -105,6 +90,7 @@ public String[] helperClassNames() {
105
90
packageName + ".BufferingHttpServletRequest" ,
106
91
packageName + ".BufferingHttpServletRequest$ServletInputStreamWrapper" ,
107
92
packageName + ".BodyCaptureAsyncListener" ,
93
+ packageName + ".Servlet31Advice" ,
108
94
};
109
95
}
110
96
@@ -115,112 +101,6 @@ public Map<? extends ElementMatcher<? super MethodDescription>, String> transfor
115
101
.and (takesArgument (0 , named ("javax.servlet.ServletRequest" )))
116
102
.and (takesArgument (1 , named ("javax.servlet.ServletResponse" )))
117
103
.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 ());
225
105
}
226
106
}
0 commit comments