1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.server;
20
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.io.PrintStream;
24 import java.util.Locale;
25
26 import javax.servlet.AsyncEvent;
27 import javax.servlet.AsyncListener;
28 import javax.servlet.DispatcherType;
29 import javax.servlet.ServletContext;
30 import javax.servlet.ServletContextEvent;
31 import javax.servlet.ServletContextListener;
32 import javax.servlet.ServletRequest;
33 import javax.servlet.ServletRequestEvent;
34 import javax.servlet.ServletRequestListener;
35 import javax.servlet.http.HttpServletRequest;
36 import javax.servlet.http.HttpServletResponse;
37
38 import org.eclipse.jetty.server.handler.ContextHandler;
39 import org.eclipse.jetty.server.handler.ContextHandler.Context;
40 import org.eclipse.jetty.server.handler.ContextHandler.ContextScopeListener;
41 import org.eclipse.jetty.util.DateCache;
42 import org.eclipse.jetty.util.annotation.ManagedAttribute;
43 import org.eclipse.jetty.util.annotation.ManagedObject;
44 import org.eclipse.jetty.util.annotation.Name;
45 import org.eclipse.jetty.util.component.AbstractLifeCycle;
46 import org.eclipse.jetty.util.log.Log;
47 import org.eclipse.jetty.util.log.Logger;
48
49
50
51
52
53
54
55
56 @ManagedObject("Debug Listener")
57 public class DebugListener extends AbstractLifeCycle implements ServletContextListener
58 {
59 private static final Logger LOG = Log.getLogger(DebugListener.class);
60 private static final DateCache __date=new DateCache("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
61
62 private final String _attr = String.format("__R%s@%x",this.getClass().getSimpleName(),System.identityHashCode(this));
63
64 private final PrintStream _out;
65 private boolean _renameThread;
66 private boolean _showHeaders;
67 private boolean _dumpContext;
68
69 public DebugListener()
70 {
71 this(null,false,false,false);
72 }
73
74 public DebugListener(@Name("renameThread") boolean renameThread, @Name("showHeaders") boolean showHeaders, @Name("dumpContext") boolean dumpContext)
75 {
76 this(null,renameThread,showHeaders,dumpContext);
77 }
78
79 public DebugListener(@Name("outputStream") OutputStream out, @Name("renameThread") boolean renameThread, @Name("showHeaders") boolean showHeaders, @Name("dumpContext") boolean dumpContext)
80 {
81 _out=out==null?null:new PrintStream(out);
82 _renameThread=renameThread;
83 _showHeaders=showHeaders;
84 _dumpContext=dumpContext;
85 }
86
87 @ManagedAttribute("Rename thread within context scope")
88 public boolean isRenameThread()
89 {
90 return _renameThread;
91 }
92
93 public void setRenameThread(boolean renameThread)
94 {
95 _renameThread = renameThread;
96 }
97
98 @ManagedAttribute("Show request headers")
99 public boolean isShowHeaders()
100 {
101 return _showHeaders;
102 }
103
104 public void setShowHeaders(boolean showHeaders)
105 {
106 _showHeaders = showHeaders;
107 }
108
109 @ManagedAttribute("Dump contexts at start")
110 public boolean isDumpContext()
111 {
112 return _dumpContext;
113 }
114
115 public void setDumpContext(boolean dumpContext)
116 {
117 _dumpContext = dumpContext;
118 }
119
120 @Override
121 public void contextInitialized(ServletContextEvent sce)
122 {
123 sce.getServletContext().addListener(_servletRequestListener);
124 ContextHandler handler = ContextHandler.getContextHandler(sce.getServletContext());
125 handler.addEventListener(_contextScopeListener);
126 String cname=findContextName(sce.getServletContext());
127 log("^ ctx=%s %s",cname,sce.getServletContext());
128 if (_dumpContext)
129 {
130 if (_out==null)
131 handler.dumpStdErr();
132 else
133 {
134 try
135 {
136 handler.dump(_out);
137 }
138 catch(Exception e)
139 {
140 LOG.warn(e);
141 }
142 }
143 }
144 }
145
146 @Override
147 public void contextDestroyed(ServletContextEvent sce)
148 {
149 String cname=findContextName(sce.getServletContext());
150 log("v ctx=%s %s",cname,sce.getServletContext());
151 }
152
153 protected String findContextName(ServletContext context)
154 {
155 if (context==null)
156 return null;
157 String n = (String)context.getAttribute(_attr);
158 if (n==null)
159 {
160 n=String.format("%s@%x",context.getContextPath(),context.hashCode());
161 context.setAttribute(_attr,n);
162 }
163 return n;
164 }
165
166 protected String findRequestName(ServletRequest request)
167 {
168 if (request==null)
169 return null;
170 HttpServletRequest r = (HttpServletRequest)request;
171 String n = (String)request.getAttribute(_attr);
172 if (n==null)
173 {
174 n=String.format("%s@%x",r.getRequestURI(),request.hashCode());
175 request.setAttribute(_attr,n);
176 }
177 return n;
178 }
179
180 protected void log(String format, Object... arg)
181 {
182 if (!isRunning())
183 return;
184
185 String s=String.format(format,arg);
186
187 long now = System.currentTimeMillis();
188 long ms = now%1000;
189 if (_out!=null)
190 _out.printf("%s.%03d:%s%n",__date.formatNow(now),ms,s);
191 if (LOG.isDebugEnabled())
192 LOG.info(s);
193 }
194
195 final AsyncListener _asyncListener = new AsyncListener()
196 {
197 @Override
198 public void onTimeout(AsyncEvent event) throws IOException
199 {
200 String cname=findContextName(((AsyncContextEvent)event).getServletContext());
201 String rname=findRequestName(event.getAsyncContext().getRequest());
202 log("! ctx=%s r=%s onTimeout %s",cname,rname,((AsyncContextEvent)event).getHttpChannelState());
203 }
204
205 @Override
206 public void onStartAsync(AsyncEvent event) throws IOException
207 {
208 String cname=findContextName(((AsyncContextEvent)event).getServletContext());
209 String rname=findRequestName(event.getAsyncContext().getRequest());
210 log("! ctx=%s r=%s onStartAsync %s",cname,rname,((AsyncContextEvent)event).getHttpChannelState());
211 }
212
213 @Override
214 public void onError(AsyncEvent event) throws IOException
215 {
216 String cname=findContextName(((AsyncContextEvent)event).getServletContext());
217 String rname=findRequestName(event.getAsyncContext().getRequest());
218 log("!! ctx=%s r=%s onError %s %s",cname,rname,event.getThrowable(),((AsyncContextEvent)event).getHttpChannelState());
219 }
220
221 @Override
222 public void onComplete(AsyncEvent event) throws IOException
223 {
224 AsyncContextEvent ace=(AsyncContextEvent)event;
225 String cname=findContextName(ace.getServletContext());
226 String rname=findRequestName(ace.getAsyncContext().getRequest());
227
228 Request br=Request.getBaseRequest(ace.getAsyncContext().getRequest());
229 Response response = br.getResponse();
230 String headers=_showHeaders?("\n"+response.getHttpFields().toString()):"";
231
232 log("! ctx=%s r=%s onComplete %s %d%s",cname,rname,ace.getHttpChannelState(),response.getStatus(),headers);
233 }
234 };
235
236 final ServletRequestListener _servletRequestListener = new ServletRequestListener()
237 {
238 @Override
239 public void requestInitialized(ServletRequestEvent sre)
240 {
241 String cname=findContextName(sre.getServletContext());
242 HttpServletRequest r = (HttpServletRequest)sre.getServletRequest();
243
244 String rname=findRequestName(r);
245 DispatcherType d = r.getDispatcherType();
246 if (d==DispatcherType.REQUEST)
247 {
248 Request br=Request.getBaseRequest(r);
249
250 String headers=_showHeaders?("\n"+br.getMetaData().getFields().toString()):"";
251
252
253 StringBuffer url=r.getRequestURL();
254 if (r.getQueryString()!=null)
255 url.append('?').append(r.getQueryString());
256 log(">> %s ctx=%s r=%s %s %s %s %s %s%s",d,
257 cname,
258 rname,
259 d,
260 r.getMethod(),
261 url.toString(),
262 r.getProtocol(),
263 br.getHttpChannel(),
264 headers);
265 }
266 else
267 log(">> %s ctx=%s r=%s",d,cname,rname);
268 }
269
270 @Override
271 public void requestDestroyed(ServletRequestEvent sre)
272 {
273 String cname=findContextName(sre.getServletContext());
274 HttpServletRequest r = (HttpServletRequest)sre.getServletRequest();
275 String rname=findRequestName(r);
276 DispatcherType d = r.getDispatcherType();
277 if (sre.getServletRequest().isAsyncStarted())
278 {
279 sre.getServletRequest().getAsyncContext().addListener(_asyncListener);
280 log("<< %s ctx=%s r=%s async=true",d,cname,rname);
281 }
282 else
283 {
284 Request br=Request.getBaseRequest(r);
285 String headers=_showHeaders?("\n"+br.getResponse().getHttpFields().toString()):"";
286 log("<< %s ctx=%s r=%s async=false %d%s",d,cname,rname,Request.getBaseRequest(r).getResponse().getStatus(),headers);
287 }
288 }
289 };
290
291 final ContextHandler.ContextScopeListener _contextScopeListener = new ContextHandler.ContextScopeListener()
292 {
293 @Override
294 public void enterScope(Context context, Request request, Object reason)
295 {
296 String cname=findContextName(context);
297 if (request==null)
298 log("> ctx=%s %s",cname,reason);
299 else
300 {
301 String rname=findRequestName(request);
302
303 if (_renameThread)
304 {
305 Thread thread=Thread.currentThread();
306 thread.setName(String.format("%s#%s",thread.getName(),rname));
307 }
308
309 log("> ctx=%s r=%s %s",cname,rname,reason);
310 }
311 }
312
313
314 @Override
315 public void exitScope(Context context, Request request)
316 {
317 String cname=findContextName(context);
318 if (request==null)
319 log("< ctx=%s",cname);
320 else
321 {
322 String rname=findRequestName(request);
323
324 log("< ctx=%s r=%s",cname,rname);
325 if (_renameThread)
326 {
327 Thread thread=Thread.currentThread();
328 if (thread.getName().endsWith(rname))
329 thread.setName(thread.getName().substring(0,thread.getName().length()-rname.length()-1));
330 }
331 }
332 }
333 };
334 }