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.SimpleDateFormat; 019 import java.text.DateFormat; 020 import java.text.ParseException; 021 import java.util.Date; 022 import java.util.regex.Pattern; 023 024 import net.sf.logdistiller.LogEvent; 025 import net.sf.logdistiller.LogType; 026 import net.sf.logdistiller.util.StringCutter; 027 028 /** 029 * Log event for <a href="http://jboss.org/">JBoss</a>'s server logs. By default, the classification rules generated by 030 * the GUI for this type of logs will sort events based on the following attributes: <code>level</code> then 031 * <code>logger</code>. 032 * 033 * @since 0.9 034 */ 035 public class JBossLogEvent 036 extends LogEvent 037 implements Comparable 038 { 039 public final static String ID = "jboss"; 040 041 public final String timestamp; 042 043 public final Date date; 044 045 public final String level; 046 047 public final String logger; 048 049 public final String message; 050 051 public final String throwable; 052 053 public final String throwable_firstLine; 054 055 public final String throwable_class; 056 057 public final static LogType LOGTYPE = new LogType.Basic( ID ); 058 059 private final static DateFormat DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss,SSS" ); 060 061 private final static String[] ATTRIBUTE_NAMES = 062 { "logSource", "timestamp", "timestamp.date", "timestamp.time", "level", "logger", "message", "throwable", 063 "throwable.firstline", "throwable.class" }; 064 065 public final static LogType.Description DESCRIPTION = new Description( (LogType.Basic) LOGTYPE, ATTRIBUTE_NAMES ); 066 067 public JBossLogEvent( Factory factory, String firstLine, String secondLine, String throwable ) 068 throws ParseException 069 { 070 super( factory, ( secondLine == null ) ? firstLine : ( firstLine + Factory.NEWLINE + throwable ) ); 071 timestamp = firstLine.substring( 0, 23 ); 072 date = DATE_FORMAT.parse( timestamp ); 073 level = firstLine.substring( 24, 29 ).trim(); 074 StringCutter cutter = new StringCutter( firstLine.substring( 31 ) ); 075 logger = cutter.parseTo( "] " ); 076 message = cutter.getRemaining(); 077 this.throwable = throwable; 078 throwable_firstLine = ( secondLine == null ) ? "" : secondLine; 079 int index = throwable_firstLine.indexOf( ':' ); 080 throwable_class = ( index > 0 ) ? throwable.substring( 0, index ) : ""; 081 setAttributes( new String[] { factory.getLogSource(), timestamp, timestamp.substring( 0, 10 ), 082 timestamp.substring( 11, 23 ), level, logger, message, throwable, throwable_firstLine, throwable_class } ); 083 } 084 085 public int compareTo( Object o ) 086 { 087 return date.compareTo( ( (JBossLogEvent) o ).date ); 088 } 089 090 private static class Description 091 extends LogType.Description 092 { 093 public Description( LogType.Basic logtype, String[] attributeNames ) 094 { 095 super( logtype, attributeNames ); 096 logtype.setDescription( this ); 097 } 098 099 public LogEvent.Factory newFactory( Reader reader, String logSource ) 100 throws IOException 101 { 102 return new Factory( this, reader, logSource ); 103 } 104 105 public String getDefaultSpecificGroups() 106 { 107 return " <group id=\"warn\">\n" 108 + " <description>WARN events</description>\n" 109 + " <condition>\n" 110 + " <match attribute=\"level\" type=\"equals\">WARN</match>\n" 111 + " </condition>\n" 112 + " <report publisher=\"file\"/>\n" 113 + " <plugin type=\"sampling\">\n" 114 + " <param name=\"attributes\">logger</param>\n" 115 + " </plugin>\n" 116 + " </group>\n" 117 + "\n" 118 + " <group id=\"error\">\n" 119 + " <description>ERROR events</description>\n" 120 + " <condition>\n" 121 + " <match attribute=\"level\" type=\"equals\">ERROR</match>\n" 122 + " </condition>\n" 123 + " <report publisher=\"file\"/>\n" 124 + " <plugin type=\"sampling\">\n" 125 + " <param name=\"attributes\">logger</param>\n" 126 + " </plugin>\n" 127 + " </group>"; 128 } 129 130 public String getDefaultSamplingAttributes() 131 { 132 return "level,logger"; 133 } 134 } 135 136 private static class Factory 137 extends LogEvent.Factory 138 { 139 private final LineNumberReader reader; 140 141 private String curLine; 142 143 public Factory( Description description, Reader reader, String logSource ) 144 throws FileNotFoundException 145 { 146 super( description, logSource ); 147 this.reader = new LineNumberReader( reader ); 148 } 149 150 private final static Pattern DATE_PATTERN = 151 Pattern.compile( "\\A\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d{3} " ); 152 153 /** 154 * Detect the start of a new log event 155 */ 156 protected boolean detectLogEventStart( String line ) 157 { 158 // heuristics: detects the beginning of the date... 159 return DATE_PATTERN.matcher( line ).find(); 160 } 161 162 protected LogEvent readNextEvent() 163 throws IOException, ParseException 164 { 165 if ( curLine == null ) 166 { 167 curLine = reader.readLine(); 168 if ( curLine == null ) 169 { 170 // EOF 171 return null; 172 } 173 } 174 String firstLine = curLine; 175 String secondLine = null; 176 StringBuffer buffer = new StringBuffer(); 177 while ( ( ( curLine = reader.readLine() ) != null ) && ( !detectLogEventStart( curLine ) ) ) 178 { 179 if ( secondLine == null ) 180 { 181 secondLine = curLine; 182 } 183 else 184 { 185 buffer.append( NEWLINE ); 186 } 187 buffer.append( curLine ); 188 } 189 return new JBossLogEvent( this, firstLine, secondLine, buffer.toString() ); 190 } 191 } 192 }