View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.classic.html;
15  
16  import java.util.Map;
17  
18  import ch.qos.logback.classic.PatternLayout;
19  import ch.qos.logback.classic.pattern.MDCConverter;
20  import ch.qos.logback.classic.spi.ILoggingEvent;
21  import ch.qos.logback.core.helpers.Transform;
22  import ch.qos.logback.core.html.HTMLLayoutBase;
23  import ch.qos.logback.core.html.IThrowableRenderer;
24  import ch.qos.logback.core.pattern.Converter;
25  import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;
26  
27  /**
28   * 
29   * HTMLLayout outputs events in an HTML table.
30   * <p>
31   * The content of the table columns are specified using a conversion pattern.
32   * See {@link ch.qos.logback.classic.PatternLayout} for documentation on the
33   * available patterns.
34   * <p>
35   * For more information about this layout, please refer to the online manual at
36   * http://logback.qos.ch/manual/layouts.html#ClassicHTMLLayout
37   * 
38   * @author Ceki G&uuml;lc&uuml;
39   * @author S&eacute;bastien Pennec
40   */
41  public class HTMLLayout extends HTMLLayoutBase<ILoggingEvent> {
42  
43      /**
44       * Default pattern string for log output.
45       */
46      static final String DEFAULT_CONVERSION_PATTERN = "%date%thread%level%logger%mdc%msg";
47  
48      IThrowableRenderer<ILoggingEvent> throwableRenderer;
49  
50      /**
51       * Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
52       * 
53       * The default pattern just produces the application supplied message.
54       */
55      public HTMLLayout() {
56          pattern = DEFAULT_CONVERSION_PATTERN;
57          throwableRenderer = new DefaultThrowableRenderer();
58          cssBuilder = new DefaultCssBuilder();
59      }
60  
61      @Override
62      public void start() {
63          int errorCount = 0;
64          if (throwableRenderer == null) {
65              addError("ThrowableRender cannot be null.");
66              errorCount++;
67          }
68          if (errorCount == 0) {
69              super.start();
70          }
71      }
72  
73      protected Map<String, String> getDefaultConverterMap() {
74          return PatternLayout.DEFAULT_CONVERTER_MAP;
75      }
76  
77      public String doLayout(ILoggingEvent event) {
78          StringBuilder buf = new StringBuilder();
79          startNewTableIfLimitReached(buf);
80  
81          boolean odd = true;
82          if (((counter++) & 1) == 0) {
83              odd = false;
84          }
85  
86          String level = event.getLevel().toString().toLowerCase();
87  
88          buf.append(LINE_SEPARATOR);
89          buf.append("<tr class=\"");
90          buf.append(level);
91          if (odd) {
92              buf.append(" odd\">");
93          } else {
94              buf.append(" even\">");
95          }
96          buf.append(LINE_SEPARATOR);
97  
98          Converter<ILoggingEvent> c = head;
99          while (c != null) {
100             appendEventToBuffer(buf, c, event);
101             c = c.getNext();
102         }
103         buf.append("</tr>");
104         buf.append(LINE_SEPARATOR);
105 
106         if (event.getThrowableProxy() != null) {
107             throwableRenderer.render(buf, event);
108         }
109         return buf.toString();
110     }
111 
112     private void appendEventToBuffer(StringBuilder buf, Converter<ILoggingEvent> c, ILoggingEvent event) {
113         buf.append("<td class=\"");
114         buf.append(computeConverterName(c));
115         buf.append("\">");
116         buf.append(Transform.escapeTags(c.convert(event)));
117         buf.append("</td>");
118         buf.append(LINE_SEPARATOR);
119     }
120 
121     public IThrowableRenderer<ILoggingEvent> getThrowableRenderer() {
122         return throwableRenderer;
123     }
124 
125     public void setThrowableRenderer(IThrowableRenderer<ILoggingEvent> throwableRenderer) {
126         this.throwableRenderer = throwableRenderer;
127     }
128 
129     @Override
130     protected String computeConverterName(Converter<ILoggingEvent> c) {
131         if (c instanceof MDCConverter) {
132             MDCConverter mc = (MDCConverter) c;
133             String key = mc.getFirstOption();
134             if (key != null) {
135                 return key;
136             } else {
137                 return "MDC";
138             }
139         } else {
140             return super.computeConverterName(c);
141         }
142     }
143 }