View Javadoc
1   package net.sf.logdistiller.logtypes;
2   
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  import java.io.*;
18  import java.text.DateFormat;
19  import java.text.ParseException;
20  import java.text.SimpleDateFormat;
21  import java.util.Date;
22  import java.util.Locale;
23  import java.util.Map;
24  
25  import net.sf.logdistiller.LogEvent;
26  import net.sf.logdistiller.LogType;
27  import net.sf.logdistiller.util.FormatUtil;
28  import net.sf.logdistiller.util.LogEventBuilder;
29  import net.sf.logdistiller.util.StringCutter;
30  
31  /**
32   * Log event for <a href="http://edocs.bea.com/">BEA Weblogic server</a>'s logs. By default, the date format is
33   * <code>MMM d, yyyy K:mm:ss a zz</code> with <code>en_US</code> locale, but you can change these values with logtype
34   * parameters <code>date.format</code> (expressed as a
35   * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/SimpleDateFormat.html">java.text.SimpleDateFormat pattern</a>)
36   * and <code>date.locale</code>.<br>
37   * Example:
38   *
39   * <pre>
40   * &lt;logtype id=&quot;weblogic&quot;&gt;
41   *  &lt;param name=&quot;date.locale&quot;&gt;fr_FR&lt;/param&gt;
42   *  &lt;param name=&quot;date.format&quot;&gt;MMM d, yyyy K:mm:ss a zz&lt;/param&gt;
43   * &lt;/logtype&gt;
44   * </pre>
45   *
46   * By default, the classification rules generated by the GUI for this type of logs will sort events based on the
47   * following attributes: <code>severity</code>, then <code>subsystem</code> then <code>message_id</code>.
48   *
49   * @see java.text.SimpleDateFormat
50   */
51  public class WeblogicLogEvent
52      extends LogEvent
53      implements Comparable<WeblogicLogEvent>
54  {
55      public final static String ID = "weblogic";
56  
57      public final Date date;
58  
59      public final String timestamp;
60  
61      public final String severity;
62  
63      public final String subsystem;
64  
65      public final String machine;
66  
67      public final String server;
68  
69      public final String thread_id;
70  
71      public final String transaction_id;
72  
73      public final String user_id;
74  
75      public final String message_id;
76  
77      public final String message_text;
78  
79      public final String stacktrace;
80  
81      public final static LogType LOGTYPE = new WlLogType();
82  
83      private final static String LOGEVENT_START = "####<";
84  
85      private final static String[] ATTRIBUTE_NAMES =
86          { "logSource", "timestamp", "severity", "subsystem", "machine", "server", "thread_id", "transaction_id",
87              "user_id", "message_id", "message_text", "stacktrace" };
88  
89      public WeblogicLogEvent( Factory factory, String rawLog )
90          throws ParseException
91      {
92          super( factory, rawLog );
93          StringCutter cutter = new StringCutter( rawLog );
94          cutter.parseTo( LOGEVENT_START );
95          timestamp = cutter.parseTo( "> <" );
96          date = factory.parseDate( timestamp );
97          severity = cutter.parseTo( "> <" );
98          subsystem = cutter.parseTo( "> <" );
99          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 }