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> "; 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 }