commit e2b46c3e8c86fee3d55ec354d120cefc2616a587 Author: Maxime Chassagneux <4163013@airfrance.fr> Date: Wed Mar 23 15:43:44 2016 +0100 Share Log Parser project diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..c9ef8f9 --- /dev/null +++ b/.classpath @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..731eb43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target/ +/.settings/ diff --git a/.project b/.project new file mode 100644 index 0000000..b9b397c --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + logParser + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..94d41eb --- /dev/null +++ b/pom.xml @@ -0,0 +1,56 @@ + + 4.0.0 + com.airfrance.diqmqs + logParser + 0.0.1-SNAPSHOT + logParser + logParser - send data to influxdb + + + + commons-cli + commons-cli + 1.3.1 + + + io.thekraken + grok + 0.1.3 + + + commons-io + commons-io + 2.4 + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + + + + + com.airfrance.diqmqs.logparser.Cli + + + + + + make-assembly + package + + single + + + + + + + + diff --git a/src/main/java/com/airfrance/diqmqs/logparser/Cli.java b/src/main/java/com/airfrance/diqmqs/logparser/Cli.java new file mode 100644 index 0000000..c67bf9d --- /dev/null +++ b/src/main/java/com/airfrance/diqmqs/logparser/Cli.java @@ -0,0 +1,178 @@ +package com.airfrance.diqmqs.logparser; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +public class Cli { + + public final static String VER = "1.0"; + public static Options options = new Options(); + public static Option help = new Option( "help", "Print this message" ); + public static Option version = new Option( "version", "Print the version information and exit" ); + public static Option application = new Option( "application", true , "Input application name" ); + public static Option patternFilePath = new Option( "pattern", true , "Input pattern path file" ); + public static Option logFile = new Option( "logfile", true , "Input log path files" ); + public static Option regex = new Option( "regex", true , "Name of the regex to apply" ); + public static Option fileParam = new Option( "paramfile", true , "Input a param file" ); + public static Option debugOption = new Option( "debug", "Active debug output message" ); + private static long lastModifiedTime = 0L; + public Cli() { + // TODO Auto-generated constructor stub + } + + public static void main(String[] args) { + + + application.setArgName("application name"); + patternFilePath.setArgName("path to the pattern file"); + logFile.setArgName("path to the logs file"); + fileParam.setArgName("path to the param file"); + + options.addOption(help); + options.addOption(version); + options.addOption(application); + options.addOption(patternFilePath); + options.addOption(logFile); + options.addOption(regex); + options.addOption(debugOption); + options.addOption(fileParam); + + HelpFormatter formatter = new HelpFormatter(); + CommandLineParser parser = new DefaultParser(); + CommandLine cmd = null; + try { + cmd = parser.parse( options, args); + } + catch (ParseException e) { + System.err.println("Command parse error : " + e.getMessage() ); + System.exit(0); + } + + + if(cmd.hasOption("help")) { + formatter.printHelp( "logParser" , options ); + System.exit(0); + } + + if(cmd.hasOption("version")) { + System.out.println("logParser " + Cli.VER ); + System.exit(0); + } + + boolean debug = false; + if(cmd.hasOption("debug")) { + debug = true; + } + + String patternPath = ""; + if(cmd.hasOption("pattern")) { + patternPath = cmd.getOptionValue("pattern"); + } + else + { + System.err.println("patternFilePath application missing"); + System.exit(0); + } + + if(cmd.hasOption("paramfile")) { + String fileParamName = cmd.getOptionValue("paramfile"); + File param = new File(fileParamName); + ParserEngine engine = new ParserEngine(patternPath, debug); + try { + startParserFromFile(param, engine ); + lastModifiedTime = param.lastModified(); + if (debug) { + System.out.println("All parsers started"); + } + while (true) { + try { + Thread.sleep(5000); + if (param.exists()) + { + if ( param.lastModified() != lastModifiedTime ) + { + engine.stopAllParser(); + startParserFromFile(param, engine ); + lastModifiedTime = param.lastModified(); + } + } + + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } catch (FileNotFoundException e) { + System.err.println("Execption : " + e.getMessage()); + System.exit(0); + } + } + else + { + String applicationName = ""; + if(cmd.hasOption("application")) { + applicationName = cmd.getOptionValue("application"); + } + else + { + System.err.println("Option application missing"); + System.exit(0); + } + + String[] regexName = null; + if(cmd.hasOption("regex")) { + regexName = cmd.getOptionValues("regex"); + } + else + { + System.err.println("regex application missing"); + System.exit(0); + } + + if(cmd.hasOption("logfile")) { + + ParserEngine engine = new ParserEngine(patternPath, debug); + String[] filesName = cmd.getOptionValues("logfile"); + for (int i = 0; i < filesName.length ; i++) { + File f = new File (filesName[i]); + engine.addNewParser(f, regexName[i], applicationName); + } + + + } + } + + } + + + static void startParserFromFile(File file, ParserEngine engine) throws FileNotFoundException { + + Scanner scanner = new Scanner(file); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (!line.startsWith("#")) + { + String[] arguments = line.split("\\t"); + String applicationName = arguments[0].toLowerCase(); + Paths paths = new Paths("/", arguments[1]); + String regexName = arguments[2]; + for (File f : paths.getFiles()) { + engine.addNewParser(f, regexName, applicationName); + } + + } + } + scanner.close(); + + } + +} diff --git a/src/main/java/com/airfrance/diqmqs/logparser/GlobScanner.java b/src/main/java/com/airfrance/diqmqs/logparser/GlobScanner.java new file mode 100644 index 0000000..13c0e2f --- /dev/null +++ b/src/main/java/com/airfrance/diqmqs/logparser/GlobScanner.java @@ -0,0 +1,271 @@ +package com.airfrance.diqmqs.logparser; + + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.airfrance.diqmqs.logparser.GlobScanner.Pattern; + +class GlobScanner { + private final File rootDir; + private final List matches = new ArrayList(128); + + public GlobScanner (File rootDir, List includes, List excludes, boolean ignoreCase) { + if (rootDir == null) throw new IllegalArgumentException("rootDir cannot be null."); + if (!rootDir.exists()) throw new IllegalArgumentException("Directory does not exist: " + rootDir); + if (!rootDir.isDirectory()) throw new IllegalArgumentException("File must be a directory: " + rootDir); + try { + rootDir = rootDir.getCanonicalFile(); + } catch (IOException ex) { + throw new RuntimeException("OS error determining canonical path: " + rootDir, ex); + } + this.rootDir = rootDir; + + if (includes == null) throw new IllegalArgumentException("includes cannot be null."); + if (excludes == null) throw new IllegalArgumentException("excludes cannot be null."); + + if (includes.isEmpty()) includes.add("**"); + List includePatterns = new ArrayList(includes.size()); + for (String include : includes) + includePatterns.add(new Pattern(include, ignoreCase)); + + List allExcludePatterns = new ArrayList(excludes.size()); + for (String exclude : excludes) + allExcludePatterns.add(new Pattern(exclude, ignoreCase)); + + scanDir(rootDir, includePatterns); + + if (!allExcludePatterns.isEmpty()) { + // For each file, see if any exclude patterns match. + outerLoop: + // + for (Iterator matchIter = matches.iterator(); matchIter.hasNext();) { + String filePath = (String)matchIter.next(); + List excludePatterns = new ArrayList(allExcludePatterns); + try { + // Shortcut for excludes that are "**/XXX", just check file name. + for (Iterator excludeIter = excludePatterns.iterator(); excludeIter.hasNext();) { + Pattern exclude = (Pattern)excludeIter.next(); + if (exclude.values.length == 2 && exclude.values[0].equals("**")) { + exclude.incr(); + String fileName = filePath.substring(filePath.lastIndexOf(File.separatorChar) + 1); + if (exclude.matches(fileName)) { + matchIter.remove(); + continue outerLoop; + } + excludeIter.remove(); + } + } + // Get the file names after the root dir. + String[] fileNames = filePath.split("\\" + File.separator); + for (String fileName : fileNames) { + for (Iterator excludeIter = excludePatterns.iterator(); excludeIter.hasNext();) { + Pattern exclude = (Pattern)excludeIter.next(); + if (!exclude.matches(fileName)) { + excludeIter.remove(); + continue; + } + exclude.incr(fileName); + if (exclude.wasFinalMatch()) { + // Exclude pattern matched. + matchIter.remove(); + continue outerLoop; + } + } + // Stop processing the file if none of the exclude patterns matched. + if (excludePatterns.isEmpty()) continue outerLoop; + } + } finally { + for (Pattern exclude : allExcludePatterns) + exclude.reset(); + } + } + } + } + + private void scanDir (File dir, List includes) { + if (!dir.canRead()) return; + + // See if patterns are specific enough to avoid scanning every file in the directory. + boolean scanAll = false; + for (Pattern include : includes) { + if (include.value.indexOf('*') != -1 || include.value.indexOf('?') != -1) { + scanAll = true; + break; + } + } + + if (!scanAll) { + // If not scanning all the files, we know exactly which ones to include. + List matchingIncludes = new ArrayList(1); + for (Pattern include : includes) { + if (matchingIncludes.isEmpty()) + matchingIncludes.add(include); + else + matchingIncludes.set(0, include); + process(dir, include.value, matchingIncludes); + } + } else { + // Scan every file. + for (String fileName : dir.list()) { + // Get all include patterns that match. + List matchingIncludes = new ArrayList(includes.size()); + for (Pattern include : includes) + if (include.matches(fileName)) matchingIncludes.add(include); + if (matchingIncludes.isEmpty()) continue; + process(dir, fileName, matchingIncludes); + } + } + } + + private void process (File dir, String fileName, List matchingIncludes) { + // Increment patterns that need to move to the next token. + boolean isFinalMatch = false; + List incrementedPatterns = new ArrayList(); + for (Iterator iter = matchingIncludes.iterator(); iter.hasNext();) { + Pattern include = (Pattern)iter.next(); + if (include.incr(fileName)) { + incrementedPatterns.add(include); + if (include.isExhausted()) iter.remove(); + } + if (include.wasFinalMatch()) isFinalMatch = true; + } + + File file = new File(dir, fileName); + if (isFinalMatch) { + int length = rootDir.getPath().length(); + if (!rootDir.getPath().endsWith(File.separator)) length++; // Lose starting slash. + matches.add(file.getPath().substring(length)); + } + if (!matchingIncludes.isEmpty() && file.isDirectory()) scanDir(file, matchingIncludes); + + // Decrement patterns. + for (Pattern include : incrementedPatterns) + include.decr(); + } + + public List matches () { + return matches; + } + + public File rootDir () { + return rootDir; + } + + static class Pattern { + String value; + boolean ignoreCase; + final String[] values; + + private int index; + + Pattern (String pattern, boolean ignoreCase) { + this.ignoreCase = ignoreCase; + + pattern = pattern.replace('\\', '/'); + pattern = pattern.replaceAll("\\*\\*[^/]", "**/*"); + pattern = pattern.replaceAll("[^/]\\*\\*", "*/**"); + if (ignoreCase) pattern = pattern.toLowerCase(); + + values = pattern.split("/"); + value = values[0]; + } + + boolean matches (String fileName) { + if (value.equals("**")) return true; + + if (ignoreCase) fileName = fileName.toLowerCase(); + + // Shortcut if no wildcards. + if (value.indexOf('*') == -1 && value.indexOf('?') == -1) return fileName.equals(value); + + int i = 0, j = 0; + while (i < fileName.length() && j < value.length() && value.charAt(j) != '*') { + if (value.charAt(j) != fileName.charAt(i) && value.charAt(j) != '?') return false; + i++; + j++; + } + + // If reached end of pattern without finding a * wildcard, the match has to fail if not same length. + if (j == value.length()) return fileName.length() == value.length(); + + int cp = 0; + int mp = 0; + while (i < fileName.length()) { + if (j < value.length() && value.charAt(j) == '*') { + if (j++ >= value.length()) return true; + mp = j; + cp = i + 1; + } else if (j < value.length() && (value.charAt(j) == fileName.charAt(i) || value.charAt(j) == '?')) { + j++; + i++; + } else { + j = mp; + i = cp++; + } + } + + // Handle trailing asterisks. + while (j < value.length() && value.charAt(j) == '*') + j++; + + return j >= value.length(); + } + + String nextValue () { + if (index + 1 == values.length) return null; + return values[index + 1]; + } + + boolean incr (String fileName) { + if (value.equals("**")) { + if (index == values.length - 1) return false; + incr(); + if (matches(fileName)) + incr(); + else { + decr(); + return false; + } + } else + incr(); + return true; + } + + void incr () { + index++; + if (index >= values.length) + value = null; + else + value = values[index]; + } + + void decr () { + index--; + if (index > 0 && values[index - 1].equals("**")) index--; + value = values[index]; + } + + void reset () { + index = 0; + value = values[0]; + } + + boolean isExhausted () { + return index >= values.length; + } + + boolean isLast () { + return index >= values.length - 1; + } + + boolean wasFinalMatch () { + return isExhausted() || (isLast() && value.equals("**")); + } + } + + +} diff --git a/src/main/java/com/airfrance/diqmqs/logparser/Parser.java b/src/main/java/com/airfrance/diqmqs/logparser/Parser.java new file mode 100644 index 0000000..596af83 --- /dev/null +++ b/src/main/java/com/airfrance/diqmqs/logparser/Parser.java @@ -0,0 +1,127 @@ +package com.airfrance.diqmqs.logparser; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Map; + +import org.apache.commons.io.input.Tailer; +import org.apache.commons.io.input.TailerListenerAdapter; +import org.apache.commons.lang3.StringUtils; + +import oi.thekraken.grok.api.Grok; +import oi.thekraken.grok.api.Match; +import oi.thekraken.grok.api.exception.GrokException; + +public class Parser extends TailerListenerAdapter { + + private Grok grok = null; + + private String fileName = ""; + private String pathName = ""; + private String hostname = ""; + private String application = ""; + private ParserEngine engine = null; + + + public Parser(String application, String regexName, ParserEngine engine) { + + try { + if (engine.isDebug()) { + System.out.println("Create Grok with regex name : " + regexName); + } + grok = Grok.create(engine.getPatternPath()); + grok.compile("%{" + regexName + "}"); + } catch (GrokException e) { + e.printStackTrace(); + } + + try { + hostname = InetAddress.getLocalHost().getHostName().split("\\.")[0]; + } catch (UnknownHostException e) { + e.printStackTrace(); + } + this.application = application; + this.engine = engine; + } + + @Override + public void init(Tailer tailer) { + super.init(tailer); + fileName = tailer.getFile().getName(); + pathName = tailer.getFile().getParent(); + if (engine.isDebug()) { + System.out.println("Init tailer on file : " + pathName + "/" + fileName ); + } + } + + public void handle(String line) { + + Match gm = grok.match(line); + gm.captures(); + Map result = gm.toMap(); + if ( result.size() > 0 ) + { + if (engine.isDebug()) { + System.out.println("Match OK "); + } + + StringBuffer sb = new StringBuffer(); + sb.append("log"); + //Tag + sb.append(",host=" + hostname); + sb.append(",application=" + application); + sb.append(",file=" + sanitizeString(fileName) ); + sb.append(",path=" + sanitizeString(pathName) ); + + String tagName = null; + String tagValue = null; + String value = null; + + // iterate on all match pattern + for (Map.Entry entry : result.entrySet() ) + { + tagName = entry.getKey(); + // Keep only key with lowercase + if ( StringUtils.isAllLowerCase( tagName ) ) + { + tagValue = entry.getValue().toString(); + // if key name is 'value', it's not a tag, but a field + if ( ! tagName.equalsIgnoreCase("value") ) { + // check if tag value is not empty + if (!tagValue.equalsIgnoreCase("") ) { + sb.append("," + tagName + "=" + sanitizeString( tagValue ) ); + } + } + else + { + value = tagValue; + } + } + + } + sb.append(" "); + //Field + if ( StringUtils.isNumeric(value) ) { + sb.append("value=" + value); + } + else + { + sb.append("value=1"); + } + + sb.append(" " + System.currentTimeMillis() + "000000"); + + // Add to the queue + engine.addToQueue(sb.toString()); + + if (engine.isDebug()) { + System.out.println(gm.toJson()); + } + } + } + + String sanitizeString(String s) + { + return s.trim().replaceAll(" ", "\\\\ ").replaceAll(",", "\\\\,").replaceAll("=", "\\\\="); + } +} diff --git a/src/main/java/com/airfrance/diqmqs/logparser/ParserEngine.java b/src/main/java/com/airfrance/diqmqs/logparser/ParserEngine.java new file mode 100644 index 0000000..1acc091 --- /dev/null +++ b/src/main/java/com/airfrance/diqmqs/logparser/ParserEngine.java @@ -0,0 +1,155 @@ +package com.airfrance.diqmqs.logparser; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.input.Tailer; +import org.apache.commons.io.input.TailerListener; + +public class ParserEngine implements Runnable{ + + private static final long ONE_SECOND = 1L; + private static final int BATCH_SIZE_MAX = 10; + final private String database = "qualif"; + final long delay = 500; + private ArrayList threadsParser = null; + static BlockingDeque queue = new LinkedBlockingDeque(1000); + private boolean debug = false; + private String patternPath = ""; + private ScheduledExecutorService scheduler; + @SuppressWarnings("unused") + private ScheduledFuture timerHandle; + + public ParserEngine(String patternPath, boolean debug) { + threadsParser = new ArrayList(); + this.debug = debug; + this.patternPath = patternPath; + scheduler = Executors.newScheduledThreadPool(1); + // Don't change this as metrics are per second + this.timerHandle = scheduler.scheduleAtFixedRate( this, ONE_SECOND, ONE_SECOND, TimeUnit.SECONDS); + + if (debug) { + System.out.println("Create ParserEngine with pattern file : " + patternPath); + System.out.println("Schedule sender is set to " + ONE_SECOND + " second(s)"); + } + } + + void addNewParser(File f , String regexName, String application ) { + + TailerListener listener = new Parser(application, regexName, this); + Tailer tailer = new Tailer(f, listener, delay, true); + Thread thread = new Thread(tailer); + thread.setDaemon(true); + thread.setName("Parser - " + threadsParser.size() ); + thread.start(); + threadsParser.add(thread); + if (debug) { + System.out.println("Thread Parser - " + threadsParser.size() + " started - file : " + f.getName()); + } + + } + + void stopAllParser() { + for (Thread t : threadsParser) { + t.interrupt(); + if (debug) { + System.out.println("Stop Thread " + t.getName() ); + } + } + threadsParser.clear(); + } + + // Read data from the Queue and send it to influxdb + public void run() { + + StringBuilder postData = new StringBuilder(); + for (int i = 0 ; i < BATCH_SIZE_MAX; i++) + { + try { + String message = queue.poll( 50, TimeUnit.MILLISECONDS); + if (message != null) { + postData.append( message + "\n" ); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + try { + if (postData.length() > 0) { + sendMetricToInfluxdb(postData.toString()); + } + } catch (IOException e) { + e.printStackTrace(); + } + + } + + public boolean sendMetricToInfluxdb(String postData) throws IOException { + + URL url = new URL("http://diqmqs.airfrance.fr/influxdb_query/write?rp=one_week&db=" + database); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setRequestMethod("POST"); + connection.setRequestProperty("User-Agent", "LogParser/1.0"); + connection.setRequestProperty("Authorization", "Basic cXVhbGlmOmRpcW0wMQ=="); + connection.setRequestProperty("Content-Length", String.valueOf(postData.length())); + + // Write data + OutputStream os = connection.getOutputStream(); + if (this.isDebug()) { + System.out.println("Send : " + postData ); + } + os.write(postData.getBytes()); + + int HttpResult = connection.getResponseCode(); + if (HttpResult == 204) { + return true; + } else { + if (this.isDebug()) { + System.err.println(connection.getResponseCode() + " " + connection.getResponseMessage()); + } + return false; + } + } + + public void addToQueue(String s) { + + try { + queue.put(s); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + + public boolean isDebug() { + return debug; + } + + + public void setDebug(boolean debug) { + this.debug = debug; + } + + + public String getPatternPath() { + return patternPath; + } + + + public void setPatternPath(String patternPath) { + this.patternPath = patternPath; + } + +} diff --git a/src/main/java/com/airfrance/diqmqs/logparser/Paths.java b/src/main/java/com/airfrance/diqmqs/logparser/Paths.java new file mode 100644 index 0000000..1e151ce --- /dev/null +++ b/src/main/java/com/airfrance/diqmqs/logparser/Paths.java @@ -0,0 +1,304 @@ +package com.airfrance.diqmqs.logparser; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +/** Collects filesystem paths using wildcards, preserving the directory structure. Copies, deletes, and zips paths. */ +public class Paths implements Iterable { + + + static private List defaultGlobExcludes; + + final HashSet paths = new HashSet(32); + + /** Creates an empty Paths object. */ + public Paths () { + } + + /** Creates a Paths object and calls {@link #glob(String, String[])} with the specified arguments. */ + public Paths (String dir, String... patterns) { + glob(dir, patterns); + } + + /** Creates a Paths object and calls {@link #glob(String, List)} with the specified arguments. */ + public Paths (String dir, List patterns) { + glob(dir, patterns); + } + + private Paths glob (String dir, boolean ignoreCase, String... patterns) { + if (dir == null) dir = "."; + if (patterns != null && patterns.length == 0) { + String[] split = dir.split("\\|"); + if (split.length > 1) { + dir = split[0]; + patterns = new String[split.length - 1]; + for (int i = 1, n = split.length; i < n; i++) + patterns[i - 1] = split[i]; + } + } + File dirFile = new File(dir); + if (!dirFile.exists()) return this; + + List includes = new ArrayList(); + List excludes = new ArrayList(); + if (patterns != null) { + for (String pattern : patterns) { + if (pattern.charAt(0) == '!') + excludes.add(pattern.substring(1)); + else + includes.add(pattern); + } + } + if (includes.isEmpty()) includes.add("**"); + + if (defaultGlobExcludes != null) excludes.addAll(defaultGlobExcludes); + + GlobScanner scanner = new GlobScanner(dirFile, includes, excludes, ignoreCase); + String rootDir = scanner.rootDir().getPath().replace('\\', '/'); + if (!rootDir.endsWith("/")) rootDir += '/'; + for (String filePath : scanner.matches()) + paths.add(new Path(rootDir, filePath)); + return this; + } + + /** Collects all files and directories in the specified directory matching the wildcard patterns. + * @param dir The directory containing the paths to collect. If it does not exist, no paths are collected. If null, "." is + * assumed. + * @param patterns The wildcard patterns of the paths to collect or exclude. Patterns may optionally contain wildcards + * represented by asterisks and question marks. If empty or omitted then the dir parameter is split on the "|" + * character, the first element is used as the directory and remaining are used as the patterns. If null, ** is + * assumed (collects all paths).
+ *
+ * A single question mark (?) matches any single character. Eg, something? collects any path that is named + * "something" plus any character.
+ *
+ * A single asterisk (*) matches any characters up to the next slash (/). Eg, *\*\something* collects any path that + * has two directories of any name, then a file or directory that starts with the name "something".
+ *
+ * A double asterisk (**) matches any characters. Eg, **\something\** collects any path that contains a directory + * named "something".
+ *
+ * A pattern starting with an exclamation point (!) causes paths matched by the pattern to be excluded, even if other + * patterns would select the paths. */ + public Paths glob (String dir, String... patterns) { + return glob(dir, false, patterns); + } + + /** Case insensitive glob. + * @see #glob(String, String...) */ + public Paths globIgnoreCase (String dir, String... patterns) { + return glob(dir, true, patterns); + } + + /** Case sensitive glob. + * @see #glob(String, String...) */ + public Paths glob (String dir, List patterns) { + if (patterns == null) throw new IllegalArgumentException("patterns cannot be null."); + glob(dir, false, patterns.toArray(new String[patterns.size()])); + return this; + } + + /** Case insensitive glob. + * @see #glob(String, String...) */ + public Paths globIgnoreCase (String dir, List patterns) { + if (patterns == null) throw new IllegalArgumentException("patterns cannot be null."); + glob(dir, true, patterns.toArray(new String[patterns.size()])); + return this; + } + + public int count () { + return paths.size(); + } + + public boolean isEmpty () { + return paths.isEmpty(); + } + + /** Returns the absolute paths delimited by the specified character. */ + public String toString (String delimiter) { + StringBuffer buffer = new StringBuffer(256); + for (String path : getPaths()) { + if (buffer.length() > 0) buffer.append(delimiter); + buffer.append(path); + } + return buffer.toString(); + } + + /** Returns the absolute paths delimited by commas. */ + public String toString () { + return toString(", "); + } + + /** Returns a Paths object containing the paths that are files, as if each file were selected from its parent directory. */ + public Paths flatten () { + Paths newPaths = new Paths(); + for (Path path : paths) { + File file = path.file(); + if (file.isFile()) newPaths.paths.add(new Path(file.getParent(), file.getName())); + } + return newPaths; + } + + /** Returns a Paths object containing the paths that are files. */ + public Paths filesOnly () { + Paths newPaths = new Paths(); + for (Path path : paths) { + if (path.file().isFile()) newPaths.paths.add(path); + } + return newPaths; + } + + /** Returns a Paths object containing the paths that are directories. */ + public Paths dirsOnly () { + Paths newPaths = new Paths(); + for (Path path : paths) { + if (path.file().isDirectory()) newPaths.paths.add(path); + } + return newPaths; + } + + /** Returns the paths as File objects. */ + public List getFiles () { + return getFiles(new ArrayList(paths)); + } + + private ArrayList getFiles (List paths) { + ArrayList files = new ArrayList(paths.size()); + for (Path path : paths) + files.add(path.file()); + return files; + } + + /** Returns the portion of the path after the root directory where the path was collected. */ + public List getRelativePaths () { + ArrayList stringPaths = new ArrayList(paths.size()); + for (Path path : paths) + stringPaths.add(path.name); + return stringPaths; + } + + /** Returns the full paths. */ + public List getPaths () { + ArrayList stringPaths = new ArrayList(paths.size()); + for (File file : getFiles()) + stringPaths.add(file.getPath()); + return stringPaths; + } + + /** Returns the paths' filenames. */ + public List getNames () { + ArrayList stringPaths = new ArrayList(paths.size()); + for (File file : getFiles()) + stringPaths.add(file.getName()); + return stringPaths; + } + + /** Adds a single path to this Paths object. */ + public Paths addFile (String fullPath) { + File file = new File(fullPath); + String parent = file.getParent(); + paths.add(new Path(parent == null ? "" : parent, file.getName())); + return this; + } + + /** Adds a single path to this Paths object. */ + public Paths add (String dir, String name) { + paths.add(new Path(dir, name)); + return this; + } + + /** Adds all paths from the specified Paths object to this Paths object. */ + public void add (Paths paths) { + this.paths.addAll(paths.paths); + } + + /** Iterates over the absolute paths. The iterator supports the remove method. */ + public Iterator iterator () { + return new Iterator() { + private Iterator iter = paths.iterator(); + + public void remove () { + iter.remove(); + } + + public String next () { + return iter.next().absolute(); + } + + public boolean hasNext () { + return iter.hasNext(); + } + }; + } + + /** Iterates over the paths as File objects. The iterator supports the remove method. */ + public Iterator fileIterator () { + return new Iterator() { + private Iterator iter = paths.iterator(); + + public void remove () { + iter.remove(); + } + + public File next () { + return iter.next().file(); + } + + public boolean hasNext () { + return iter.hasNext(); + } + }; + } + + static private final class Path { + public final String dir; + public final String name; + + public Path (String dir, String name) { + if (dir.length() > 0 && !dir.endsWith("/")) dir += "/"; + this.dir = dir; + this.name = name; + } + + public String absolute () { + return dir + name; + } + + public File file () { + return new File(dir, name); + } + + public int hashCode () { + final int prime = 31; + int result = 1; + result = prime * result + ((dir == null) ? 0 : dir.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + public boolean equals (Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Path other = (Path)obj; + if (dir == null) { + if (other.dir != null) return false; + } else if (!dir.equals(other.dir)) return false; + if (name == null) { + if (other.name != null) return false; + } else if (!name.equals(other.name)) return false; + return true; + } + } + + /** Sets the exclude patterns that will be used in addition to the excludes specified for all glob searches. */ + static public void setDefaultGlobExcludes (String... defaultGlobExcludes) { + Paths.defaultGlobExcludes = Arrays.asList(defaultGlobExcludes); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/airfrance/diqmqs/logparser/package-info.java b/src/main/java/com/airfrance/diqmqs/logparser/package-info.java new file mode 100644 index 0000000..559d77d --- /dev/null +++ b/src/main/java/com/airfrance/diqmqs/logparser/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author 4163013 + * + */ +package com.airfrance.diqmqs.logparser; \ No newline at end of file diff --git a/src/main/java/com/airfrance/diqmqs/logparser/patterns b/src/main/java/com/airfrance/diqmqs/logparser/patterns new file mode 100644 index 0000000..8c7dffe --- /dev/null +++ b/src/main/java/com/airfrance/diqmqs/logparser/patterns @@ -0,0 +1,107 @@ + +USERNAME [a-zA-Z0-9._-]+ +USER %{USERNAME:UNWANTED} +INT (?:[+-]?(?:[0-9]+)) +BASE10NUM (?[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))) +NUMBER (?:%{BASE10NUM:UNWANTED}) +BASE16NUM (?(?"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``)) +UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12} + +# Networking +MAC (?:%{CISCOMAC:UNWANTED}|%{WINDOWSMAC:UNWANTED}|%{COMMONMAC:UNWANTED}) +CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4}) +WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2}) +COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}) +IPV6 ((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)? +IPV4 (?/(?>[\w_%!$@:.,~-]+|\\.)*)+ +#UNIXPATH (?[A-Za-z]+:|\\)(?:\\[^\\?*]*)+ +URIPROTO [A-Za-z]+(\+[A-Za-z+]+)? +URIHOST %{IPORHOST}(?::%{POSINT:port})? +# uripath comes loosely from RFC1738, but mostly from what Firefox +# doesn't turn into %XX +URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*)+ +#URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)? +URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]* +URIPATHPARAM %{URIPATH}(?:%{URIPARAM})? +URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})? + +# Months: January, Feb, 3, 03, 12, December +MONTH \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b +MONTHNUM (?:0?[1-9]|1[0-2]) +MONTHNUM2 (?:0[1-9]|1[0-2]) +MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) + +# Days: Monday, Tue, Thu, etc... +DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?) + +# Years? +YEAR (?>\d\d){1,2} +# Time: HH:MM:SS +#TIME \d{2}:\d{2}(?::\d{2}(?:\.\d+)?)? +# I'm still on the fence about using grok to perform the time match, +# since it's probably slower. +# TIME %{POSINT<24}:%{POSINT<60}(?::%{POSINT<60}(?:\.%{POSINT})?)? +HOUR (?:2[0123]|[01]?[0-9]) +MINUTE (?:[0-5][0-9]) +# '60' is a leap second in most time standards and thus is valid. +SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?) +TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9]) +# datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it) +DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR} +DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR} +ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE})) +ISO8601_SECOND (?:%{SECOND}|60) +TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}? +DATE %{DATE_US}|%{DATE_EU} +DATESTAMP %{DATE}[- ]%{TIME} +TZ (?:[PMCE][SD]T|UTC) +DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ} +DATESTAMP_RFC2822 %{DAY}, %{MONTHDAY} %{MONTH} %{YEAR} %{TIME} %{ISO8601_TIMEZONE} +DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR} +DATESTAMP_EVENTLOG %{YEAR}%{MONTHNUM2}%{MONTHDAY}%{HOUR}%{MINUTE}%{SECOND} + +# Syslog Dates: Month Day HH:MM:SS +SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME} +PROG (?:[\w._/%-]+) +SYSLOGPROG %{PROG:program}(?:\[%{POSINT:pid}\])? +SYSLOGHOST %{IPORHOST} +SYSLOGFACILITY <%{NONNEGINT:facility}.%{NONNEGINT:priority}> +HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT} + +# Shortcuts +QS %{QUOTEDSTRING:UNWANTED} + +# Log formats +SYSLOGBASE %{SYSLOGTIMESTAMP:timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}: + +MESSAGESLOG %{SYSLOGBASE} %{DATA} + +COMMONAPACHELOG %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-) +COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent} +COMMONAPACHELOG_DATATYPED %{IPORHOST:clientip} %{USER:ident;boolean} %{USER:auth} \[%{HTTPDATE:timestamp;date;dd/MMM/yyyy:HH:mm:ss Z}\] "(?:%{WORD:verb;string} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion;float})?|%{DATA:rawrequest})" %{NUMBER:response;int} (?:%{NUMBER:bytes;long}|-) + + +# Log Levels +LOGLEVEL ([A|a]lert|ALERT|[T|t]race|TRACE|[D|d]ebug|DEBUG|[N|n]otice|NOTICE|[I|i]nfo|INFO|[W|w]arn?(?:ing)?|WARN?(?:ING)?|[E|e]rr?(?:or)?|ERR?(?:OR)?|[C|c]rit?(?:ical)?|CRIT?(?:ICAL)?|[F|f]atal|FATAL|[S|s]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?) \ No newline at end of file diff --git a/src/main/resources/patterns b/src/main/resources/patterns new file mode 100644 index 0000000..6d03514 --- /dev/null +++ b/src/main/resources/patterns @@ -0,0 +1,111 @@ + +USERNAME [a-zA-Z0-9._-]+ +USER %{USERNAME:UNWANTED} +INT (?:[+-]?(?:[0-9]+)) +BASE10NUM (?[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+))) +NUMBER (?:%{BASE10NUM:UNWANTED}) +BASE16NUM (?(?"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``)) +UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12} + +# Networking +MAC (?:%{CISCOMAC:UNWANTED}|%{WINDOWSMAC:UNWANTED}|%{COMMONMAC:UNWANTED}) +CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4}) +WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2}) +COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}) +IPV6 ((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)? +IPV4 (?/(?>[\w_%!$@:.,~-]+|\\.)*)+ +#UNIXPATH (?[A-Za-z]+:|\\)(?:\\[^\\?*]*)+ +URIPROTO [A-Za-z]+(\+[A-Za-z+]+)? +URIHOST %{IPORHOST}(?::%{POSINT:port})? +# uripath comes loosely from RFC1738, but mostly from what Firefox +# doesn't turn into %XX +URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*)+ +#URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)? +URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]* +URIPATHPARAM %{URIPATH}(?:%{URIPARAM})? +URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})? + +# Months: January, Feb, 3, 03, 12, December +MONTH \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b +MONTHNUM (?:0?[1-9]|1[0-2]) +MONTHNUM2 (?:0[1-9]|1[0-2]) +MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9]) + +# Days: Monday, Tue, Thu, etc... +DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?) + +# Years? +YEAR (?>\d\d){1,2} +# Time: HH:MM:SS +#TIME \d{2}:\d{2}(?::\d{2}(?:\.\d+)?)? +# I'm still on the fence about using grok to perform the time match, +# since it's probably slower. +# TIME %{POSINT<24}:%{POSINT<60}(?::%{POSINT<60}(?:\.%{POSINT})?)? +HOUR (?:2[0123]|[01]?[0-9]) +MINUTE (?:[0-5][0-9]) +# '60' is a leap second in most time standards and thus is valid. +SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?) +TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9]) +# datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it) +DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR} +DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR} +DATE_JMETER %{YEAR}[./-]%{MONTHNUM}[./-]%{MONTHDAY} +ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE})) +ISO8601_SECOND (?:%{SECOND}|60) +TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}? +DATE %{DATE_US}|%{DATE_EU} +DATESTAMP %{DATE}[- ]%{TIME} +TZ (?:[PMCE][SD]T|UTC) +DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ} +DATESTAMP_RFC2822 %{DAY}, %{MONTHDAY} %{MONTH} %{YEAR} %{TIME} %{ISO8601_TIMEZONE} +DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR} +DATESTAMP_EVENTLOG %{YEAR}%{MONTHNUM2}%{MONTHDAY}%{HOUR}%{MINUTE}%{SECOND} + +# Syslog Dates: Month Day HH:MM:SS +SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME} +PROG (?:[\w._/%-]+) +SYSLOGPROG %{PROG:program}(?:\[%{POSINT:pid}\])? +SYSLOGHOST %{IPORHOST} +SYSLOGFACILITY <%{NONNEGINT:facility}.%{NONNEGINT:priority}> +HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT} + +# Shortcuts +QS %{QUOTEDSTRING:UNWANTED} + +# Log formats +SYSLOGBASE %{SYSLOGTIMESTAMP:timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}: + +MESSAGESLOG %{SYSLOGBASE} %{DATA} + +TYPE [E|e]rr?(?:or)?|ERR?(?:OR)? +MESSAGE .* + +COMMONAPACHELOG %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-) +COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent} +COMMONAPACHELOG_DATATYPED %{IPORHOST:clientip} %{USER:ident;boolean} %{USER:auth} \[%{HTTPDATE:timestamp;date;dd/MMM/yyyy:HH:mm:ss Z}\] "(?:%{WORD:verb;string} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion;float})?|%{DATA:rawrequest})" %{NUMBER:response;int} (?:%{NUMBER:bytes;long}|-) +JMETERLOG %{DATE_JMETER} %{TIME} %{TYPE} [- ] %{MESSAGE} + +# Log Levels +LOGLEVEL ([A|a]lert|ALERT|[T|t]race|TRACE|[D|d]ebug|DEBUG|[N|n]otice|NOTICE|[I|i]nfo|INFO|[W|w]arn?(?:ing)?|WARN?(?:ING)?|[E|e]rr?(?:or)?|ERR?(?:OR)?|[C|c]rit?(?:ical)?|CRIT?(?:ICAL)?|[F|f]atal|FATAL|[S|s]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?) \ No newline at end of file