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.SimpleDateFormat; 019import java.text.DateFormat; 020import java.text.ParseException; 021import java.util.Date; 022import java.util.regex.Pattern; 023 024import net.sf.logdistiller.LogEvent; 025import net.sf.logdistiller.LogType; 026import net.sf.logdistiller.util.LogEventBuilder; 027import net.sf.logdistiller.util.StringCutter; 028 029/** 030 * Log event for <a href="http://jboss.org/">JBoss</a>'s server logs. By default, the classification rules generated by 031 * the GUI for this type of logs will sort events based on the following attributes: <code>level</code> then 032 * <code>logger</code>. 033 * 034 * @since 0.9 035 */ 036public class JBossLogEvent 037 extends LogEvent 038 implements Comparable<JBossLogEvent> 039{ 040 public final static String ID = "jboss"; 041 042 public final String timestamp; 043 044 public final Date date; 045 046 public final String level; 047 048 public final String logger; 049 050 public final String message; 051 052 public final String throwable; 053 054 public final String throwable_firstLine; 055 056 public final String throwable_class; 057 058 public final static LogType LOGTYPE = new LogType.Basic( ID ); 059 060 private final static DateFormat DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss,SSS" ); 061 062 private final static String[] ATTRIBUTE_NAMES = 063 { "logSource", "timestamp", "timestamp.date", "timestamp.time", "level", "logger", "message", "throwable", 064 "throwable.firstline", "throwable.class" }; 065 066 public final static LogType.Description DESCRIPTION = new Description( (LogType.Basic) LOGTYPE, ATTRIBUTE_NAMES ); 067 068 public JBossLogEvent( LogEvent.Factory factory, String firstLine, String secondLine, String throwable ) 069 throws ParseException 070 { 071 super( factory, ( secondLine == null ) ? firstLine : ( firstLine + Factory.NEWLINE + throwable ) ); 072 timestamp = firstLine.substring( 0, 23 ); 073 date = DATE_FORMAT.parse( timestamp ); 074 level = firstLine.substring( 24, 29 ).trim(); 075 StringCutter cutter = new StringCutter( firstLine.substring( 31 ) ); 076 logger = cutter.parseTo( "] " ); 077 message = cutter.getRemaining(); 078 this.throwable = throwable; 079 throwable_firstLine = ( secondLine == null ) ? "" : secondLine; 080 int index = throwable_firstLine.indexOf( ':' ); 081 throwable_class = ( index > 0 ) ? throwable.substring( 0, index ) : ""; 082 setAttributes( new String[] { factory.getLogSource(), timestamp, timestamp.substring( 0, 10 ), 083 timestamp.substring( 11, 23 ), level, logger, message, throwable, throwable_firstLine, throwable_class } ); 084 } 085 086 public int compareTo( JBossLogEvent o ) 087 { 088 return date.compareTo( o.date ); 089 } 090 091 private static class Description 092 extends LogType.Description 093 { 094 public Description( LogType.Basic logtype, String[] attributeNames ) 095 { 096 super( logtype, attributeNames ); 097 logtype.setDescription( this ); 098 } 099 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}