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.Locale; 023import java.util.regex.Pattern; 024 025import net.sf.logdistiller.LogEvent; 026import net.sf.logdistiller.LogType; 027import net.sf.logdistiller.util.LogEventBuilder; 028 029/** 030 * Oracle Database's <code>alert.log</code> file parser. A typical rule configuration with such log files is: 031 * 032 * <pre> 033 * <group id="ORA"> 034 * <description>ORA-* messages</description> 035 * <condition> 036 * <match attribute="message" type="contains">ORA-</match> 037 * </condition> 038 * <plugin type="sampling"> 039 * <param name="attribute">message</param> 040 * <param name="regexp">(ORA-\d+)</param> 041 * </plugin> 042 * lt;/group> 043 * </pre> 044 * 045 * By default, the classification rules generated by the GUI for this type of logs: 046 * <ol> 047 * <li>will contain a such "ORA" group for events with an ORA- id</li> 048 * <li>but won't be able to sort other events, as the log event structure is too generic (the message has no specific 049 * format).</li> 050 * </ol> 051 * 052 * @since 0.9 053 */ 054public class OracleAlertLogEvent 055 extends LogEvent 056 implements Comparable<OracleAlertLogEvent> 057{ 058 public final static String ID = "oracle-alert"; 059 060 public final String timestamp; 061 062 public final Date date; 063 064 public final String message; 065 066 public final static LogType LOGTYPE = new LogType.Basic( ID ); 067 068 private final static DateFormat DATE_FORMAT = new SimpleDateFormat( "EEE MMM dd HH:mm:ss yyyy", Locale.US ); 069 070 private final static String[] ATTRIBUTE_NAMES = 071 { "logSource", "timestamp", "timestamp.day", "timestamp.time", "message" }; 072 073 public final static LogType.Description DESCRIPTION = new Description( (LogType.Basic) LOGTYPE, ATTRIBUTE_NAMES ); 074 075 public OracleAlertLogEvent( LogEvent.Factory factory, String firstLine, String message ) 076 throws ParseException 077 { 078 super( factory, firstLine + Factory.NEWLINE + message ); 079 timestamp = firstLine; 080 date = DATE_FORMAT.parse( timestamp ); 081 this.message = message; 082 setAttributes( new String[] { factory.getLogSource(), timestamp, 083 timestamp.substring( 0, 10 ) + timestamp.substring( 19, 24 ), timestamp.substring( 11, 19 ), message } ); 084 } 085 086 public int compareTo( OracleAlertLogEvent 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=\"ORA\">\n" 109 + " <description>ORA-* messages</description>\n" 110 + " <condition>\n" 111 + " <match attribute=\"message\" type=\"contains\">ORA-</match>\n" 112 + " </condition>\n" 113 + " <report publisher=\"file\"/>\n" 114 + " <plugin type=\"sampling\">\n" 115 + " <param name=\"attribute\">message</param>\n" 116 + " <param name=\"regexp\">(ORA-\\d+)</param>\n" 117 + " </plugin>\n" 118 + " </group>"; 119 } 120 } 121 122 private static class Factory 123 extends LogEvent.Factory 124 { 125 private final LineNumberReader reader; 126 127 private String curLine; 128 129 private final static Pattern DATE_PATTERN = 130 Pattern.compile( "\\w{3} \\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2} \\d{4}" ); 131 132 public Factory( Description description, Reader reader, String logSource ) 133 throws FileNotFoundException 134 { 135 super( description, logSource ); 136 this.reader = new LineNumberReader( reader ); 137 } 138 139 /** 140 * Detect the start of a new log event 141 */ 142 protected boolean detectLogEventStart( String line ) 143 { 144 return DATE_PATTERN.matcher( line ).matches(); 145 } 146 147 protected LogEvent readNextEvent() 148 throws IOException, ParseException 149 { 150 if ( curLine == null ) 151 { 152 curLine = reader.readLine(); 153 if ( curLine == null ) 154 { 155 // EOF 156 return null; 157 } 158 // beginning of log file does not start with a complete log event with timestamp 159 while ( !detectLogEventStart( curLine ) ) 160 { 161 curLine = reader.readLine(); 162 if ( curLine == null ) 163 { 164 // EOF 165 return null; 166 } 167 } 168 } 169 170 String firstLine = curLine; 171 int lineNumber = reader.getLineNumber(); 172 173 StringBuffer buffer = new StringBuffer(); 174 while ( ( ( curLine = reader.readLine() ) != null ) && ( !detectLogEventStart( curLine ) ) ) 175 { 176 if ( buffer.length() > 0 ) 177 { 178 buffer.append( NEWLINE ); 179 } 180 buffer.append( curLine ); 181 } 182 183 return BUILDER.buildLogEvent( this, lineNumber, firstLine, buffer.toString() ); 184 } 185 186 private final static LogEventBuilder BUILDER = new LogEventBuilder() 187 { 188 protected LogEvent newEvent( LogEvent.Factory factory, String curLine, Object... objects ) 189 throws ParseException 190 { 191 return new OracleAlertLogEvent( factory, curLine, (String) objects[0] ); 192 } 193 }; 194 } 195}