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.ParseException;
019 import java.util.Arrays;
020 import java.util.Map;
021
022 import org.apache.commons.lang.StringUtils;
023
024 import net.sf.logdistiller.util.BufferingReader;
025 import net.sf.logdistiller.util.csv.CSVParse;
026 import net.sf.logdistiller.util.csv.CSVParser;
027
028 import net.sf.logdistiller.LogEvent;
029 import net.sf.logdistiller.LogType;
030
031 /**
032 * A CSV (see <a href="http://tools.ietf.org/html/rfc4180">RFC-4180</a>) log parser, based on <a
033 * href="http://ostermiller.org/utils/CSV.html">OstermillerUtils</a>. CSV log type supports following parameters:
034 * <ul>
035 * <li><code>attributes</code>: specify the column names (and of course count), starting with <code>logSource</code></li>
036 * <li><code>delimiter</code>: set the column delimiter (default value: <code>','</code>)</li>
037 * <li><code>quote</code>: set the quoting character (default value: <code>'"'</code>)</li>
038 * <li><code>commentStart</code>: set the list of characters a comment line may start with (default value: none)</li>
039 * <!--li><code>escapes</code></li-->
040 * </ul>
041 * By default, the classification rules generated by the GUI for this type of logs won't be able to sort events, as the
042 * log event structure is too generic.
043 *
044 * @see CSVParser
045 * @since 0.9
046 */
047 public class CSVLogEvent
048 extends LogEvent
049 {
050 public final static String ID = "csv";
051
052 public final static LogType LOGTYPE = new CSVLogType();
053
054 public CSVLogEvent( Factory factory, String rawLog, String[] values )
055 throws ParseException
056 {
057 super( factory, rawLog );
058 int count = factory.getDescription().getAttributesCount();
059 String[] attr = new String[count];
060 Arrays.fill( attr, "" );
061 attr[0] = factory.getLogSource();
062 System.arraycopy( values, 0, attr, 1, Math.min( values.length, count - 1 ) );
063 setAttributes( attr );
064 }
065
066 private static class CSVLogType
067 extends LogType
068 {
069 public CSVLogType()
070 {
071 super( CSVLogEvent.ID );
072 }
073
074 public LogType.Description newDescription( Map params )
075 {
076 String attributes = (String) params.get( "attributes" );
077 attributes = ( attributes == null ) ? "" : attributes;
078 if ( !attributes.startsWith( "logSource," ) )
079 {
080 attributes = "logSource," + attributes;
081 }
082 String[] attributeNames = StringUtils.split( attributes, ", " );
083 String attr = (String) params.get( "delimiter" );
084 char delimiter = ( attr == null ) ? ',' : attr.charAt( 0 );
085 attr = (String) params.get( "quote" );
086 char quote = ( attr == null ) ? '"' : attr.charAt( 0 );
087 String commentStart = (String) params.get( "commentStart" );
088 commentStart = ( commentStart == null ) ? "" : commentStart;
089 return new CSVLogEvent.Description( this, attributeNames, delimiter, quote, commentStart );
090 }
091 }
092
093 private static class Description
094 extends LogType.Description
095 {
096 private final char delimiter;
097
098 private final char quote;
099
100 private final String commentStart;
101
102 public Description( LogType logtype, String[] attributeNames, char delimiter, char quote, String commentStart )
103 {
104 super( logtype, attributeNames );
105 this.delimiter = delimiter;
106 this.quote = quote;
107 this.commentStart = commentStart;
108 }
109
110 public LogEvent.Factory newFactory( Reader reader, String logSource )
111 throws IOException
112 {
113 return new Factory( this, reader, logSource );
114 }
115
116 public CSVParse newCSVParser( Reader reader )
117 {
118 CSVParser parser = new CSVParser( reader, delimiter );
119 parser.changeQuote( quote );
120 parser.setCommentStart( commentStart );
121 return parser;
122 }
123
124 public int getTimestampAttribute()
125 {
126 return -1;
127 }
128 }
129
130 private static class Factory
131 extends LogEvent.Factory
132 {
133 private final BufferingReader buffering;
134
135 private final CSVParse parser;
136
137 public Factory( Description description, Reader reader, String logSource )
138 throws FileNotFoundException
139 {
140 super( description, logSource );
141 buffering = new BufferingReader( reader );
142 this.parser = description.newCSVParser( buffering );
143 }
144
145 protected LogEvent readNextEvent()
146 throws IOException, ParseException
147 {
148 int before = parser.getLastCharCount();
149 String[] curLine = parser.getLine();
150 if ( curLine == null )
151 {
152 // EOF
153 return null;
154 }
155 int after = parser.getLastCharCount();
156 String rawLog = StringUtils.chomp( buffering.freeData( after - before ) );
157 return new CSVLogEvent( this, rawLog, curLine );
158 }
159 }
160 }