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
020 import net.sf.logdistiller.LogEvent;
021 import net.sf.logdistiller.LogType;
022 import net.sf.logdistiller.util.StringCutter;
023
024 /**
025 * Log event for commonly used CLF format of web servers, either
026 * <a href="http://httpd.apache.org/docs/2.0/logs.html#common">Common Log Format</a>
027 * or <a href="http://httpd.apache.org/docs/2.0/logs.html#combined">Combined Log Format</a>
028 *
029 * @since 1.1
030 */
031 public class HttpClfLogEvent
032 extends LogEvent
033 {
034 public final static String ID = "http.CLF";
035
036 public final String host;
037
038 public final String identity;
039
040 public final String userid;
041
042 public final String time;
043
044 public final String timeDate;
045
046 public final String timeTime;
047
048 public final String request;
049
050 public final String requestMethod;
051
052 public final String requestUri;
053
054 public final String requestProtocol;
055
056 public final String status;
057
058 public final String size;
059
060 public final String referer;
061
062 public final String userAgent;
063
064 public final String userAgentName;
065
066 public final String userAgentVersion;
067
068 public final String userAgentDetails;
069
070 public final String other;
071
072 public final static LogType LOGTYPE = new LogType.Basic( ID );
073
074 private final static String[] ATTRIBUTE_NAMES = { "logSource", "host", "identity", "userid",
075 "time", "time.date", "time.time",
076 "request", "request.method", "request.uri", "request.protocol",
077 "status", "size", "referer",
078 "user-agent", "user-agent.name", "user-agent.version", "user-agent.details",
079 "other" };
080
081 public final static LogType.Description DESCRIPTION = new Description( (LogType.Basic) LOGTYPE, ATTRIBUTE_NAMES );
082
083 public HttpClfLogEvent( Factory factory, String rawLog )
084 throws ParseException
085 {
086 super( factory, rawLog );
087 StringCutter sc = new StringCutter( rawLog );
088 host = sc.parseTo( " " );
089 identity = sc.parseTo( " " );
090 userid = sc.parseTo( " [" );
091 time = sc.parseTo( "] \"" );
092 timeDate = time.substring( 0, 11 );
093 timeTime = time.substring( 12, 20 );
094 request = sc.parseTo( "\" " );
095 StringCutter req = new StringCutter( request );
096 requestMethod = req.parseTo( " " );
097 requestUri = req.parseTo( " " );
098 requestProtocol = req.getRemaining();
099 status = sc.parseTo( " " );
100 size = sc.parseTo( " \"", false );
101 if ( sc.getRemaining().length() == 0 )
102 { // Common Log Format only
103 referer = userAgent = userAgentName = userAgentVersion = userAgentDetails = other = "";
104 }
105 else
106 { // Combined Log Format
107 referer = sc.parseTo( "\" \"" );
108 userAgent = sc.parseTo( "\"" );
109 StringCutter ua = new StringCutter( userAgent );
110 userAgentName = ua.parseTo( "/", false );
111 userAgentVersion = ua.parseTo( " ", false );
112 ua.parseTo( "(", false );
113 userAgentDetails = ua.parseTo( ")", false );
114 other = sc.getRemaining().trim();
115 }
116 setAttributes( new String[] { factory.getLogSource(), host, identity, userid,
117 time, timeDate, timeTime,
118 request, requestMethod, requestUri, requestProtocol,
119 status, size, referer,
120 userAgent, userAgentName, userAgentVersion, userAgentDetails,
121 other } );
122 }
123
124 private static class Description
125 extends LogType.Description
126 {
127 public Description( LogType.Basic logtype, String[] attributeNames )
128 {
129 super( logtype, attributeNames );
130 logtype.setDescription( this );
131 }
132
133 public LogEvent.Factory newFactory( Reader reader, String logSource )
134 throws IOException
135 {
136 return new Factory( this, reader, logSource );
137 }
138
139 public int getTimestampAttribute()
140 {
141 return 3;
142 }
143
144 public String getDefaultSamplingAttributes()
145 {
146 return "request.uri,user-agent";
147 }
148 }
149
150 private static class Factory
151 extends LogEvent.Factory
152 {
153 private final LineNumberReader reader;
154
155 public Factory( Description description, Reader reader, String logSource )
156 throws FileNotFoundException
157 {
158 super( description, logSource );
159 this.reader = new LineNumberReader( reader );
160 }
161
162 protected LogEvent readNextEvent()
163 throws IOException, ParseException
164 {
165 String curLine = reader.readLine();
166 if ( curLine == null )
167 {
168 // EOF
169 return null;
170 }
171 try
172 {
173 return new HttpClfLogEvent( this, curLine );
174 }
175 catch ( RuntimeException re )
176 {
177 throw new RuntimeException( "error while parsing line '" + curLine + "'", re );
178 }
179 }
180 }
181 }