Improved line parser code.

This commit is contained in:
Christian P. MOMON 2021-11-29 03:57:27 +01:00
parent 1178ab11a4
commit c59a00a695
11 changed files with 593 additions and 185 deletions

View file

@ -35,7 +35,9 @@ import org.slf4j.LoggerFactory;
import fr.devinsy.logar.app.anonymizer.Anonymizer; import fr.devinsy.logar.app.anonymizer.Anonymizer;
import fr.devinsy.logar.app.log.Log; import fr.devinsy.logar.app.log.Log;
import fr.devinsy.logar.app.log.LogFile; import fr.devinsy.logar.app.log.LogFile;
import fr.devinsy.logar.app.log.LogParser; import fr.devinsy.logar.app.log.LogType;
import fr.devinsy.logar.app.log.parser.AccessLogParser;
import fr.devinsy.logar.app.log.parser.LineParser;
import fr.devinsy.logar.stats.UserAgentStator; import fr.devinsy.logar.stats.UserAgentStator;
import fr.devinsy.logar.util.Chrono; import fr.devinsy.logar.util.Chrono;
import fr.devinsy.logar.util.Files; import fr.devinsy.logar.util.Files;
@ -64,8 +66,9 @@ public final class Logar
* *
* @param source * @param source
* the source * the source
* @throws IOException
*/ */
public static void anonymize(final File source) public static void anonymize(final File source) throws IOException
{ {
anonymize(source, null); anonymize(source, null);
} }
@ -77,8 +80,9 @@ public final class Logar
* the source * the source
* @param mapFile * @param mapFile
* the map file * the map file
* @throws IOException
*/ */
public static void anonymize(final File source, final File mapFile) public static void anonymize(final File source, final File mapFile) throws IOException
{ {
if (source == null) if (source == null)
{ {
@ -150,6 +154,7 @@ public final class Logar
YearMonth targetYearMonth = YearMonth.now().minusMonths(1); YearMonth targetYearMonth = YearMonth.now().minusMonths(1);
Stats counter = new Stats(); Stats counter = new Stats();
LineParser lineParser = new AccessLogParser();
for (File directory : Files.of(source).removeHidden().keepDirectoryType().sortByName()) for (File directory : Files.of(source).removeHidden().keepDirectoryType().sortByName())
{ {
String targetFileName = String.format("%s-access-%s.log.gz", directory.getName(), targetYearMonth.toString()); String targetFileName = String.format("%s-access-%s.log.gz", directory.getName(), targetYearMonth.toString());
@ -179,7 +184,7 @@ public final class Logar
try try
{ {
Log log = LogParser.parseAccessLog(line); Log log = lineParser.parse(line);
counter.incSuccessLineCount(); counter.incSuccessLineCount();
if (YearMonth.from(log.getDatetime()).equals(targetYearMonth)) if (YearMonth.from(log.getDatetime()).equals(targetYearMonth))
@ -268,6 +273,7 @@ public final class Logar
{ {
if ((!file.isDirectory()) && (file.getName().contains("error"))) if ((!file.isDirectory()) && (file.getName().contains("error")))
{ {
LineParser lineParser = LogFile.getParser(file);
// logger.info(file.getName()); // logger.info(file.getName());
try try
{ {
@ -279,7 +285,7 @@ public final class Logar
try try
{ {
Log log = LogParser.parseErrorLog(line); Log log = lineParser.parse(line);
counter.incSuccessLineCount(); counter.incSuccessLineCount();
if (YearMonth.from(log.getDatetime()).equals(targetYearMonth)) if (YearMonth.from(log.getDatetime()).equals(targetYearMonth))
@ -325,8 +331,9 @@ public final class Logar
* *
* @param file * @param file
* the source * the source
* @throws IOException
*/ */
public static void checkLogFile(final File file) public static void checkLogFile(final File file) throws IOException
{ {
if (file == null) if (file == null)
{ {
@ -339,7 +346,7 @@ public final class Logar
else else
{ {
System.out.println("== Check parse log for [" + file.getName() + "]"); System.out.println("== Check parse log for [" + file.getName() + "]");
boolean isAccessFile = file.getName().contains("access"); LineParser parser = LogFile.getParser(file);
int lineCount = 0; int lineCount = 0;
int badLineCount = 0; int badLineCount = 0;
@ -353,14 +360,7 @@ public final class Logar
try try
{ {
if (isAccessFile) parser.parse(line).getDatetime();
{
LogParser.parseAccessLog(line).getDatetime();
}
else
{
LogParser.parseErrorLog(line).getDatetime();
}
} }
catch (IllegalArgumentException exception) catch (IllegalArgumentException exception)
{ {
@ -393,8 +393,9 @@ public final class Logar
* *
* @param source * @param source
* the source * the source
* @throws IOException
*/ */
public static void checkLogFiles(final File source) public static void checkLogFiles(final File source) throws IOException
{ {
if (source == null) if (source == null)
{ {
@ -464,7 +465,7 @@ public final class Logar
else else
{ {
System.out.println("== Check sort for [" + file.getName() + "]"); System.out.println("== Check sort for [" + file.getName() + "]");
boolean isAccessFile = file.getName().contains("access"); LineParser lineParser = LogFile.getParser(file);
LocalDateTime currentDate = null; LocalDateTime currentDate = null;
int lineCount = 0; int lineCount = 0;
int badLineCount = 0; int badLineCount = 0;
@ -474,14 +475,7 @@ public final class Logar
String line = iterator.next(); String line = iterator.next();
lineCount += 1; lineCount += 1;
LocalDateTime date; LocalDateTime date;
if (isAccessFile) date = lineParser.parse(line).getDatetime();
{
date = LogParser.parseAccessLog(line).getDatetime();
}
else
{
date = LogParser.parseErrorLog(line).getDatetime();
}
if ((currentDate != null) && (date.isBefore(currentDate))) if ((currentDate != null) && (date.isBefore(currentDate)))
{ {
@ -530,6 +524,7 @@ public final class Logar
System.err.println("== Extract userAgent for [" + file.getName() + "]"); System.err.println("== Extract userAgent for [" + file.getName() + "]");
try try
{ {
LineParser lineParser = LogFile.getParser(file);
LineIterator iterator = new LineIterator(file); LineIterator iterator = new LineIterator(file);
while (iterator.hasNext()) while (iterator.hasNext())
{ {
@ -537,7 +532,7 @@ public final class Logar
// System.out.println(line); // System.out.println(line);
try try
{ {
Log log = LogParser.parseAccessLog(line); Log log = lineParser.parse(line);
StringList extract = new StringList(); StringList extract = new StringList();
if (options.getIp().isOn()) if (options.getIp().isOn())
@ -582,6 +577,36 @@ public final class Logar
} }
} }
/**
* Identify.
*
* @param source
* the source
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static void identify(final File source) throws IOException
{
if (source == null)
{
System.out.println("Undefined source.");
}
else if (!source.exists())
{
System.out.println("Missing source to sort.");
}
else
{
Files files = FilesUtils.search(source, LOGFILE_PATTERN).removeHidden().sortByName();
for (File file : files)
{
String type = LogFile.getType(file);
System.out.println(StringUtils.rightPad(type, 20) + file.getName());
}
}
}
/** /**
* Sort. * Sort.
* *
@ -602,7 +627,7 @@ public final class Logar
} }
else else
{ {
Files files = FilesUtils.searchEndingWith(source, LOGFILE_PATTERN).removeHidden().sortByName(); Files files = FilesUtils.search(source, LOGFILE_PATTERN).removeHidden().sortByName();
for (File file : files) for (File file : files)
{ {
@ -652,6 +677,7 @@ public final class Logar
int badLineCount = 0; int badLineCount = 0;
try try
{ {
LineParser lineParser = LogFile.getParser(file);
UserAgentStator stator = new UserAgentStator(); UserAgentStator stator = new UserAgentStator();
LineIterator iterator = new LineIterator(file); LineIterator iterator = new LineIterator(file);
Chrono chrono = new Chrono().start(); Chrono chrono = new Chrono().start();
@ -669,7 +695,7 @@ public final class Logar
try try
{ {
Log log = LogParser.parseAccessLog(line); Log log = lineParser.parse(line);
stator.putLog(log); stator.putLog(log);
} }
catch (IllegalArgumentException exception) catch (IllegalArgumentException exception)
@ -724,8 +750,9 @@ public final class Logar
* *
* @param source * @param source
* the source * the source
* @throws IOException
*/ */
public static void testConcate(final File source) public static void testConcate(final File source) throws IOException
{ {
Files files = FilesUtils.searchEndingWith(source, ".log", ".log.gz").keepFileType().removeContaining("-anon.log").sortByName(); Files files = FilesUtils.searchEndingWith(source, ".log", ".log.gz").keepFileType().removeContaining("-anon.log").sortByName();
@ -740,8 +767,9 @@ public final class Logar
* *
* @param file * @param file
* the file * the file
* @throws IOException
*/ */
public static void testConcateFile(final File file) public static void testConcateFile(final File file) throws IOException
{ {
if (file == null) if (file == null)
{ {
@ -754,7 +782,7 @@ public final class Logar
else else
{ {
System.out.println("== Test concate log for [" + file.getName() + "]"); System.out.println("== Test concate log for [" + file.getName() + "]");
boolean isAccessFile = file.getName().contains("access"); LineParser lineParser = LogFile.getParser(file);
int lineCount = 0; int lineCount = 0;
int badLineCount = 0; int badLineCount = 0;
@ -768,18 +796,14 @@ public final class Logar
try try
{ {
Log source; Log source = lineParser.parse(line);
Log target; Log target = new Log(source);
if (isAccessFile) if (lineParser.getType() == LogType.ACCESS)
{ {
source = LogParser.parseAccessLog(line);
target = new Log(source);
target.concateAccessLog(); target.concateAccessLog();
} }
else else if (lineParser.getType() == LogType.ERROR)
{ {
source = LogParser.parseErrorLog(line);
target = new Log(source);
target.concateErrorLog(); target.concateErrorLog();
} }

View file

@ -33,7 +33,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import fr.devinsy.logar.app.log.Log; import fr.devinsy.logar.app.log.Log;
import fr.devinsy.logar.app.log.LogParser; import fr.devinsy.logar.app.log.LogFile;
import fr.devinsy.logar.app.log.LogType;
import fr.devinsy.logar.app.log.parser.LineParser;
import fr.devinsy.logar.util.LineIterator; import fr.devinsy.logar.util.LineIterator;
/** /**
@ -65,8 +67,9 @@ public final class Anonymizer
* *
* @param source * @param source
* the source * the source
* @throws IOException
*/ */
public void anonymize(final File source) public void anonymize(final File source) throws IOException
{ {
if (source == null) if (source == null)
{ {
@ -83,7 +86,7 @@ public final class Anonymizer
else else
{ {
System.out.println("== Anonymize log for [" + source.getName() + "]"); System.out.println("== Anonymize log for [" + source.getName() + "]");
boolean isAccessFile = source.getName().contains("access"); LineParser lineParser = LogFile.getParser(source);
File target; File target;
if (source.getName().endsWith(".log.gz")) if (source.getName().endsWith(".log.gz"))
@ -106,10 +109,10 @@ public final class Anonymizer
try try
{ {
Log log = lineParser.parse(line);
Log anon; Log anon;
if (isAccessFile) if (lineParser.getType() == LogType.ACCESS)
{ {
Log log = LogParser.parseAccessLog(line);
// logger.info("line={}", line); // logger.info("line={}", line);
// logger.info("log =[{}][{}][{}]", log.getIp(), // logger.info("log =[{}][{}][{}]", log.getIp(),
// log.getUser(), log.getDatetime()); // log.getUser(), log.getDatetime());
@ -137,8 +140,6 @@ public final class Anonymizer
} }
else else
{ {
Log log = LogParser.parseErrorLog(line);
anon = anonymizeError(log); anon = anonymizeError(log);
} }

View file

@ -31,6 +31,11 @@ import org.slf4j.LoggerFactory;
import fr.devinsy.cmdexec.CmdExecException; import fr.devinsy.cmdexec.CmdExecException;
import fr.devinsy.cmdexec.CmdExecUtils; import fr.devinsy.cmdexec.CmdExecUtils;
import fr.devinsy.logar.app.log.parser.AccessLogParser;
import fr.devinsy.logar.app.log.parser.ApacheErrorLogParser;
import fr.devinsy.logar.app.log.parser.EmptyLogParser;
import fr.devinsy.logar.app.log.parser.LineParser;
import fr.devinsy.logar.app.log.parser.NginxErrorLogParser;
import fr.devinsy.logar.util.LineIterator; import fr.devinsy.logar.util.LineIterator;
/** /**
@ -48,77 +53,41 @@ public final class LogFile
} }
/** /**
* Load access log. * Gets the parser.
* *
* @param file * @param file
* the file * the file
* @return the logs * @return the parser
* @throws IOException * @throws IOException
* Signals that an I/O exception has occurred.
*/ */
public static Logs loadAccessLog(final File file) throws IOException public static LineParser getParser(final File file) throws IOException
{ {
Logs result; LineParser result;
result = loadAccessLog(file, LogMode.NORMAL); if (file.getName().contains("access"))
return result;
}
/**
* Load access log.
*
* @param file
* the file
* @param mode
* the mode
* @return the logs
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static Logs loadAccessLog(final File file, final LogMode mode) throws IOException
{
Logs result;
result = new Logs();
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{ {
String line = iterator.next(); result = new AccessLogParser();
Log log = LogParser.parseAccessLog(line); }
if (mode == LogMode.REDUCED) else if (file.getName().contains("error"))
{
String line = readFirstLine(file);
if (line == null)
{ {
log.reduce(); result = new EmptyLogParser();
}
else if (line.startsWith("["))
{
result = new ApacheErrorLogParser();
}
else
{
result = new NginxErrorLogParser();
} }
result.add(log);
} }
else
//
return result;
}
/**
* Load error log.
*
* @param file
* the file
* @return the logs
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static Logs loadErrorLog(final File file) throws IOException
{
Logs result;
result = new Logs();
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{ {
String line = iterator.next(); throw new IllegalArgumentException("Bad named file (missing access or error).");
Log log = LogParser.parseErrorLog(line);
result.add(log);
} }
// //
@ -126,7 +95,34 @@ public final class LogFile
} }
/** /**
* Load log file. * Gets the type.
*
* @param file
* the file
* @return the type
* @throws IOException
*/
public static String getType(final File file) throws IOException
{
String result;
LineParser parser = getParser(file);
if (parser == null)
{
result = "*/*";
}
else
{
result = parser.getMime();
}
//
return result;
}
/**
* Parses the log file.
* *
* @param file * @param file
* the file * the file
@ -134,18 +130,18 @@ public final class LogFile
* @throws IOException * @throws IOException
* Signals that an I/O exception has occurred. * Signals that an I/O exception has occurred.
*/ */
public static Logs loadLogFile(final File file) throws IOException public static Logs parseLogFile(final File file) throws IOException
{ {
Logs result; Logs result;
result = loadLogFile(file, LogMode.NORMAL); result = parseLogFile(file, LogMode.NORMAL);
// //
return result; return result;
} }
/** /**
* Load log file. * Parses the log file.
* *
* @param file * @param file
* the file * the file
@ -155,7 +151,7 @@ public final class LogFile
* @throws IOException * @throws IOException
* Signals that an I/O exception has occurred. * Signals that an I/O exception has occurred.
*/ */
public static Logs loadLogFile(final File file, final LogMode mode) throws IOException public static Logs parseLogFile(final File file, final LogMode mode) throws IOException
{ {
Logs result; Logs result;
@ -165,17 +161,55 @@ public final class LogFile
} }
else else
{ {
if (file.getName().contains("access")) LineParser lineParser = getParser(file);
result = new Logs();
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{ {
result = loadAccessLog(file, mode); String line = iterator.next();
Log log = lineParser.parse(line);
if (mode == LogMode.REDUCED)
{
log.reduce();
}
result.add(log);
} }
else if (file.getName().contains("error")) }
//
return result;
}
/**
* Read first line.
*
* @param file
* the file
* @return the string
*/
private static String readFirstLine(final File file) throws IOException
{
String result;
LineIterator iterator = null;
try
{
iterator = new LineIterator(file);
if (iterator.hasNext())
{ {
result = loadErrorLog(file); result = iterator.next();
} }
else else
{ {
throw new IllegalArgumentException("Bad named file (missing access or error)."); result = null;
}
}
finally
{
if (iterator != null)
{
iterator.close();
} }
} }
@ -232,7 +266,7 @@ public final class LogFile
{ {
File workFile = new File(file.getParent(), file.getName() + ".tmp"); File workFile = new File(file.getParent(), file.getName() + ".tmp");
Logs logs = loadLogFile(file, LogMode.REDUCED); Logs logs = parseLogFile(file, LogMode.REDUCED);
logs.sortByDatetime(); logs.sortByDatetime();
saveLogs(workFile, logs); saveLogs(workFile, logs);

View file

@ -0,0 +1,29 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Logar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log;
/**
* The Enum LogType.
*/
public enum LogType
{
ACCESS,
ERROR,
WILDCARD;
}

View file

@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with Logar. If not, see <http://www.gnu.org/licenses/>. * along with Logar. If not, see <http://www.gnu.org/licenses/>.
*/ */
package fr.devinsy.logar.app.log; package fr.devinsy.logar.app.log.parser;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -28,25 +28,54 @@ import java.util.regex.Pattern;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import fr.devinsy.logar.app.log.Log;
import fr.devinsy.logar.app.log.LogType;
/** /**
* The Class LogParser. * The Class NginxAccessLogParser.
*/ */
public final class LogParser public final class AccessLogParser implements LineParser
{ {
private static Logger logger = LoggerFactory.getLogger(LogParser.class); private static Logger logger = LoggerFactory.getLogger(AccessLogParser.class);
public static Pattern NGINX_ACCESSLOG_LINE_PATTERN = Pattern.compile( public static Pattern COMBINED_ACCESSLOG_LINE_PATTERN = Pattern.compile(
"^(?<remoteAddress>[a-zA-F0-9\\\\:\\\\.]+) - (?<remoteUser>[^\\[]+) \\[(?<datetime>[^\\]]+)\\] \"(?<request>[^\"]*)\" (?<status>\\d+) (?<bodyBytesSent>\\d+) \"(?<referer>[^\"]*)\" \"(?<userAgent>[^\"]*)\".*$"); "^(?<remoteAddress>[a-zA-F0-9\\\\:\\\\.]+) - (?<remoteUser>[^\\[]+) \\[(?<datetime>[^\\]]+)\\] \"(?<request>[^\"]*)\" (?<status>\\d+) (?<bodyBytesSent>\\d+) \"(?<referer>[^\"]*)\" \"(?<userAgent>[^\"]*)\".*$");
public static Pattern NGINX_ERRORLOG_LINE_PATTERN = Pattern.compile("^(?<datetime>\\S+\\s\\S+)\\s\\[(?<level>[^\\]]*)\\]\\s(?<message>.*)$");
/** /**
* Instantiates a new log parser. * Instantiates a new log parser.
*/ */
private LogParser() public AccessLogParser()
{ {
} }
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#type()
*/
@Override
public String getMime()
{
String result;
result = "Access/*";
//
return result;
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#getType()
*/
@Override
public LogType getType()
{
LogType result;
result = LogType.ACCESS;
//
return result;
}
/** /**
* From access log. * From access log.
* *
@ -58,13 +87,14 @@ public final class LogParser
* '"$request" $status $body_bytes_sent ' '"$http_referer" * '"$request" $status $body_bytes_sent ' '"$http_referer"
* "$http_user_agent"'; * "$http_user_agent"';
*/ */
public static Log parseAccessLog(final String line) @Override
public Log parse(final String line)
{ {
Log result; Log result;
try try
{ {
Matcher matcher = NGINX_ACCESSLOG_LINE_PATTERN.matcher(line); Matcher matcher = COMBINED_ACCESSLOG_LINE_PATTERN.matcher(line);
if (matcher.matches()) if (matcher.matches())
{ {
String dateTimeValue = matcher.group("datetime"); String dateTimeValue = matcher.group("datetime");
@ -94,60 +124,4 @@ public final class LogParser
// //
return result; return result;
} }
/**
* Parses the access log light.
*
* @param line
* the line
* @return the log
*/
public static Log parseAccessLogLight(final String line)
{
Log result;
result = parseAccessLog(line);
result.reduce();
//
return result;
}
/**
* From error log.
*
* @param line
* the line
* @return the log
*/
public static Log parseErrorLog(final String line)
{
Log result;
try
{
Matcher matcher = NGINX_ERRORLOG_LINE_PATTERN.matcher(line);
if (matcher.matches())
{
String value = matcher.group("datetime");
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").withLocale(Locale.ENGLISH));
result = new Log(line, date);
result.setDatetimeValue(matcher.group("datetime"));
result.setLevel(matcher.group("level"));
result.setMessage(matcher.group("message"));
}
else
{
throw new IllegalArgumentException("Bad line format: " + line);
}
}
catch (DateTimeParseException exception)
{
throw new IllegalArgumentException("Bad line format (date): " + line, exception);
}
//
return result;
}
} }

View file

@ -0,0 +1,113 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Logar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log.parser;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.logar.app.log.Log;
import fr.devinsy.logar.app.log.LogType;
/**
* The Class ApacheErrorLogParser.
*/
public final class ApacheErrorLogParser implements LineParser
{
private static Logger logger = LoggerFactory.getLogger(ApacheErrorLogParser.class);
public static Pattern APACHE_ERRORLOG_LINE_PATTERN = Pattern.compile("^\\[(?<datetime>[^\\]]+)\\]\\s\\[(?<level>[^\\]]*)\\]\\s(?<message>.*)$");
/**
* Instantiates a new nginx error log parser.
*/
public ApacheErrorLogParser()
{
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#type()
*/
@Override
public String getMime()
{
String result;
result = "Error/Apache";
//
return result;
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#getType()
*/
@Override
public LogType getType()
{
LogType result;
result = LogType.ERROR;
//
return result;
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#parse(java.lang.String)
*/
@Override
public Log parse(final String line)
{
Log result;
try
{
Matcher matcher = APACHE_ERRORLOG_LINE_PATTERN.matcher(line);
if (matcher.matches())
{
String value = matcher.group("datetime");
// Example: Mon Nov 22 06:15:13.773450 2021
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss.SSSSSS yyyy").withLocale(Locale.ENGLISH));
result = new Log(line, date);
result.setDatetimeValue(matcher.group("datetime"));
result.setLevel(matcher.group("level"));
result.setMessage(matcher.group("message"));
}
else
{
throw new IllegalArgumentException("Bad line format: " + line);
}
}
catch (DateTimeParseException exception)
{
throw new IllegalArgumentException("Bad line format (date): " + line, exception);
}
//
return result;
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Logar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log.parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.logar.app.log.Log;
import fr.devinsy.logar.app.log.LogType;
/**
* The Class EmptyLogParser.
*/
public final class EmptyLogParser implements LineParser
{
private static Logger logger = LoggerFactory.getLogger(EmptyLogParser.class);
/**
* Instantiates a new empty log parser.
*/
public EmptyLogParser()
{
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#type()
*/
@Override
public String getMime()
{
String result;
result = "*/*";
//
return result;
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#getType()
*/
@Override
public LogType getType()
{
LogType result;
result = LogType.WILDCARD;
//
return result;
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#parse(java.lang.String)
*/
@Override
public Log parse(final String line)
{
Log result;
result = null;
//
return result;
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Logar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log.parser;
import fr.devinsy.logar.app.log.Log;
import fr.devinsy.logar.app.log.LogType;
/**
* The Interface LineParser.
*/
public interface LineParser
{
String getMime();
LogType getType();
Log parse(String line);
}

View file

@ -0,0 +1,112 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Logar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log.parser;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.logar.app.log.Log;
import fr.devinsy.logar.app.log.LogType;
/**
* The Class NginxErrorLogParser.
*/
public final class NginxErrorLogParser implements LineParser
{
private static Logger logger = LoggerFactory.getLogger(NginxErrorLogParser.class);
public static Pattern NGINX_ERRORLOG_LINE_PATTERN = Pattern.compile("^(?<datetime>\\S+\\s\\S+)\\s\\[(?<level>[^\\]]*)\\]\\s(?<message>.*)$");
/**
* Instantiates a new nginx error log parser.
*/
public NginxErrorLogParser()
{
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#type()
*/
@Override
public String getMime()
{
String result;
result = "Error/Nginx";
//
return result;
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#getType()
*/
@Override
public LogType getType()
{
LogType result;
result = LogType.ERROR;
//
return result;
}
/* (non-Javadoc)
* @see fr.devinsy.logar.app.log.parser.LineParser#parse(java.lang.String)
*/
@Override
public Log parse(final String line)
{
Log result;
try
{
Matcher matcher = NGINX_ERRORLOG_LINE_PATTERN.matcher(line);
if (matcher.matches())
{
String value = matcher.group("datetime");
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").withLocale(Locale.ENGLISH));
result = new Log(line, date);
result.setDatetimeValue(matcher.group("datetime"));
result.setLevel(matcher.group("level"));
result.setMessage(matcher.group("message"));
}
else
{
throw new IllegalArgumentException("Bad line format: " + line);
}
}
catch (DateTimeParseException exception)
{
throw new IllegalArgumentException("Bad line format (date): " + line, exception);
}
//
return result;
}
}

View file

@ -61,6 +61,7 @@ public final class LogarCLI
message.appendln(" logar check <fileordirectory> check line format in log files"); message.appendln(" logar check <fileordirectory> check line format in log files");
message.appendln(" logar checksort <fileordirectory> check sort in log files"); message.appendln(" logar checksort <fileordirectory> check sort in log files");
message.appendln(" logar extract <fields> <fileordirectory> extract one or more fields (ip,user,datetime,useragent) from log files"); message.appendln(" logar extract <fields> <fileordirectory> extract one or more fields (ip,user,datetime,useragent) from log files");
message.appendln(" logar identify <fileordirectory> display type of log files");
message.appendln(" logar sort <fileordirectory> sort log files by datetime"); message.appendln(" logar sort <fileordirectory> sort log files by datetime");
message.appendln(" logar testconcate <fileordirectory> test line concate in log files"); message.appendln(" logar testconcate <fileordirectory> test line concate in log files");
@ -232,6 +233,12 @@ public final class LogarCLI
Logar.extract(source, options); Logar.extract(source, options);
} }
else if (isMatching(args, "identify", "\\s*\\S+\\s*"))
{
File source = new File(args[1]);
Logar.identify(source);
}
else if (isMatching(args, "sort", "\\s*\\S+\\s*")) else if (isMatching(args, "sort", "\\s*\\S+\\s*"))
{ {
File source = new File(args[1]); File source = new File(args[1]);

View file

@ -33,10 +33,8 @@ public final class UserAgent
private long ipLinkCount; private long ipLinkCount;
/** /**
* Instantiates a new user agent stat. * Instantiates a new user agent.
* *
* @param ip
* the ip
* @param userAgent * @param userAgent
* the user agent * the user agent
*/ */