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 }