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.SimpleDateFormat;
19  import java.text.DateFormat;
20  import java.text.ParseException;
21  import java.util.Date;
22  import java.util.regex.Pattern;
23  
24  import net.sf.logdistiller.LogEvent;
25  import net.sf.logdistiller.LogType;
26  import net.sf.logdistiller.util.LogEventBuilder;
27  import net.sf.logdistiller.util.StringCutter;
28  
29  /**
30   * Log event for <a href="http://jboss.org/">JBoss</a>'s server logs. By default, the classification rules generated by
31   * the GUI for this type of logs will sort events based on the following attributes: <code>level</code> then
32   * <code>logger</code>.
33   *
34   * @since 0.9
35   */
36  public class JBossLogEvent
37      extends LogEvent
38      implements Comparable<JBossLogEvent>
39  {
40      public final static String ID = "jboss";
41  
42      public final String timestamp;
43  
44      public final Date date;
45  
46      public final String level;
47  
48      public final String logger;
49  
50      public final String message;
51  
52      public final String throwable;
53  
54      public final String throwable_firstLine;
55  
56      public final String throwable_class;
57  
58      public final static LogType LOGTYPE = new LogType.Basic( ID );
59  
60      private final static DateFormat DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss,SSS" );
61  
62      private final static String[] ATTRIBUTE_NAMES =
63          { "logSource", "timestamp", "timestamp.date", "timestamp.time", "level", "logger", "message", "throwable",
64              "throwable.firstline", "throwable.class" };
65  
66      public final static LogType.Description DESCRIPTION = new Description( (LogType.Basic) LOGTYPE, ATTRIBUTE_NAMES );
67  
68      public JBossLogEvent( LogEvent.Factory factory, String firstLine, String secondLine, String throwable )
69          throws ParseException
70      {
71          super( factory, ( secondLine == null ) ? firstLine : ( firstLine + Factory.NEWLINE + throwable ) );
72          timestamp = firstLine.substring( 0, 23 );
73          date = DATE_FORMAT.parse( timestamp );
74          level = firstLine.substring( 24, 29 ).trim();
75          StringCutter cutter = new StringCutter( firstLine.substring( 31 ) );
76          logger = cutter.parseTo( "] " );
77          message = cutter.getRemaining();
78          this.throwable = throwable;
79          throwable_firstLine = ( secondLine == null ) ? "" : secondLine;
80          int index = throwable_firstLine.indexOf( ':' );
81          throwable_class = ( index > 0 ) ? throwable.substring( 0, index ) : "";
82          setAttributes( new String[] { factory.getLogSource(), timestamp, timestamp.substring( 0, 10 ),
83              timestamp.substring( 11, 23 ), level, logger, message, throwable, throwable_firstLine, throwable_class } );
84      }
85  
86      public int compareTo( JBossLogEvent o )
87      {
88          return date.compareTo( o.date );
89      }
90  
91      private static class Description
92          extends LogType.Description
93      {
94          public Description( LogType.Basic logtype, String[] attributeNames )
95          {
96              super( logtype, attributeNames );
97              logtype.setDescription( this );
98          }
99  
100         public LogEvent.Factory newFactory( Reader reader, String logSource )
101             throws IOException
102         {
103             return new Factory( this, reader, logSource );
104         }
105 
106         public String getDefaultSpecificGroups()
107         {
108             return "  <group id=\"warn\">\n"
109                 + "    <description>WARN events</description>\n"
110                 + "    <condition>\n"
111                 + "      <match attribute=\"level\" type=\"equals\">WARN</match>\n"
112                 + "    </condition>\n"
113                 + "    <report publisher=\"file\"/>\n"
114                 + "    <plugin type=\"sampling\">\n"
115                 + "      <param name=\"attributes\">logger</param>\n"
116                 + "    </plugin>\n"
117                 + "  </group>\n"
118                 + "\n"
119                 + "  <group id=\"error\">\n"
120                 + "    <description>ERROR events</description>\n"
121                 + "    <condition>\n"
122                 + "      <match attribute=\"level\" type=\"equals\">ERROR</match>\n"
123                 + "    </condition>\n"
124                 + "    <report publisher=\"file\"/>\n"
125                 + "    <plugin type=\"sampling\">\n"
126                 + "      <param name=\"attributes\">logger</param>\n"
127                 + "    </plugin>\n"
128                 + "  </group>";
129         }
130 
131         public String getDefaultSamplingAttributes()
132         {
133             return "level,logger";
134         }
135     }
136 
137     private static class Factory
138         extends LogEvent.Factory
139     {
140         private final LineNumberReader reader;
141 
142         private String curLine;
143 
144         public Factory( Description description, Reader reader, String logSource )
145             throws FileNotFoundException
146         {
147             super( description, logSource );
148             this.reader = new LineNumberReader( reader );
149         }
150 
151         private final static Pattern DATE_PATTERN =
152             Pattern.compile( "\\A\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d{3} " );
153 
154         /**
155          * Detect the start of a new log event
156          */
157         protected boolean detectLogEventStart( String line )
158         {
159             // heuristics: detects the beginning of the date...
160             return DATE_PATTERN.matcher( line ).find();
161         }
162 
163         protected LogEvent readNextEvent()
164             throws IOException, ParseException
165         {
166             if ( curLine == null )
167             {
168                 curLine = reader.readLine();
169                 if ( curLine == null )
170                 {
171                     // EOF
172                     return null;
173                 }
174             }
175             String firstLine = curLine;
176             int lineNumber = reader.getLineNumber();
177 
178             String secondLine = null;
179             StringBuffer buffer = new StringBuffer();
180             while ( ( ( curLine = reader.readLine() ) != null ) && ( !detectLogEventStart( curLine ) ) )
181             {
182                 if ( secondLine == null )
183                 {
184                     secondLine = curLine;
185                 }
186                 else
187                 {
188                     buffer.append( NEWLINE );
189                 }
190                 buffer.append( curLine );
191             }
192             return BUILDER.buildLogEvent( this, lineNumber, firstLine, secondLine, buffer.toString() );
193         }
194 
195         private final static LogEventBuilder BUILDER = new LogEventBuilder()
196         {
197             protected LogEvent newEvent( LogEvent.Factory factory, String curLine, Object... objects )
198                 throws ParseException
199             {
200                 return new JBossLogEvent( factory, curLine, (String) objects[0], (String) objects[1] );
201             }
202         };
203     }
204 }