This project has retired. For details please refer to its
Attic page.
LoggingFilter xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.server.support.filter;
20
21 import java.io.BufferedReader;
22 import java.io.ByteArrayOutputStream;
23 import java.io.File;
24 import java.io.FileReader;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.io.PrintWriter;
28 import java.io.StringReader;
29 import java.io.StringWriter;
30 import java.io.Writer;
31 import java.text.SimpleDateFormat;
32 import java.util.Date;
33 import java.util.Enumeration;
34 import java.util.HashMap;
35 import java.util.Locale;
36 import java.util.Map;
37 import java.util.Scanner;
38
39 import javax.servlet.Filter;
40 import javax.servlet.FilterChain;
41 import javax.servlet.FilterConfig;
42 import javax.servlet.ServletException;
43 import javax.servlet.ServletInputStream;
44 import javax.servlet.ServletOutputStream;
45 import javax.servlet.ServletRequest;
46 import javax.servlet.ServletResponse;
47 import javax.servlet.http.Cookie;
48 import javax.servlet.http.HttpServletRequest;
49 import javax.servlet.http.HttpServletRequestWrapper;
50 import javax.servlet.http.HttpServletResponse;
51 import javax.servlet.http.HttpServletResponseWrapper;
52 import javax.xml.transform.OutputKeys;
53 import javax.xml.transform.Source;
54 import javax.xml.transform.Transformer;
55 import javax.xml.transform.TransformerFactory;
56 import javax.xml.transform.stream.StreamResult;
57 import javax.xml.transform.stream.StreamSource;
58
59 import org.apache.commons.logging.Log;
60 import org.apache.commons.logging.LogFactory;
61
62 public class LoggingFilter implements Filter {
63
64 private static final Log log = LogFactory.getLog(LoggingFilter.class);
65 private static int REQUEST_NO = 0;
66 private static final SimpleDateFormat FORMAT = new SimpleDateFormat("EEE MMM dd hh:mm:ss a z yyyy", Locale.US);
67 private String logDir;
68 private boolean prettyPrint = true;
69 private boolean logHeaders = true;
70 private int indent = -1;
71
72 public void init(FilterConfig cfg) throws ServletException {
73
74 String val;
75 logDir = cfg.getInitParameter("LogDir");
76 if (null == logDir || logDir.length() == 0)
77 logDir = System.getProperty("java.io.tmpdir");
78 if (null == logDir|| logDir.length() == 0)
79 logDir = "." + File.separator;
80
81 if (!logDir.endsWith(File.separator))
82 logDir += File.separator;
83
84 val = cfg.getInitParameter("Indent");
85 if (null != val)
86 indent = Integer.parseInt(val);
87 if (indent < 0)
88 indent = 4;
89
90 val = cfg.getInitParameter("PrettyPrint");
91 if (null != val)
92 prettyPrint = Boolean.parseBoolean(val);
93
94 val = cfg.getInitParameter("LogHeaders");
95 if (null != val)
96 logHeaders = Boolean.parseBoolean(val);
97 }
98
99 public void destroy() {
100 }
101
102 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,
103 ServletException {
104 log.debug("Logging filter doFilter");
105
106 if (resp instanceof HttpServletResponse && req instanceof HttpServletRequest) {
107 LoggingRequestWrapper logReq = new LoggingRequestWrapper((HttpServletRequest)req);
108 LoggingResponseWrapper logResponse = new LoggingResponseWrapper((HttpServletResponse)resp);
109
110 chain.doFilter(logReq, logResponse);
111
112 int reqNo = getNextRequestNumber();
113 String requestFileName = getRequestFileName(reqNo);
114 String cType = logReq.getContentType();
115 String xmlRequest = logReq.getPayload();
116 StringBuffer sb = new StringBuffer();
117
118 if (logHeaders)
119 logHeaders(logReq, sb);
120
121 if (xmlRequest == null || xmlRequest.length() == 0)
122 xmlRequest = "";
123
124 if (prettyPrint && cType != null) {
125 if (cType.startsWith("multipart")) {
126 xmlRequest = processMultipart(cType, xmlRequest);
127 } else if (cType.contains("xml")) {
128 xmlRequest = prettyPrintXml(xmlRequest, indent);
129 }
130 }
131
132 xmlRequest = sb.toString() + xmlRequest;
133 log.debug("Found request: " + requestFileName + ": " + xmlRequest);
134 writeTextToFile(requestFileName, xmlRequest);
135
136
137 sb = new StringBuffer();
138 cType = logResponse.getContentType();
139 String xmlResponse = logResponse.getPayload();
140 String responseFileName = getResponseFileName(reqNo);
141
142 if (logHeaders) {
143 logHeaders(logResponse, req.getProtocol(), sb);
144 }
145
146 if (xmlResponse == null || xmlResponse.length() == 0)
147 xmlResponse = "";
148
149 if (prettyPrint && cType != null) {
150 if (cType.startsWith("multipart")) {
151 xmlResponse = processMultipart(cType, xmlResponse);
152 } else if (cType.contains("xml")) {
153 xmlResponse = prettyPrintXml(xmlResponse, indent);
154 } else if (cType.contains("json")) {
155 xmlResponse = prettyPrintJson(xmlResponse, indent);
156 }
157 }
158
159 xmlResponse = sb.toString() + xmlResponse;
160 log.debug("Found response: " + responseFileName + ": " + xmlResponse);
161 writeTextToFile(responseFileName, xmlResponse);
162 } else {
163 chain.doFilter(req, resp);
164 }
165 }
166
167 private void writeTextToFile(String filename, String content) {
168 PrintWriter pw = null;
169 FileWriter fw = null;
170 try {
171 fw = new FileWriter(filename);
172 pw = new PrintWriter(fw);
173
174 Scanner scanner = new Scanner(content);
175 while (scanner.hasNextLine()) {
176 String line = scanner.nextLine();
177 pw.println(line);
178 }
179
180 pw.flush();
181 } catch (IOException e) {
182 e.printStackTrace();
183 } finally {
184 if (pw != null)
185 pw.close();
186 if (fw != null)
187 try {
188 fw.close();
189 } catch (IOException e) {
190 e.printStackTrace();
191 }
192 }
193 }
194
195 private static String prettyPrintXml(String input, int indent) {
196 try {
197 Source xmlInput = new StreamSource(new StringReader(input));
198 StringWriter stringWriter = new StringWriter();
199 StreamResult xmlOutput = new StreamResult(stringWriter);
200 TransformerFactory transformerFactory = TransformerFactory.newInstance();
201 transformerFactory.setAttribute("indent-number", indent);
202 Transformer transformer = transformerFactory.newTransformer();
203 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
204 transformer.transform(xmlInput, xmlOutput);
205 return xmlOutput.getWriter().toString();
206 } catch (Exception e) {
207 throw new RuntimeException(e);
208 }
209 }
210
211 private static String prettyPrintJson(String input, int indent) {
212 JsonPrettyPrinter pp = new JsonPrettyPrinter(indent);
213 return pp.prettyPrint(input);
214 }
215
216 private String processMultipart(String cType, String messageBody) throws IOException {
217 int beginIndex = cType.indexOf("boundary=\"") + 10;
218 int endIndex = cType.indexOf("\"", beginIndex);
219 if (endIndex < 0)
220 endIndex = cType.length();
221 String boundary = "--" + cType.substring(beginIndex, endIndex);
222 log.debug("Boundary = " + boundary);
223 BufferedReader in = new BufferedReader(new StringReader(messageBody));
224 StringBuffer out = new StringBuffer();
225 String line;
226 ByteArrayOutputStream xmlBodyBuffer = new ByteArrayOutputStream();
227 boolean boundaryFound;
228
229 boolean inXmlOrJsonBody = false;
230 boolean inXmlOrJsonPart = false;
231 boolean isXml;
232 while ((line = in.readLine()) != null) {
233 if (inXmlOrJsonPart) {
234 if (line.startsWith("<?xml") || line.startsWith("{")) {
235 inXmlOrJsonBody = true;
236 isXml = line.startsWith("<?xml");
237 xmlBodyBuffer.write(line.getBytes(), 0, line.length());
238 while (inXmlOrJsonBody) {
239 line = in.readLine();
240 boundaryFound = line.startsWith(boundary);
241 if (boundaryFound) {
242 log.debug("Leaving XML body: " + line);
243 inXmlOrJsonBody = false;
244 inXmlOrJsonPart = false;
245 if (isXml)
246 out.append(prettyPrintXml(xmlBodyBuffer.toString(), indent));
247 else
248 out.append(prettyPrintJson(xmlBodyBuffer.toString(), indent));
249 out.append(line).append("\n");
250 } else
251 xmlBodyBuffer.write(line.getBytes(), 0, line.length());
252 }
253 } else {
254 log.debug("in XML part is: " + line);
255 out.append(line).append("\n");
256 }
257
258 } else {
259 log.debug("not in XML part: " + line);
260 out.append(line).append("\n");
261 boundaryFound = line.startsWith(boundary);
262 if (boundaryFound) {
263 log.debug("Boundardy found!");
264 inXmlOrJsonPart = true;
265 }
266 }
267 }
268 in.close();
269 log.debug("End parsing multipart.");
270
271 return out.toString();
272 }
273
274 @SuppressWarnings("rawtypes")
275 private void logHeaders(LoggingRequestWrapper req, StringBuffer sb) {
276 sb.append(req.getMethod());
277 sb.append(" ");
278 sb.append(req.getRequestURI());
279 String queryString = req.getQueryString();
280 if (null != queryString && queryString.length() > 0) {
281 sb.append("?");
282 sb.append(queryString);
283 }
284 sb.append(" ");
285 sb.append(req.getProtocol());
286 sb.append("\n");
287 Enumeration headerNames = req.getHeaderNames();
288 while (headerNames.hasMoreElements()) {
289 String headerName = headerNames.nextElement().toString();
290 headerName = headerName.substring(0, 1).toUpperCase() + headerName.substring(1);
291 sb.append(headerName + ": ");
292 sb.append(req.getHeader(headerName));
293 sb.append("\n");
294 }
295 sb.append("\n");
296 }
297
298 private void logHeaders(LoggingResponseWrapper resp, String protocol, StringBuffer sb) {
299 sb.append(protocol);
300 sb.append(" ");
301 sb.append(String.valueOf(resp.getStatus()));
302 sb.append("\n");
303 Map<String, String> headers = resp.getHeaders();
304 for ( Map.Entry<String, String> header: headers.entrySet()) {
305 sb.append(header.getKey());
306 sb.append(": ");
307 sb.append(header.getValue());
308 sb.append("\n");
309 }
310 sb.append("\n");
311 }
312
313 private String getRequestFileName(int no) {
314 return logDir + String.format("%05d-request.log", no);
315 }
316
317 private String getResponseFileName(int no) {
318 return logDir + String.format("%05d-response.log", no);
319 }
320
321 private static synchronized int getNextRequestNumber() {
322 return REQUEST_NO++;
323 }
324
325 private class LoggingRequestWrapper extends HttpServletRequestWrapper {
326
327 private LoggingInputStream is;
328
329 public LoggingRequestWrapper(HttpServletRequest request) throws IOException {
330 super(request);
331 }
332
333 @Override
334 public ServletInputStream getInputStream() throws IOException {
335 this.is = new LoggingInputStream(super.getInputStream());
336 return is;
337 }
338
339 public String getPayload() {
340 return null == is ? "" : is.getPayload();
341 }
342 }
343
344 private class LoggingInputStream extends ServletInputStream {
345
346 private ByteArrayOutputStream baous = new ByteArrayOutputStream();
347 private ServletInputStream is;
348
349 public LoggingInputStream(ServletInputStream is) {
350 super();
351 this.is = is;
352 }
353
354
355 @Override
356 public int read() throws IOException {
357 int ch = is.read();
358 if (ch != -1) {
359 baous.write(ch);
360 }
361 return ch;
362 }
363
364 @Override
365 public int read(byte[] b) throws IOException {
366 int ch = is.read(b);
367 if (ch != -1) {
368 baous.write(b, 0, ch);
369 }
370 return ch;
371 }
372
373 @Override
374 public int read(byte[] b, int o, int l) throws IOException {
375 int ch = is.read(b, o, l);
376 if (ch != -1) {
377 baous.write(b, o, ch);
378 }
379 return ch;
380 }
381
382 @Override
383 public int readLine(byte[] b, int o, int l) throws IOException {
384 int ch = is.readLine(b, o, l);
385 if (ch != -1) {
386 baous.write(b, o, ch);
387 }
388 return ch;
389 }
390
391 public String getPayload() {
392 return baous.toString();
393 }
394 }
395
396 private class LoggingResponseWrapper extends HttpServletResponseWrapper {
397
398 private LoggingOutputStream os;
399 private PrintWriter writer;
400 private int statusCode;
401 private Map<String, String> headers = new HashMap<String, String>();
402 String encoding;
403
404 public LoggingResponseWrapper(HttpServletResponse response) throws IOException {
405 super(response);
406 this.os = new LoggingOutputStream(response.getOutputStream());
407 }
408
409 @Override
410 public PrintWriter getWriter() {
411 try {
412 if (null == writer)
413 writer = new PrintWriter(this.getOutputStream());
414 return writer;
415 } catch (IOException e) {
416 log.error("Failed to get PrintWriter in LoggingFilter: "+ e);
417 e.printStackTrace();
418 return null;
419 }
420 }
421
422 @Override
423 public ServletOutputStream getOutputStream() throws IOException {
424 return os;
425 }
426
427 public String getPayload() {
428 return os.getPayload();
429 }
430
431 @Override
432 public void addCookie(Cookie cookie) {
433 super.addCookie(cookie);
434 String value;
435 if (headers.containsKey("Cookie")) {
436 value = headers.get("Cookie") + "; " + cookie.toString();
437 } else
438 value = cookie.toString();
439 headers.put("Cookie", value);
440 }
441
442 @Override
443 public void setContentType(String type) {
444 super.setContentType(type);
445 if (headers.containsKey("Content-Type")) {
446 String cType = headers.get("Content-Type");
447 int pos = cType.indexOf(";charset=");
448 if (pos < 0 && encoding != null)
449 type = cType + ";charset=" + encoding;
450 else if (pos >= 0)
451 encoding = null;
452 }
453 headers.put("Content-Type", type);
454 }
455
456 @Override
457 public void setCharacterEncoding(java.lang.String charset) {
458 super.setCharacterEncoding(charset);
459 encoding = charset;
460 if (headers.containsKey("Content-Type")) {
461 String cType = headers.get("Content-Type");
462 int pos = cType.indexOf(";charset=");
463 if (pos >=0)
464 cType = cType.substring(0, pos) + ";charset=" + encoding;
465 else
466 cType = cType + ";charset=" + encoding;
467 headers.put("Content-Type", cType);
468 }
469 }
470
471 @Override
472 public void setContentLength(int len) {
473 super.setContentLength(len);
474 headers.put("Content-Length", String.valueOf(len));
475 }
476
477 private String getDateString(long date) {
478 return FORMAT.format(new Date(date));
479 }
480
481 @Override
482 public void setDateHeader(String name, long date) {
483 super.setDateHeader(name, date);
484 headers.put(name, String.valueOf(getDateString(date)));
485 }
486
487 @Override
488 public void addDateHeader(String name, long date) {
489 super.addDateHeader(name, date);
490 if (headers.containsKey(name)) {
491 headers.put(name, headers.get(name) + "; " + getDateString(date));
492 } else {
493 headers.put(name, String.valueOf(getDateString(date)));
494 }
495 }
496
497 @Override
498 public void setHeader(String name, String value) {
499 super.setHeader(name, value);
500 headers.put(name, String.valueOf(value));
501 }
502
503 @Override
504 public void addHeader(String name, String value) {
505 super.addHeader(name, value);
506 if (headers.containsKey(name)) {
507 headers.put(name, headers.get(name) + "; " + value);
508 } else {
509 headers.put(name, String.valueOf(value));
510 }
511 }
512
513 @Override
514 public void setIntHeader(String name, int value) {
515 super.setIntHeader(name, value);
516 headers.put(name, String.valueOf(value));
517 }
518
519 @Override
520 public void addIntHeader(String name, int value) {
521 super.addIntHeader(name, value);
522 if (headers.containsKey(name)) {
523 headers.put(name, headers.get(name) + "; " + String.valueOf(value));
524 } else {
525 headers.put(name, String.valueOf(value));
526 }
527 }
528
529 @Override
530 public void sendError(int sc) throws IOException {
531 statusCode = sc;
532 super.sendError(sc);
533 }
534
535 @Override
536 public void sendError(int sc, String msg) throws IOException {
537 statusCode = sc;
538 super.sendError(sc, msg);
539 }
540
541 @Override
542 public void sendRedirect(String location) throws IOException {
543 statusCode = 302;
544 super.sendRedirect(location);
545 }
546
547 @Override
548 public void setStatus(int sc) {
549 statusCode = sc;
550 super.setStatus(sc);
551 }
552
553 public int getStatus() {
554 return statusCode;
555 }
556
557 public Map<String, String> getHeaders() {
558 return headers;
559 }
560 }
561
562 private class LoggingOutputStream extends ServletOutputStream {
563 private ByteArrayOutputStream baous = new ByteArrayOutputStream();
564 private ServletOutputStream os;
565
566 public LoggingOutputStream(ServletOutputStream os) {
567 super();
568 this.os = os;
569 }
570
571 public String getPayload() {
572 return new String(baous.toString());
573 }
574
575 @Override
576 public void write(byte[] b, int off, int len) {
577 try {
578 baous.write(b, off, len);
579 os.write(b, off, len);
580 } catch (IOException e) {
581 throw new RuntimeException(e);
582 }
583 }
584
585 @Override
586 public
587 void write(byte[] b) {
588 try {
589 baous.write(b);
590 os.write(b);
591 } catch (IOException e) {
592 throw new RuntimeException(e);
593 }
594 }
595
596 @Override
597 public void write(int ch) throws IOException {
598 baous.write(ch);
599 os.write(ch);
600 }
601 }
602 }