001package net.sf.logdistiller.logtypes; 002 003/* 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017import java.io.*; 018import java.text.DateFormat; 019import java.text.ParseException; 020import java.text.SimpleDateFormat; 021import java.util.Date; 022import java.util.Locale; 023import java.util.Map; 024 025import net.sf.logdistiller.LogEvent; 026import net.sf.logdistiller.LogType; 027import net.sf.logdistiller.util.FormatUtil; 028import net.sf.logdistiller.util.LogEventBuilder; 029import net.sf.logdistiller.util.StringCutter; 030 031/** 032 * Log event for <a href="http://edocs.bea.com/">BEA Weblogic server</a>'s logs. By default, the date format is 033 * <code>MMM d, yyyy K:mm:ss a zz</code> with <code>en_US</code> locale, but you can change these values with logtype 034 * parameters <code>date.format</code> (expressed as a 035 * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/SimpleDateFormat.html">java.text.SimpleDateFormat pattern</a>) 036 * and <code>date.locale</code>.<br> 037 * Example: 038 * 039 * <pre> 040 * <logtype id="weblogic"> 041 * <param name="date.locale">fr_FR</param> 042 * <param name="date.format">MMM d, yyyy K:mm:ss a zz</param> 043 * </logtype> 044 * </pre> 045 * 046 * By default, the classification rules generated by the GUI for this type of logs will sort events based on the 047 * following attributes: <code>severity</code>, then <code>subsystem</code> then <code>message_id</code>. 048 * 049 * @see java.text.SimpleDateFormat 050 */ 051public class WeblogicLogEvent 052 extends LogEvent 053 implements Comparable<WeblogicLogEvent> 054{ 055 public final static String ID = "weblogic"; 056 057 public final Date date; 058 059 public final String timestamp; 060 061 public final String severity; 062 063 public final String subsystem; 064 065 public final String machine; 066 067 public final String server; 068 069 public final String thread_id; 070 071 public final String transaction_id; 072 073 public final String user_id; 074 075 public final String message_id; 076 077 public final String message_text; 078 079 public final String stacktrace; 080 081 public final static LogType LOGTYPE = new WlLogType(); 082 083 private final static String LOGEVENT_START = "####<"; 084 085 private final static String[] ATTRIBUTE_NAMES = 086 { "logSource", "timestamp", "severity", "subsystem", "machine", "server", "thread_id", "transaction_id", 087 "user_id", "message_id", "message_text", "stacktrace" }; 088 089 public WeblogicLogEvent( Factory factory, String rawLog ) 090 throws ParseException 091 { 092 super( factory, rawLog ); 093 StringCutter cutter = new StringCutter( rawLog ); 094 cutter.parseTo( LOGEVENT_START ); 095 timestamp = cutter.parseTo( "> <" ); 096 date = factory.parseDate( timestamp ); 097 severity = cutter.parseTo( "> <" ); 098 subsystem = cutter.parseTo( "> <" ); 099 machine = cutter.parseTo( "> <" ); 100 server = cutter.parseTo( "> <" ); 101 thread_id = cutter.parseTo( "> <" ); 102 transaction_id = cutter.parseTo( "> <" ); 103 user_id = cutter.parseTo( "> <" ); 104 message_id = cutter.parseTo( "> <" ); 105 message_text = cutter.parseTo( "> " ); 106 String remaining = cutter.getRemaining(); 107 stacktrace = ( "".equals( remaining ) ) ? "" : remaining.substring( LogEvent.Factory.NEWLINE.length() ); 108 setAttributes( new String[] { factory.getLogSource(), timestamp, severity, subsystem, machine, server, 109 thread_id, transaction_id, user_id, message_id, message_text, stacktrace } ); 110 } 111 112 public int compareTo( WeblogicLogEvent o ) 113 { 114 return date.compareTo( o.date ); 115 } 116 117 /** 118 * Weblogic log type supports following parameters: 119 * <ul> 120 * <li><code>date.format</code></li> 121 * <li><code>date.locale</code></li> 122 * </ul> 123 */ 124 private static class WlLogType 125 extends LogType 126 { 127 private final static String DEFAULT_DATE_FORMAT = "MMM d, yyyy K:mm:ss a zz"; 128 129 public WlLogType() 130 { 131 super( WeblogicLogEvent.ID ); 132 } 133 134 public LogType.Description newDescription( Map<String, String> params ) 135 { 136 String dateFormat = params.get( "date.format" ); 137 dateFormat = ( dateFormat == null ) ? DEFAULT_DATE_FORMAT : dateFormat; 138 String locale = params.get( "date.locale" ); 139 Locale lcle = ( locale == null ) ? Locale.US : FormatUtil.parseLocale( locale ); 140 return new WeblogicLogEvent.Description( this, WeblogicLogEvent.ATTRIBUTE_NAMES, dateFormat, lcle ); 141 } 142 } 143 144 private static class Description 145 extends LogType.Description 146 { 147 /** @since 0.9 */ 148 private final String format; 149 150 /** @since 0.9 */ 151 private final Locale locale; 152 153 /** @since 0.9 */ 154 private final DateFormat df; 155 156 public Description( LogType logtype, String[] attributeNames, String format, Locale locale ) 157 { 158 super( logtype, attributeNames ); 159 this.format = format; 160 this.locale = locale; 161 this.df = new SimpleDateFormat( format, locale ); 162 } 163 164 public LogEvent.Factory newFactory( Reader reader, String logSource ) 165 throws IOException 166 { 167 return new Factory( this, reader, logSource ); 168 } 169 170 /** @since 0.9 */ 171 public DateFormat getDateFormat() 172 { 173 return df; 174 } 175 176 /** @since 0.9 */ 177 public Locale getLocale() 178 { 179 return locale; 180 } 181 182 /** @since 0.9 */ 183 public String getFormat() 184 { 185 return format; 186 } 187 188 public String getDefaultSpecificGroups() 189 { 190 return " <group id=\"warning\">\n" 191 + " <description>Warning events</description>\n" 192 + " <condition>\n" 193 + " <match attribute=\"severity\" type=\"equals\">Warning</match>\n" 194 + " </condition>\n" 195 + " <report publisher=\"file\"/>\n" 196 + " <plugin type=\"sampling\">\n" 197 + " <param name=\"attributes\">subsystem,message_id</param>\n" 198 + " </plugin>\n" 199 + " </group>\n" 200 + "\n" 201 + " <group id=\"error\">\n" 202 + " <description>Error events</description>\n" 203 + " <condition>\n" 204 + " <match attribute=\"severity\" type=\"equals\">Error</match>\n" 205 + " </condition>\n" 206 + " <report publisher=\"file\"/>\n" 207 + " <plugin type=\"sampling\">\n" 208 + " <param name=\"attributes\">subsystem,message_id</param>\n" 209 + " </plugin>\n" 210 + " </group>"; 211 } 212 213 public String getDefaultSamplingAttributes() 214 { 215 return "severity,subsystem,message_id"; 216 } 217 } 218 219 private static class Factory 220 extends LogEvent.Factory 221 { 222 private final DateFormat df; 223 224 private final LineNumberReader reader; 225 226 private String curLine; 227 228 public Factory( Description description, Reader reader, String logSource ) 229 throws FileNotFoundException 230 { 231 super( description, logSource ); 232 this.reader = new LineNumberReader( reader ); 233 this.df = description.getDateFormat(); 234 } 235 236 protected boolean detectLogEventStart( String line ) 237 { 238 return line.startsWith( LOGEVENT_START ); 239 } 240 241 protected LogEvent readNextEvent() 242 throws IOException, ParseException 243 { 244 if ( curLine == null ) 245 { 246 curLine = reader.readLine(); 247 if ( curLine == null ) 248 { 249 // EOF 250 return null; 251 } 252 } 253 254 int lineNumber = reader.getLineNumber(); 255 256 if ( !detectLogEventStart( curLine ) ) 257 { 258 if ( curLine.length() > 15 ) 259 { 260 curLine = curLine.substring( 0, 15 ) + "... (line " + lineNumber + ")"; 261 } 262 String msg = " should start with '" + LOGEVENT_START + "' but found '" + curLine + "'"; 263 if ( reader.getLineNumber() == 1 ) 264 { 265 throw new ParseException( "bad log format: is it really a Weblogic log file? It" + msg, 0 ); 266 } 267 throw new ParseException( "bad log format, line " + reader.getLineNumber() + msg, 0 ); 268 } 269 270 StringBuffer buffer = new StringBuffer( curLine ); 271 while ( ( ( curLine = reader.readLine() ) != null ) && ( !detectLogEventStart( curLine ) ) ) 272 { 273 buffer.append( NEWLINE ); 274 buffer.append( curLine ); 275 } 276 277 return BUILDER.buildLogEvent( this, lineNumber, buffer.toString() ); 278 } 279 280 private final static LogEventBuilder BUILDER = new LogEventBuilder() 281 { 282 protected LogEvent newEvent( LogEvent.Factory factory, String curLine, Object... objects ) 283 throws ParseException 284 { 285 return new WeblogicLogEvent( (Factory)factory, curLine ); 286 } 287 }; 288 289 public Date parseDate( String date ) 290 throws ParseException 291 { 292 try 293 { 294 return df.parse( date ); 295 } 296 catch ( ParseException pe ) 297 { 298 Description desc = (Description) description; 299 throw new ParseException( pe.getMessage() + ", expected format: " + desc.getFormat() 300 + ", expected locale: " + desc.getLocale(), pe.getErrorOffset() ); 301 } 302 } 303 } 304}