View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.log4j;
19  
20  import org.apache.log4j.spi.LoggingEvent;
21  import org.apache.log4j.spi.LocationInfo;
22  import org.apache.log4j.helpers.Transform;
23  
24  /**
25   * This layout outputs events in a HTML table.
26   *
27   * Appenders using this layout should have their encoding
28   * set to UTF-8 or UTF-16, otherwise events containing
29   * non ASCII characters could result in corrupted
30   * log files.
31   *
32   *  @author Ceki Gülcü
33   */
34  public class HTMLLayout extends Layout {
35  
36    protected final int BUF_SIZE = 256;
37    protected final int MAX_CAPACITY = 1024;
38  
39    static String TRACE_PREFIX = "<br>&nbsp;&nbsp;&nbsp;&nbsp;";
40  
41    // output buffer appended to when format() is invoked
42    private StringBuffer sbuf = new StringBuffer(BUF_SIZE);
43  
44    /**
45       A string constant used in naming the option for setting the the
46       location information flag.  Current value of this string
47       constant is <b>LocationInfo</b>.
48  
49       <p>Note that all option keys are case sensitive.
50  
51       @deprecated Options are now handled using the JavaBeans paradigm.
52       This constant is not longer needed and will be removed in the
53       <em>near</em> term.
54  
55    */
56    public static final String LOCATION_INFO_OPTION = "LocationInfo";
57  
58    /**
59       A string constant used in naming the option for setting the the
60       HTML document title.  Current value of this string
61       constant is <b>Title</b>.
62    */
63    public static final String TITLE_OPTION = "Title";
64  
65    // Print no location info by default
66    boolean locationInfo = false;
67  
68    String title = "Log4J Log Messages";
69  
70    /**
71       The <b>LocationInfo</b> option takes a boolean value. By
72       default, it is set to false which means there will be no location
73       information output by this layout. If the the option is set to
74       true, then the file name and line number of the statement
75       at the origin of the log statement will be output.
76  
77       <p>If you are embedding this layout within an {@link
78       org.apache.log4j.net.SMTPAppender} then make sure to set the
79       <b>LocationInfo</b> option of that appender as well.
80     */
81    public
82    void setLocationInfo(boolean flag) {
83      locationInfo = flag;
84    }
85  
86    /**
87       Returns the current value of the <b>LocationInfo</b> option.
88     */
89    public
90    boolean getLocationInfo() {
91      return locationInfo;
92    }
93  
94    /**
95      The <b>Title</b> option takes a String value. This option sets the
96      document title of the generated HTML document.
97  
98      <p>Defaults to 'Log4J Log Messages'.
99    */
100   public
101   void setTitle(String title) {
102     this.title = title;
103   }
104 
105   /**
106      Returns the current value of the <b>Title</b> option.
107   */
108   public
109   String getTitle() {
110     return title;
111   }
112 
113  /**
114      Returns the content type output by this layout, i.e "text/html".
115   */
116   public
117   String getContentType() {
118     return "text/html";
119   }
120 
121   /**
122      No options to activate.
123   */
124   public
125   void activateOptions() {
126   }
127 
128   public
129   String format(LoggingEvent event) {
130 
131     if(sbuf.capacity() > MAX_CAPACITY) {
132       sbuf = new StringBuffer(BUF_SIZE);
133     } else {
134       sbuf.setLength(0);
135     }
136 
137     sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);
138 
139     sbuf.append("<td>");
140     sbuf.append(event.timeStamp - LoggingEvent.getStartTime());
141     sbuf.append("</td>" + Layout.LINE_SEP);
142 
143     String escapedThread = Transform.escapeTags(event.getThreadName());
144     sbuf.append("<td title=\"" + escapedThread + " thread\">");
145     sbuf.append(escapedThread);
146     sbuf.append("</td>" + Layout.LINE_SEP);
147 
148     sbuf.append("<td title=\"Level\">");
149     if (event.getLevel().equals(Level.DEBUG)) {
150       sbuf.append("<font color=\"#339933\">");
151       sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
152       sbuf.append("</font>");
153     }
154     else if(event.getLevel().isGreaterOrEqual(Level.WARN)) {
155       sbuf.append("<font color=\"#993300\"><strong>");
156       sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
157       sbuf.append("</strong></font>");
158     } else {
159       sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
160     }
161     sbuf.append("</td>" + Layout.LINE_SEP);
162 
163     String escapedLogger = Transform.escapeTags(event.getLoggerName());
164     sbuf.append("<td title=\"" + escapedLogger + " category\">");
165     sbuf.append(escapedLogger);
166     sbuf.append("</td>" + Layout.LINE_SEP);
167 
168     if(locationInfo) {
169       LocationInfo locInfo = event.getLocationInformation();
170       sbuf.append("<td>");
171       sbuf.append(Transform.escapeTags(locInfo.getFileName()));
172       sbuf.append(':');
173       sbuf.append(locInfo.getLineNumber());
174       sbuf.append("</td>" + Layout.LINE_SEP);
175     }
176 
177     sbuf.append("<td title=\"Message\">");
178     sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
179     sbuf.append("</td>" + Layout.LINE_SEP);
180     sbuf.append("</tr>" + Layout.LINE_SEP);
181 
182     if (event.getNDC() != null) {
183       sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : xx-small;\" colspan=\"6\" title=\"Nested Diagnostic Context\">");
184       sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));
185       sbuf.append("</td></tr>" + Layout.LINE_SEP);
186     }
187 
188     String[] s = event.getThrowableStrRep();
189     if(s != null) {
190       sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : xx-small;\" colspan=\"6\">");
191       appendThrowableAsHTML(s, sbuf);
192       sbuf.append("</td></tr>" + Layout.LINE_SEP);
193     }
194 
195     return sbuf.toString();
196   }
197 
198   void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {
199     if(s != null) {
200       int len = s.length;
201       if(len == 0)
202 	return;
203       sbuf.append(Transform.escapeTags(s[0]));
204       sbuf.append(Layout.LINE_SEP);
205       for(int i = 1; i < len; i++) {
206 	sbuf.append(TRACE_PREFIX);
207 	sbuf.append(Transform.escapeTags(s[i]));
208 	sbuf.append(Layout.LINE_SEP);
209       }
210     }
211   }
212 
213   /**
214      Returns appropriate HTML headers.
215   */
216   public
217   String getHeader() {
218     StringBuffer sbuf = new StringBuffer();
219     sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"  + Layout.LINE_SEP);
220     sbuf.append("<html>" + Layout.LINE_SEP);
221     sbuf.append("<head>" + Layout.LINE_SEP);
222     sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);
223     sbuf.append("<style type=\"text/css\">"  + Layout.LINE_SEP);
224     sbuf.append("<!--"  + Layout.LINE_SEP);
225     sbuf.append("body, table {font-family: arial,sans-serif; font-size: x-small;}" + Layout.LINE_SEP);
226     sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);
227     sbuf.append("-->" + Layout.LINE_SEP);
228     sbuf.append("</style>" + Layout.LINE_SEP);
229     sbuf.append("</head>" + Layout.LINE_SEP);
230     sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">" + Layout.LINE_SEP);
231     sbuf.append("<hr size=\"1\" noshade>" + Layout.LINE_SEP);
232     sbuf.append("Log session start time " + new java.util.Date() + "<br>" + Layout.LINE_SEP);
233     sbuf.append("<br>" + Layout.LINE_SEP);
234     sbuf.append("<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">" + Layout.LINE_SEP);
235     sbuf.append("<tr>" + Layout.LINE_SEP);
236     sbuf.append("<th>Time</th>" + Layout.LINE_SEP);
237     sbuf.append("<th>Thread</th>" + Layout.LINE_SEP);
238     sbuf.append("<th>Level</th>" + Layout.LINE_SEP);
239     sbuf.append("<th>Category</th>" + Layout.LINE_SEP);
240     if(locationInfo) {
241       sbuf.append("<th>File:Line</th>" + Layout.LINE_SEP);
242     }
243     sbuf.append("<th>Message</th>" + Layout.LINE_SEP);
244     sbuf.append("</tr>" + Layout.LINE_SEP);
245     return sbuf.toString();
246   }
247 
248   /**
249      Returns the appropriate HTML footers.
250   */
251   public
252   String getFooter() {
253     StringBuffer sbuf = new StringBuffer();
254     sbuf.append("</table>" + Layout.LINE_SEP);
255     sbuf.append("<br>" + Layout.LINE_SEP);
256     sbuf.append("</body></html>");
257     return sbuf.toString();
258   }
259 
260   /**
261      The HTML layout handles the throwable contained in logging
262      events. Hence, this method return <code>false</code>.  */
263   public
264   boolean ignoresThrowable() {
265     return false;
266   }
267 }