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&uuml;lc&uuml;
    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 }