1
1
package io .dropwizard .metrics .jetty12 .ee10 ;
2
2
3
+ import com .codahale .metrics .Meter ;
3
4
import com .codahale .metrics .MetricRegistry ;
4
5
import com .codahale .metrics .annotation .ResponseMeteredLevel ;
5
6
import io .dropwizard .metrics .jetty12 .AbstractInstrumentedHandler ;
6
7
import jakarta .servlet .AsyncEvent ;
7
8
import jakarta .servlet .AsyncListener ;
8
- import org .eclipse .jetty .ee10 .servlet .AsyncContextState ;
9
+ import jakarta .servlet .ServletRequest ;
10
+ import jakarta .servlet .ServletRequestEvent ;
11
+ import jakarta .servlet .ServletRequestListener ;
9
12
import org .eclipse .jetty .ee10 .servlet .ServletApiRequest ;
10
- import org .eclipse .jetty .ee10 .servlet .ServletApiResponse ;
11
13
import org .eclipse .jetty .ee10 .servlet .ServletChannelState ;
14
+ import org .eclipse .jetty .ee10 .servlet .ServletContextHandler ;
12
15
import org .eclipse .jetty .ee10 .servlet .ServletContextRequest ;
13
16
import org .eclipse .jetty .server .Handler ;
14
17
import org .eclipse .jetty .server .Request ;
15
18
import org .eclipse .jetty .server .Response ;
16
- import org .eclipse .jetty .util .Callback ;
17
19
18
20
import java .io .IOException ;
19
- import java .util .concurrent .TimeUnit ;
20
-
21
- import static com .codahale .metrics .annotation .ResponseMeteredLevel .COARSE ;
22
21
23
22
/**
24
23
* A Jetty {@link Handler} which records various metrics about an underlying {@link Handler}
28
27
* {@link org.eclipse.jetty.ee10.servlet.ServletContextHandler#insertHandler(Singleton)}.
29
28
*/
30
29
public class InstrumentedEE10Handler extends AbstractInstrumentedHandler {
31
- private AsyncListener listener ;
30
+ private AsyncDispatchesAwareServletRequestListener asyncDispatchesAwareServletRequestListener ;
32
31
33
32
/**
34
33
* Create a new instrumented handler using a given metrics registry.
35
34
*
36
35
* @param registry the registry for the metrics
37
36
*/
38
37
public InstrumentedEE10Handler (MetricRegistry registry ) {
39
- super (registry , null );
38
+ super (registry );
40
39
}
41
40
42
41
/**
@@ -46,7 +45,7 @@ public InstrumentedEE10Handler(MetricRegistry registry) {
46
45
* @param prefix the prefix to use for the metrics names
47
46
*/
48
47
public InstrumentedEE10Handler (MetricRegistry registry , String prefix ) {
49
- super (registry , prefix , COARSE );
48
+ super (registry , prefix );
50
49
}
51
50
52
51
/**
@@ -63,8 +62,7 @@ public InstrumentedEE10Handler(MetricRegistry registry, String prefix, ResponseM
63
62
@ Override
64
63
protected void doStart () throws Exception {
65
64
super .doStart ();
66
-
67
- this .listener = new AsyncAttachingListener ();
65
+ asyncDispatchesAwareServletRequestListener = new AsyncDispatchesAwareServletRequestListener (getAsyncDispatches ());
68
66
}
69
67
70
68
@ Override
@@ -73,104 +71,84 @@ protected void doStop() throws Exception {
73
71
}
74
72
75
73
@ Override
76
- public boolean handle (Request request , Response response , Callback callback ) throws Exception {
74
+ protected void setupServletListeners (Request request , Response response ) {
77
75
ServletContextRequest servletContextRequest = Request .as (request , ServletContextRequest .class );
78
-
79
- // only handle servlet requests with the InstrumentedHandler
80
- // because it depends on the ServletRequestState
81
76
if (servletContextRequest == null ) {
82
- return super .handle (request , response , callback );
83
- }
84
-
85
- activeDispatches .inc ();
86
-
87
- final long start ;
88
- final ServletChannelState state = servletContextRequest .getServletRequestState ();
89
- if (state .isInitial ()) {
90
- // new request
91
- activeRequests .inc ();
92
- start = Request .getTimeStamp (request );
93
- state .addListener (listener );
94
- } else {
95
- // resumed request
96
- start = System .currentTimeMillis ();
97
- activeSuspended .dec ();
98
- if (state .getState () == ServletChannelState .State .HANDLING ) {
99
- asyncDispatches .mark ();
100
- }
77
+ return ;
101
78
}
102
79
103
- boolean handled = false ;
80
+ ServletChannelState servletChannelState = servletContextRequest .getServletRequestState ();
81
+ // the ServletChannelState gets recycled after handling, so add a new listener for every request
82
+ servletChannelState .addListener (new InstrumentedAsyncListener (getAsyncTimeouts ()));
104
83
105
- try {
106
- handled = super .handle (request , response , callback );
107
- } finally {
108
- final long now = System .currentTimeMillis ();
109
- final long dispatched = now - start ;
84
+ ServletContextHandler servletContextHandler = servletContextRequest .getServletContextHandler ();
85
+ // addEventListener checks for duplicates, so we can try to add the listener for every request
86
+ servletContextHandler .addEventListener (asyncDispatchesAwareServletRequestListener );
87
+ }
110
88
111
- activeDispatches .dec ();
112
- dispatches .update (dispatched , TimeUnit .MILLISECONDS );
89
+ @ Override
90
+ protected boolean isSuspended (Request request , Response response ) {
91
+ ServletContextRequest servletContextRequest = Request .as (request , ServletContextRequest .class );
92
+ if (servletContextRequest == null ) {
93
+ return false ;
94
+ }
113
95
114
- if (state .isSuspended ()) {
115
- activeSuspended .inc ();
116
- } else if (state .isInitial ()) {
117
- updateResponses (request , response , start , handled );
118
- }
119
- // else onCompletion will handle it.
96
+ ServletChannelState servletChannelState = servletContextRequest .getServletRequestState ();
97
+ if (servletChannelState == null ) {
98
+ return false ;
120
99
}
121
100
122
- return handled ;
101
+ return servletChannelState . isSuspended () ;
123
102
}
124
103
125
- private class AsyncAttachingListener implements AsyncListener {
126
-
127
- @ Override
128
- public void onTimeout (AsyncEvent event ) throws IOException {}
104
+ private static class AsyncDispatchesAwareServletRequestListener implements ServletRequestListener {
105
+ private final Meter asyncDispatches ;
129
106
130
- @ Override
131
- public void onStartAsync (AsyncEvent event ) throws IOException {
132
- event .getAsyncContext ().addListener (new InstrumentedAsyncListener ());
107
+ private AsyncDispatchesAwareServletRequestListener (Meter asyncDispatches ) {
108
+ this .asyncDispatches = asyncDispatches ;
133
109
}
134
110
135
111
@ Override
136
- public void onError (AsyncEvent event ) throws IOException {}
112
+ public void requestInitialized (ServletRequestEvent sre ) {
113
+ ServletRequest servletRequest = sre .getServletRequest ();
114
+ if (!(servletRequest instanceof ServletApiRequest )) {
115
+ return ;
116
+ }
137
117
138
- @ Override
139
- public void onComplete (AsyncEvent event ) throws IOException {}
118
+ ServletApiRequest servletApiRequest = (ServletApiRequest ) servletRequest ;
119
+
120
+ ServletContextHandler .ServletRequestInfo servletRequestInfo = servletApiRequest .getServletRequestInfo ();
121
+
122
+ ServletChannelState servletChannelState = servletRequestInfo .getServletRequestState ();
123
+
124
+ // if the request isn't 'initial', the request was re-dispatched
125
+ if (servletChannelState .isAsync () && !servletChannelState .isInitial ()) {
126
+ asyncDispatches .mark ();
127
+ }
128
+ }
140
129
}
141
130
142
- private class InstrumentedAsyncListener implements AsyncListener {
143
- private final long startTime ;
131
+ private static class InstrumentedAsyncListener implements AsyncListener {
132
+ private final Meter asyncTimeouts ;
144
133
145
- InstrumentedAsyncListener () {
146
- this .startTime = System . currentTimeMillis () ;
134
+ private InstrumentedAsyncListener (Meter asyncTimeouts ) {
135
+ this .asyncTimeouts = asyncTimeouts ;
147
136
}
148
137
149
138
@ Override
150
- public void onTimeout (AsyncEvent event ) throws IOException {
151
- asyncTimeouts .mark ();
152
- }
139
+ public void onComplete (AsyncEvent event ) throws IOException {}
153
140
154
141
@ Override
155
- public void onStartAsync (AsyncEvent event ) throws IOException {
142
+ public void onTimeout (AsyncEvent event ) throws IOException {
143
+ asyncTimeouts .mark ();
156
144
}
157
145
158
146
@ Override
159
- public void onError (AsyncEvent event ) throws IOException {
160
- }
147
+ public void onError (AsyncEvent event ) throws IOException {}
161
148
162
149
@ Override
163
- public void onComplete (AsyncEvent event ) throws IOException {
164
- final AsyncContextState state = (AsyncContextState ) event .getAsyncContext ();
165
- final ServletApiRequest request = (ServletApiRequest ) state .getRequest ();
166
- final ServletApiResponse response = (ServletApiResponse ) state .getResponse ();
167
- updateResponses (request .getRequest (), response .getResponse (), startTime , true );
168
-
169
- final ServletContextRequest servletContextRequest = Request .as (request .getRequest (), ServletContextRequest .class );
170
- final ServletChannelState servletRequestState = servletContextRequest .getServletRequestState ();
171
- if (!servletRequestState .isSuspended ()) {
172
- activeSuspended .dec ();
173
- }
150
+ public void onStartAsync (AsyncEvent event ) throws IOException {
151
+ event .getAsyncContext ().addListener (this );
174
152
}
175
153
}
176
154
}
0 commit comments