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