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