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