/* * Copyright 2011 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.araqne.logfile; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.charset.Charset; import java.nio.file.Files; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.araqne.log.api.V1LogParser; public class ApacheWebLogParser extends V1LogParser { private String logFormat; private final static Map<String, FormatInfo> formats = new HashMap<String, FormatInfo>(); static class FormatInfo { Class<?> clazz; String name; public FormatInfo(Class<?> clazz, String name) { this.clazz = clazz; this.name = name; } } static { set("a", InetAddress.class, "client_ip"); set("A", InetAddress.class, "server_ip"); set("B", Integer.class, "resp_bytes"); set("b", Integer.class, "resp_bytes_clf"); set("C", String.class, "cookie"); set("D", Integer.class, "duration_msec"); set("e", String.class, "env"); set("f", String.class, "file"); set("h", InetAddress.class, "remote_host"); set("H", String.class, "protocol"); set("i", String.class, "req_header"); set("l", String.class, "login"); set("m", String.class, "method"); set("n", String.class, "note"); set("o", String.class, "resp_header"); set("P", Integer.class, "pid"); set("p", Integer.class, "server_port"); set("q", String.class, "query"); set("r", String.class, "request"); set("s", Integer.class, "status"); set("t", Date.class, "date"); set("T", Integer.class, "duration_sec"); set("u", String.class, "user"); set("U", String.class, "url"); set("v", String.class, "canonical_name"); set("V", String.class, "server_name"); set("X", String.class, "connection"); set("I", Integer.class, "rcvd"); set("O", Integer.class, "sent"); } private static void set(String descriptor, Class<?> clazz, String name) { formats.put(descriptor, new FormatInfo(clazz, name)); } public ApacheWebLogParser() { // "common" log format // this("%h %l %u %t \"%r\" %>s %b"); this("%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\""); } public ApacheWebLogParser(String logFormat) { int formatBegin; char f; boolean fFlag = false; char delimiter = 0; for (formatBegin = 0; formatBegin < logFormat.length(); formatBegin++) { f = logFormat.charAt(formatBegin); if (f == '%') { fFlag = true; } else if (fFlag == true) { String token = Character.toString(f); if (f == '>') continue; else if (f == '{') { while (f != '}') { formatBegin++; f = logFormat.charAt(formatBegin); } continue; } if (!formats.containsKey(token)) throw new IllegalArgumentException(); if (formatBegin + 1 < logFormat.length()) { formatBegin++; delimiter = logFormat.charAt(formatBegin); } else break; if (delimiter == '%') throw new IllegalArgumentException(); fFlag = false; } } this.logFormat = logFormat; } public Map<String, Object> parse(String line) { Map<String, Object> params = new HashMap<String, Object>(); params.put("line", line); return parse(params); } @Override public Map<String, Object> parse(Map<String, Object> params) { String line = (String) params.get("line"); Map<String, Object> m = new HashMap<String, Object>(); m.put("logtype", "httpd"); int formatBegin; int lineBegin, lineEnd = 0; boolean fFlag = false; char delimiter = 0; FormatInfo format = null; String content = null; for (formatBegin = 0, lineBegin = 0; formatBegin < logFormat.length(); formatBegin++) { char f = logFormat.charAt(formatBegin); if (f == '%') { fFlag = true; continue; } else if (fFlag == true) { if (f == '>') continue; else if (f == '{') { int begin = formatBegin + 1; int end; while (f != '}') { formatBegin++; f = logFormat.charAt(formatBegin); } end = formatBegin; content = logFormat.substring(begin, end).replace('-', '_').toLowerCase(Locale.ENGLISH); continue; } String token = Character.toString(f); // casting if (formats.containsKey(token)) { format = formats.get(token); } else throw new IllegalArgumentException(); // Get Delimiter if (format.clazz == Date.class) { delimiter = ']'; lineBegin++; } else { if (formatBegin + 1 < logFormat.length()) { delimiter = logFormat.charAt(formatBegin + 1); if (delimiter == '%') { throw new IllegalArgumentException(); } } else delimiter = ' '; } lineEnd = lineBegin; char l = line.charAt(lineEnd); while (l != delimiter) { lineEnd++; if (lineEnd < line.length()) l = line.charAt(lineEnd); else break; } fFlag = false; } else { // input format = "ab %h";// line = "ab 10.0.1.17"; if (line.charAt(lineBegin) == logFormat.charAt(formatBegin)) { lineBegin++; } else { // wrong line variable throw new IllegalArgumentException(Character.toString(line.charAt(lineBegin))); } continue; } // Mapping String key = Character.toString(f); Object value = null; if (format.clazz == String.class) { value = line.substring(lineBegin, lineEnd); } else if (format.clazz == Integer.class) { if (line.substring(lineBegin, lineEnd).equals("-")) value = null; else value = Integer.valueOf(line.substring(lineBegin, lineEnd)); } else if (format.clazz == InetAddress.class) { try { value = InetAddress.getByName(line.substring(lineBegin, lineEnd)); } catch (UnknownHostException e) { return null; } } else { // type == Date.class value = parseDate(line.substring(lineBegin, lineEnd)); lineEnd++; } lineBegin = lineEnd; if (value == null || value.equals("-") || value.equals("")) { if (!key.equals("X")) value = null; } if (content != null) { key = content; content = null; m.put(key, value); } else { m.put(format.name, value); } } return m; } private Date parseDate(String time) { SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss Z", Locale.ENGLISH); try { return dateFormat.parse(time); } catch (ParseException e) { return null; } } }