Compare commits
13 Commits
11ee2d4f84
...
15b088268b
Author | SHA1 | Date |
---|---|---|
Christian P. MOMON | 15b088268b | |
Christian P. MOMON | 4cf6678aae | |
Christian P. MOMON | 77837b3aee | |
Christian P. MOMON | b7f9d875f1 | |
Christian P. MOMON | d4d1b6038c | |
Christian P. MOMON | 1e46e07c4b | |
Christian P. MOMON | c3a6fc9841 | |
Christian P. MOMON | 541e0d9254 | |
Christian P. MOMON | 90dc98fbc5 | |
Christian P. MOMON | 2ff492fc83 | |
Christian P. MOMON | a0d78392fc | |
Christian P. MOMON | e324aef88d | |
Christian P. MOMON | 69506d67f2 |
|
@ -21,5 +21,6 @@
|
|||
<classpathentry kind="lib" path="lib/commons-text-1.9.jar" sourcepath="lib/commons-text-1.9-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/devinsy-strings-0.11.3.jar" sourcepath="lib/devinsy-strings-0.11.3-sources.zip"/>
|
||||
<classpathentry kind="lib" path="lib/threeten-extra-1.5.0.jar" sourcepath="lib/threeten-extra-1.5.0-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/devinsy-cmdexec-0.11.1.jar" sourcepath="lib/devinsy-cmdexec-0.11.1-sources.zip"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -3,7 +3,7 @@
|
|||
# Java check.
|
||||
javaCheck=`which java`
|
||||
if [[ "$javaCheck" =~ ^/.* ]]; then
|
||||
echo "Java requirement............... OK"
|
||||
#echo "Java requirement............... OK"
|
||||
java -jar "$(dirname "$0")"/logar.jar $@
|
||||
else
|
||||
echo "Java requirement............... MISSING"
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The Enum DryOption.
|
||||
*/
|
||||
public enum DryOption
|
||||
{
|
||||
ON,
|
||||
OFF;
|
||||
|
||||
/**
|
||||
* Checks if is off.
|
||||
*
|
||||
* @return true, if is off
|
||||
*/
|
||||
public boolean isOff()
|
||||
{
|
||||
boolean result;
|
||||
|
||||
result = (this == OFF);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is on.
|
||||
*
|
||||
* @return true, if is on
|
||||
*/
|
||||
public boolean isOn()
|
||||
{
|
||||
boolean result;
|
||||
|
||||
result = (this == ON);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -24,20 +24,22 @@ import java.io.IOException;
|
|||
import java.io.PrintWriter;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
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 java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.april.logar.util.Files;
|
||||
import org.april.logar.util.FilesUtils;
|
||||
import org.april.logar.util.LineIterator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import fr.devinsy.logar.app.anonymizer.Anonymizer;
|
||||
import fr.devinsy.logar.app.log.Log;
|
||||
import fr.devinsy.logar.app.log.LogFile;
|
||||
import fr.devinsy.logar.app.log.LogParser;
|
||||
|
||||
/**
|
||||
* The Class Logar.
|
||||
*/
|
||||
|
@ -45,11 +47,7 @@ public final class Logar
|
|||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(Logar.class);
|
||||
|
||||
public static Pattern nginxAccessLogLinePatternFull = Pattern.compile(
|
||||
"^(?<remoteAddress>[a-zA-F0-9\\\\:\\\\.]+) - (?<remoteUser>\\S+) \\[(?<time>[^\\]]+)\\] \"(?<request>[^\"]*)\" (?<status>\\d+) (?<bodyBytesSent>\\d+) \"(?<referer>[^\"]*)\" \"(?<userAgent>[^\"]*)\".*$");
|
||||
|
||||
public static Pattern nginxAccessLogLinePattern = Pattern.compile("^\\S+ - [^\\[]+ \\[(?<time>[^\\]]+)\\] .*$");
|
||||
public static Pattern nginxErrorLogLinePattern = Pattern.compile("^(?<time>\\S+\\s\\S+)\\s\\[(?<level>[^\\]]*)\\]\\s.*$");
|
||||
public static String LOGFILE_PATTERN = "^.+(\\.|_)(log|log\\.gz|log\\.\\d+|log\\.\\d+\\.gz)$";
|
||||
|
||||
/**
|
||||
* Instantiates a new log tool.
|
||||
|
@ -66,13 +64,46 @@ public final class Logar
|
|||
* @param target
|
||||
* the target
|
||||
*/
|
||||
public static void anonymize(final File source, final File target)
|
||||
public static void anonymize(final File source)
|
||||
{
|
||||
for (File file : source.listFiles())
|
||||
{
|
||||
if ((file.isDirectory()) && (!StringUtils.equalsAny(file.getName(), ".", "..")))
|
||||
{
|
||||
anonymize(source, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @param target
|
||||
* the target
|
||||
*/
|
||||
public static void anonymize(final File source, final File mapFile)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Null source file.");
|
||||
}
|
||||
else if (!source.exists())
|
||||
{
|
||||
throw new IllegalArgumentException("Source file does not exist.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Anonymizer anonymizer = new Anonymizer();
|
||||
anonymizer.loadMapTable(mapFile);
|
||||
System.out.println("Table size=" + anonymizer.getMapTable().size());
|
||||
|
||||
Files files = FilesUtils.searchEndingWith(source, ".log", ".log.gz").keepFileType().removeContaining("-anon.log").sortByName();
|
||||
logger.info("file count={}", files.size());
|
||||
for (File file : files)
|
||||
{
|
||||
anonymizer.anonymize(file);
|
||||
}
|
||||
|
||||
if (mapFile != null)
|
||||
{
|
||||
System.out.println("Table size=" + anonymizer.getMapTable().size());
|
||||
anonymizer.SaveMapTable(mapFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,10 +117,10 @@ public final class Logar
|
|||
* the target
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void archive(final File source, final File target) throws IOException
|
||||
public static void archive(final File source, final File target, final DryOption dry) throws IOException
|
||||
{
|
||||
archiveAccessFiles(source, target);
|
||||
archiveErrorFiles(source, target);
|
||||
archiveAccessFiles(source, target, dry);
|
||||
archiveErrorFiles(source, target, dry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +130,7 @@ public final class Logar
|
|||
* the source
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void archiveAccessFiles(final File source, final File target) throws IOException
|
||||
public static void archiveAccessFiles(final File source, final File target, final DryOption dry) throws IOException
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
|
@ -118,74 +149,69 @@ public final class Logar
|
|||
YearMonth targetYearMonth = YearMonth.now().minusMonths(1);
|
||||
Stats counter = new Stats();
|
||||
|
||||
for (File directory : Files.of(source).sortByName())
|
||||
for (File directory : Files.of(source).removeHidden().keepDirectoryType().sortByName())
|
||||
{
|
||||
if ((directory.isDirectory()) && (!StringUtils.equalsAny(directory.getName(), ".", "..")))
|
||||
String targetFileName = String.format("%s-access-%s.log.gz", directory.getName(), targetYearMonth.toString());
|
||||
File targetDirectory = new File(target, directory.getName());
|
||||
File targetFile = new File(targetDirectory, targetFileName);
|
||||
logger.info("== {} -> {}", directory.getName(), targetFile.getAbsoluteFile());
|
||||
|
||||
PrintWriter out = null;
|
||||
if (dry.isOff())
|
||||
{
|
||||
String targetFileName = String.format("%s-access-%s.log.gz", directory.getName(), targetYearMonth.toString());
|
||||
File targetDirectory = new File(target, directory.getName());
|
||||
targetDirectory.mkdirs();
|
||||
File targetFile = new File(targetDirectory, targetFileName);
|
||||
logger.info("== {} -> {}", directory.getName(), targetFile.getAbsoluteFile());
|
||||
PrintWriter out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(targetFile)));
|
||||
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(targetFile)));
|
||||
}
|
||||
|
||||
for (File file : Files.of(directory).sortByName())
|
||||
for (File file : Files.of(directory).sortByName())
|
||||
{
|
||||
if ((!file.isDirectory()) && (file.getName().contains("access")))
|
||||
{
|
||||
if ((!file.isDirectory()) && (file.getName().contains("access")))
|
||||
logger.info(file.getName());
|
||||
try
|
||||
{
|
||||
// logger.info(file.getName());
|
||||
try
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
String line = iterator.next();
|
||||
counter.incLineCount();
|
||||
|
||||
try
|
||||
{
|
||||
String line = iterator.next();
|
||||
counter.incLineCount();
|
||||
Log log = LogParser.parseAccessLog(line);
|
||||
counter.incSuccessLineCount();
|
||||
|
||||
Matcher matcher = nginxAccessLogLinePattern.matcher(line);
|
||||
if (matcher.matches())
|
||||
if (YearMonth.from(log.getDatetime()).equals(targetYearMonth))
|
||||
{
|
||||
String value = matcher.group("time");
|
||||
try
|
||||
if (dry.isOff())
|
||||
{
|
||||
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z").withLocale(Locale.ENGLISH));
|
||||
counter.incSuccessLineCount();
|
||||
|
||||
if (YearMonth.from(date).equals(targetYearMonth))
|
||||
{
|
||||
out.println(line);
|
||||
}
|
||||
out.println(line);
|
||||
}
|
||||
catch (DateTimeParseException exception)
|
||||
{
|
||||
System.err.println("Date format problem with [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("Not matching line [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException exception)
|
||||
{
|
||||
System.err.println("Bad line format [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
|
||||
counter.incSuccessFileCount();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
counter.incErrorFileCount();
|
||||
}
|
||||
finally
|
||||
{
|
||||
counter.incFileCount();
|
||||
}
|
||||
counter.incSuccessFileCount();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
counter.incErrorFileCount();
|
||||
}
|
||||
finally
|
||||
{
|
||||
counter.incFileCount();
|
||||
}
|
||||
}
|
||||
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
|
||||
System.out.println("=====================================================");
|
||||
|
@ -204,7 +230,7 @@ public final class Logar
|
|||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public static void archiveErrorFiles(final File source, final File target) throws IOException
|
||||
public static void archiveErrorFiles(final File source, final File target, final DryOption dry) throws IOException
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
|
@ -224,74 +250,67 @@ public final class Logar
|
|||
Stats counter = new Stats();
|
||||
counter.start();
|
||||
|
||||
for (File directory : Files.of(source).sortByName())
|
||||
for (File directory : Files.of(source).removeHidden().keepDirectoryType().sortByName())
|
||||
{
|
||||
if ((directory.isDirectory()) && (!StringUtils.equalsAny(directory.getName(), ".", "..")))
|
||||
String targetFileName = String.format("%s-error-%s.log.gz", directory.getName(), targetYearMonth.toString());
|
||||
File targetDirectory = new File(target, directory.getName());
|
||||
File targetFile = new File(targetDirectory, targetFileName);
|
||||
logger.info("== {} -> {}", directory.getName(), targetFile.getAbsoluteFile());
|
||||
PrintWriter out = null;
|
||||
if (dry.isOff())
|
||||
{
|
||||
String targetFileName = String.format("%s-error-%s.log.gz", directory.getName(), targetYearMonth.toString());
|
||||
File targetDirectory = new File(target, directory.getName());
|
||||
targetDirectory.mkdirs();
|
||||
File targetFile = new File(targetDirectory, targetFileName);
|
||||
logger.info("== {} -> {}", directory.getName(), targetFile.getAbsoluteFile());
|
||||
PrintWriter out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(targetFile)));
|
||||
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(targetFile)));
|
||||
}
|
||||
|
||||
for (File file : Files.of(directory).sortByName())
|
||||
for (File file : Files.of(directory).sortByName())
|
||||
{
|
||||
if ((!file.isDirectory()) && (file.getName().contains("error")))
|
||||
{
|
||||
if ((!file.isDirectory()) && (file.getName().contains("error")))
|
||||
// logger.info(file.getName());
|
||||
try
|
||||
{
|
||||
// logger.info(file.getName());
|
||||
try
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
String line = iterator.next();
|
||||
counter.incLineCount();
|
||||
|
||||
try
|
||||
{
|
||||
String line = iterator.next();
|
||||
counter.incLineCount();
|
||||
Log log = LogParser.parseErrorLog(line);
|
||||
counter.incSuccessLineCount();
|
||||
|
||||
Matcher matcher = nginxErrorLogLinePattern.matcher(line);
|
||||
if (matcher.matches())
|
||||
if (YearMonth.from(log.getDatetime()).equals(targetYearMonth))
|
||||
{
|
||||
String value = matcher.group("time");
|
||||
try
|
||||
if (dry.isOff())
|
||||
{
|
||||
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").withLocale(Locale.ENGLISH));
|
||||
counter.incSuccessLineCount();
|
||||
|
||||
if (YearMonth.from(date).equals(targetYearMonth))
|
||||
{
|
||||
out.println(line);
|
||||
}
|
||||
out.println(line);
|
||||
}
|
||||
catch (DateTimeParseException exception)
|
||||
{
|
||||
System.err.println("Date format problem with [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("Not matching line [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
|
||||
counter.incSuccessLineCount();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
counter.incErrorFileCount();
|
||||
}
|
||||
finally
|
||||
{
|
||||
counter.incFileCount();
|
||||
catch (IllegalArgumentException exception)
|
||||
{
|
||||
System.err.println("Bad line format [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
counter.incSuccessFileCount();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
counter.incErrorFileCount();
|
||||
}
|
||||
finally
|
||||
{
|
||||
counter.incFileCount();
|
||||
}
|
||||
}
|
||||
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
|
||||
System.out.println("=====================================================");
|
||||
|
@ -301,183 +320,274 @@ public final class Logar
|
|||
}
|
||||
|
||||
/**
|
||||
* Test parsing.
|
||||
* Check access files.
|
||||
*
|
||||
* @param source
|
||||
* @param file
|
||||
* the source
|
||||
*/
|
||||
public static void testParsing(final File source)
|
||||
public static void checkLogFile(final File file)
|
||||
{
|
||||
testParsingAccessFiles(source);
|
||||
testParsingErrorFiles(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing access files.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
*/
|
||||
public static void testParsingAccessFiles(final File source)
|
||||
{
|
||||
if (source == null)
|
||||
if (file == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Null parameter [source]");
|
||||
throw new IllegalArgumentException("Null parameter.");
|
||||
}
|
||||
else if (!source.isDirectory())
|
||||
else if (!file.isFile())
|
||||
{
|
||||
throw new IllegalArgumentException("Source parameter is not a directory.");
|
||||
throw new IllegalArgumentException("Parameter is not a file.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Stats counter = new Stats();
|
||||
System.out.println("== Check parse log for [" + file.getName() + "]");
|
||||
boolean isAccessFile = file.getName().contains("access");
|
||||
|
||||
for (File directory : source.listFiles())
|
||||
int lineCount = 0;
|
||||
int badLineCount = 0;
|
||||
try
|
||||
{
|
||||
if ((directory.isDirectory()) && (!StringUtils.equalsAny(directory.getName(), ".", "..")))
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
logger.info("== {}", directory.getName());
|
||||
String line = iterator.next();
|
||||
lineCount += 1;
|
||||
|
||||
for (File file : directory.listFiles())
|
||||
try
|
||||
{
|
||||
if ((!file.isDirectory()) && (file.getName().contains("access")))
|
||||
if (isAccessFile)
|
||||
{
|
||||
// logger.info(file.getName());
|
||||
|
||||
try
|
||||
{
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
String line = iterator.next();
|
||||
counter.incLineCount();
|
||||
|
||||
Matcher matcher = nginxAccessLogLinePattern.matcher(line);
|
||||
if (matcher.matches())
|
||||
{
|
||||
String value = matcher.group("time");
|
||||
try
|
||||
{
|
||||
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z").withLocale(Locale.ENGLISH));
|
||||
counter.incSuccessLineCount();
|
||||
}
|
||||
catch (DateTimeParseException exception)
|
||||
{
|
||||
System.err.println("Date format error with [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("Not matching line [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
|
||||
counter.incSuccessFileCount();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
counter.incErrorFileCount();
|
||||
}
|
||||
finally
|
||||
{
|
||||
counter.incFileCount();
|
||||
}
|
||||
LogParser.parseAccessLog(line).getDatetime();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogParser.parseErrorLog(line).getDatetime();
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException exception)
|
||||
{
|
||||
System.out.println("Bad format line: " + line);
|
||||
badLineCount += 1;
|
||||
exception.printStackTrace();
|
||||
}
|
||||
catch (DateTimeParseException exception)
|
||||
{
|
||||
System.out.println("Bad datetime format: " + line);
|
||||
badLineCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("=====================================================");
|
||||
counter.stop();
|
||||
System.out.println(counter.toString());
|
||||
if (badLineCount > 0)
|
||||
{
|
||||
System.out.println("Bad line count: " + badLineCount + "/" + lineCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing error files.
|
||||
* Check.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
*/
|
||||
public static void testParsingErrorFiles(final File source)
|
||||
public static void checkLogFiles(final File source)
|
||||
{
|
||||
if (source == null)
|
||||
Files files = FilesUtils.search(source, LOGFILE_PATTERN).sortByName();
|
||||
|
||||
for (File file : files)
|
||||
{
|
||||
checkLogFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check sort.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void checkSort(final File source) throws IOException
|
||||
{
|
||||
Files files = FilesUtils.search(source, LOGFILE_PATTERN).sortByName();
|
||||
|
||||
for (File file : files)
|
||||
{
|
||||
checkSortFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check sort for access files.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void checkSortFile(final File file) throws IOException
|
||||
{
|
||||
if (file == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Null parameter [source]");
|
||||
}
|
||||
else if (!source.isDirectory())
|
||||
else if (!file.isFile())
|
||||
{
|
||||
throw new IllegalArgumentException("Source parameter is not a directory.");
|
||||
throw new IllegalArgumentException("Source parameter is not a file.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Stats counter = new Stats();
|
||||
|
||||
for (File directory : source.listFiles())
|
||||
System.out.println("== Check sort for [" + file.getName() + "]");
|
||||
boolean isAccessFile = file.getName().contains("access");
|
||||
LocalDateTime currentDate = null;
|
||||
int lineCount = 0;
|
||||
int badLineCount = 0;
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
if ((directory.isDirectory()) && (!StringUtils.equalsAny(directory.getName(), ".", "..")))
|
||||
String line = iterator.next();
|
||||
lineCount += 1;
|
||||
LocalDateTime date;
|
||||
if (isAccessFile)
|
||||
{
|
||||
logger.info("== {}", directory.getName());
|
||||
date = LogParser.parseAccessLog(line).getDatetime();
|
||||
}
|
||||
else
|
||||
{
|
||||
date = LogParser.parseErrorLog(line).getDatetime();
|
||||
}
|
||||
|
||||
for (File file : directory.listFiles())
|
||||
if ((currentDate != null) && (date.isBefore(currentDate)))
|
||||
{
|
||||
System.out.println(String.format("break detected: %d %s", lineCount, currentDate.toString()));
|
||||
badLineCount += 1;
|
||||
}
|
||||
currentDate = date;
|
||||
}
|
||||
|
||||
if (badLineCount > 0)
|
||||
{
|
||||
System.out.println("Bad line count: " + badLineCount + "/" + lineCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public static void sort(final File source) throws IOException
|
||||
{
|
||||
Files files = FilesUtils.searchEndingWith(source, LOGFILE_PATTERN).removeHidden().sortByName();
|
||||
|
||||
for (File file : files)
|
||||
{
|
||||
System.out.println("== Sort for [" + file.getName() + "]");
|
||||
LogFile.sortLogFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check concate.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
*/
|
||||
public static void testConcate(final File source)
|
||||
{
|
||||
Files files = FilesUtils.searchEndingWith(source, ".log", ".log.gz").keepFileType().removeContaining("-anon.log").sortByName();
|
||||
|
||||
for (File file : files)
|
||||
{
|
||||
testConcateFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check concate on file.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
*/
|
||||
public static void testConcateFile(final File file)
|
||||
{
|
||||
if (file == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Null parameter.");
|
||||
}
|
||||
else if (!file.isFile())
|
||||
{
|
||||
throw new IllegalArgumentException("Parameter is not a file.");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("== Test concate log for [" + file.getName() + "]");
|
||||
boolean isAccessFile = file.getName().contains("access");
|
||||
|
||||
int lineCount = 0;
|
||||
int badLineCount = 0;
|
||||
try
|
||||
{
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
String line = iterator.next();
|
||||
lineCount += 1;
|
||||
|
||||
try
|
||||
{
|
||||
if ((!file.isDirectory()) && (file.getName().contains("error")))
|
||||
Log source;
|
||||
Log target;
|
||||
if (isAccessFile)
|
||||
{
|
||||
// logger.info(file.getName());
|
||||
try
|
||||
{
|
||||
LineIterator iterator = new LineIterator(file);
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
String line = iterator.next();
|
||||
counter.incLineCount();
|
||||
|
||||
Matcher matcher = nginxErrorLogLinePattern.matcher(line);
|
||||
if (matcher.matches())
|
||||
{
|
||||
String value = matcher.group("time");
|
||||
try
|
||||
{
|
||||
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").withLocale(Locale.ENGLISH));
|
||||
counter.incSuccessLineCount();
|
||||
}
|
||||
catch (DateTimeParseException exception)
|
||||
{
|
||||
System.err.println("Date format problem with [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("Not matching line [" + line + "]");
|
||||
counter.incErrorLineCount();
|
||||
}
|
||||
}
|
||||
|
||||
counter.incSuccessFileCount();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
counter.incErrorFileCount();
|
||||
}
|
||||
finally
|
||||
{
|
||||
counter.incFileCount();
|
||||
}
|
||||
source = LogParser.parseAccessLog(line);
|
||||
target = new Log(source);
|
||||
target.concateAccessLog();
|
||||
}
|
||||
else
|
||||
{
|
||||
source = LogParser.parseErrorLog(line);
|
||||
target = new Log(source);
|
||||
target.concateErrorLog();
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(source.getLine(), target.getLine()))
|
||||
{
|
||||
System.out.println("Bad concat (1): " + source);
|
||||
System.out.println("Bad concat (2): " + target);
|
||||
badLineCount += 1;
|
||||
}
|
||||
|
||||
}
|
||||
catch (IllegalArgumentException exception)
|
||||
{
|
||||
System.out.println("Bad format line: " + line);
|
||||
badLineCount += 1;
|
||||
exception.printStackTrace();
|
||||
}
|
||||
catch (DateTimeParseException exception)
|
||||
{
|
||||
System.out.println("Bad datetime format: " + line);
|
||||
badLineCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("=====================================================");
|
||||
counter.stop();
|
||||
System.out.println(counter.toString());
|
||||
if (badLineCount > 0)
|
||||
{
|
||||
System.out.println("Bad line count: " + badLineCount + "/" + lineCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
*/
|
||||
package fr.devinsy.logar.app;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -28,6 +37,8 @@ public final class LogarUtils
|
|||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(LogarUtils.class);
|
||||
|
||||
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
|
||||
|
||||
/**
|
||||
* Instantiates a new log tool utils.
|
||||
*/
|
||||
|
@ -35,6 +46,38 @@ public final class LogarUtils
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sha 1 sum.
|
||||
*
|
||||
* @param file
|
||||
* the file
|
||||
* @return the string
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String sha1sum(final File file) throws IOException
|
||||
{
|
||||
String result;
|
||||
|
||||
DigestInputStream digestStream = null;
|
||||
try
|
||||
{
|
||||
digestStream = new DigestInputStream(new FileInputStream(file), MessageDigest.getInstance("SHA-1"));
|
||||
digestStream.readAllBytes();
|
||||
result = DigestUtils.sha1Hex(digestStream.getMessageDigest().digest());
|
||||
}
|
||||
catch (NoSuchAlgorithmException e1)
|
||||
{
|
||||
throw new IOException("Impossible to get SHA-1 digester", e1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(digestStream);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* To human.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* 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.anonymizer;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import fr.devinsy.strings.StringSet;
|
||||
|
||||
/**
|
||||
* The Class AnonMap.
|
||||
*/
|
||||
public final class AnonMap
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(AnonMap.class);
|
||||
|
||||
private HashMap<String, String> map;
|
||||
private HashMap<String, String> unmap;
|
||||
|
||||
/**
|
||||
* Instantiates a new anon map.
|
||||
*/
|
||||
public AnonMap()
|
||||
{
|
||||
this.map = new HashMap<String, String>();
|
||||
this.unmap = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the all.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
*/
|
||||
public void addAll(final AnonMap source)
|
||||
{
|
||||
for (String key : source.getKeys())
|
||||
{
|
||||
String value = source.get(key);
|
||||
|
||||
this.map.put(key, value);
|
||||
this.unmap.put(value, key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ip.
|
||||
*
|
||||
* @param ip
|
||||
* the ip
|
||||
* @return the ip
|
||||
*/
|
||||
public String anonymizeIp(final String ip)
|
||||
{
|
||||
String result;
|
||||
|
||||
if (ip == null)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = this.map.get(ip);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
boolean ended = false;
|
||||
while (!ended)
|
||||
{
|
||||
if (ip.contains(":"))
|
||||
{
|
||||
result = Ipv6Generator.random(ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Ipv4Generator.random(ip);
|
||||
}
|
||||
|
||||
// Check it does not already exist.
|
||||
if ((this.map.get(result) == null) && (this.unmap.get(result) == null))
|
||||
{
|
||||
this.map.put(ip, result);
|
||||
this.unmap.put(ip, result);
|
||||
ended = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user.
|
||||
*
|
||||
* @param user
|
||||
* the user
|
||||
* @return the user
|
||||
*/
|
||||
public String anonymizeUser(final String user)
|
||||
{
|
||||
String result;
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
else if (user.equals("-"))
|
||||
{
|
||||
result = user;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = this.map.get(user);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
boolean ended = false;
|
||||
while (!ended)
|
||||
{
|
||||
result = UserGenerator.random(user);
|
||||
|
||||
// Check it does not already exist.
|
||||
if ((this.map.get(result) == null) && (this.unmap.get(result) == null))
|
||||
{
|
||||
this.map.put(user, result);
|
||||
this.unmap.put(user, result);
|
||||
ended = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the.
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @return the string
|
||||
*/
|
||||
public String get(final String key)
|
||||
{
|
||||
String result;
|
||||
|
||||
if (key == null)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = this.map.get(key);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the keys.
|
||||
*
|
||||
* @return the keys
|
||||
*/
|
||||
public StringSet getKeys()
|
||||
{
|
||||
StringSet result;
|
||||
|
||||
result = new StringSet(this.map.keySet());
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put.
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param value
|
||||
* the value
|
||||
*/
|
||||
public void put(final String key, final String value)
|
||||
{
|
||||
this.map.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Size.
|
||||
*
|
||||
* @return the int
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
int result;
|
||||
|
||||
result = this.map.size();
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* 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.anonymizer;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Class AnonMapFile.
|
||||
*/
|
||||
public final class AnonMapFile
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(AnonMapFile.class);
|
||||
|
||||
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
|
||||
|
||||
/**
|
||||
* Instantiates a new anon map file.
|
||||
*/
|
||||
private AnonMapFile()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Load.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @return the anon map
|
||||
*/
|
||||
public static AnonMap load(final File source)
|
||||
{
|
||||
AnonMap result;
|
||||
|
||||
result = new AnonMap();
|
||||
if ((source != null) && (source.exists()))
|
||||
{
|
||||
BufferedReader in = null;
|
||||
try
|
||||
{
|
||||
if (source.getName().endsWith(".gz"))
|
||||
{
|
||||
in = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(source))));
|
||||
}
|
||||
else
|
||||
{
|
||||
in = new BufferedReader(new InputStreamReader(new FileInputStream(source), DEFAULT_CHARSET_NAME));
|
||||
}
|
||||
|
||||
boolean ended = false;
|
||||
while (!ended)
|
||||
{
|
||||
String key = in.readLine();
|
||||
String value = in.readLine();
|
||||
|
||||
if (key == null)
|
||||
{
|
||||
ended = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
exception.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(in);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @param map
|
||||
* the map
|
||||
*/
|
||||
public static void save(final File target, final AnonMap map)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Null parameter source.");
|
||||
}
|
||||
else if (map == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Null parameter map.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintWriter out = null;
|
||||
try
|
||||
{
|
||||
if (target.getName().endsWith(".gz"))
|
||||
{
|
||||
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(target)));
|
||||
}
|
||||
else
|
||||
{
|
||||
out = new PrintWriter(new FileOutputStream(target));
|
||||
}
|
||||
|
||||
for (String key : map.getKeys())
|
||||
{
|
||||
out.println(key);
|
||||
out.println(map.get(key));
|
||||
}
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + target.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* 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.anonymizer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.april.logar.util.LineIterator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import fr.devinsy.logar.app.log.Log;
|
||||
import fr.devinsy.logar.app.log.LogParser;
|
||||
|
||||
/**
|
||||
* The Class Anonymizer.
|
||||
*/
|
||||
/**
|
||||
* @author cpm
|
||||
*
|
||||
*/
|
||||
public final class Anonymizer
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(Anonymizer.class);
|
||||
|
||||
public static final Pattern IPV4_PATTERN = Pattern.compile("\\d{0,3}\\.\\d{0,3}\\.\\d{0,3}\\.\\d{0,3}");
|
||||
public static final Pattern IPV6_PATTERN = Pattern.compile("([0-9a-f]{1,4}:{1,2}){4,7}([0-9a-f]){1,4}", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private AnonMap map;
|
||||
|
||||
/**
|
||||
* Instantiates a new anonymizer.
|
||||
*/
|
||||
public Anonymizer()
|
||||
{
|
||||
this.map = new AnonMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @param target
|
||||
* the target
|
||||
*/
|
||||
public void anonymize(final File source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Null parameter.");
|
||||
}
|
||||
else if (!source.isFile())
|
||||
{
|
||||
throw new IllegalArgumentException("Parameter is not a file.");
|
||||
}
|
||||
else if (!StringUtils.containsAny(source.getName(), "access", "error"))
|
||||
{
|
||||
throw new IllegalArgumentException("File name does not contain 'access' or 'error'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("== Anonymize log for [" + source.getName() + "]");
|
||||
boolean isAccessFile = source.getName().contains("access");
|
||||
|
||||
File target;
|
||||
if (source.getName().endsWith(".log.gz"))
|
||||
{
|
||||
target = new File(source.getParentFile(), source.getName().replace(".log.gz", "-anon.log.gz"));
|
||||
}
|
||||
else
|
||||
{
|
||||
target = new File(source.getParentFile(), source.getName().replace(".log", "-anon.log"));
|
||||
}
|
||||
|
||||
PrintWriter out = null;
|
||||
try
|
||||
{
|
||||
LineIterator iterator = new LineIterator(source);
|
||||
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(target)));
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
String line = iterator.next();
|
||||
|
||||
try
|
||||
{
|
||||
Log anon;
|
||||
if (isAccessFile)
|
||||
{
|
||||
Log log = LogParser.parseAccessLog(line);
|
||||
// logger.info("line={}", line);
|
||||
// logger.info("log =[{}][{}][{}]", log.getIp(),
|
||||
// log.getUser(), log.getDatetime());
|
||||
|
||||
anon = anonymizeAccess(log);
|
||||
// logger.info("anon=[{}][{}][{}]", anon.getIp(),
|
||||
// anon.getUser(), anon.getDatetime());
|
||||
// logger.info("anon={}", anon);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log log = LogParser.parseErrorLog(line);
|
||||
|
||||
anon = anonymizeError(log);
|
||||
}
|
||||
|
||||
// Make a check.
|
||||
if (StringUtils.equals(line, anon.getLine()))
|
||||
{
|
||||
System.err.println("Anonymize failed detected: " + line);
|
||||
}
|
||||
|
||||
out.println(anon);
|
||||
}
|
||||
catch (IllegalArgumentException exception)
|
||||
{
|
||||
System.out.println("Bad format line: " + line);
|
||||
exception.printStackTrace();
|
||||
}
|
||||
catch (DateTimeParseException exception)
|
||||
{
|
||||
System.out.println("Bad datetime format: " + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
System.err.println("Error with file [" + source.getAbsolutePath() + "]");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize.
|
||||
*
|
||||
* @param log
|
||||
* the log
|
||||
* @return the log
|
||||
*/
|
||||
public Log anonymizeAccess(final Log log)
|
||||
{
|
||||
Log result;
|
||||
|
||||
//
|
||||
String anonIp = this.map.anonymizeIp(log.getIp());
|
||||
String line = log.getLine().replace(log.getIp(), anonIp);
|
||||
|
||||
//
|
||||
if (!StringUtils.equals(log.getUser(), "-"))
|
||||
{
|
||||
String anonUser = this.map.anonymizeUser(log.getUser());
|
||||
line = line.replaceFirst(" " + log.getUser(), " " + anonUser);
|
||||
}
|
||||
|
||||
//
|
||||
result = new Log(line, log.getDatetime());
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize error.
|
||||
*
|
||||
* @param log
|
||||
* the log
|
||||
* @return the log
|
||||
*/
|
||||
public Log anonymizeError(final Log log)
|
||||
{
|
||||
Log result;
|
||||
|
||||
// Search and anonymized Ipv4 addresses.
|
||||
Matcher matcher = IPV4_PATTERN.matcher(log.getLine());
|
||||
String anonLine = log.getLine();
|
||||
while (matcher.find())
|
||||
{
|
||||
String left = anonLine.substring(0, matcher.start());
|
||||
String ipv4 = matcher.group();
|
||||
String right = anonLine.substring(matcher.end());
|
||||
|
||||
String anonIpv4 = this.map.get(ipv4);
|
||||
anonLine = left + anonIpv4 + right;
|
||||
}
|
||||
|
||||
// Search and anonymized Ipv4 addresses.
|
||||
matcher = IPV6_PATTERN.matcher(anonLine);
|
||||
while (matcher.find())
|
||||
{
|
||||
String left = anonLine.substring(0, matcher.start());
|
||||
String ipv6 = matcher.group();
|
||||
String right = anonLine.substring(matcher.end());
|
||||
|
||||
String anonIpv6 = this.map.get(ipv6);
|
||||
anonLine = left + anonIpv6 + right;
|
||||
}
|
||||
|
||||
result = new Log(anonLine, log.getDatetime());
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map table.
|
||||
*
|
||||
* @return the map table
|
||||
*/
|
||||
public AnonMap getMapTable()
|
||||
{
|
||||
AnonMap result;
|
||||
|
||||
result = this.map;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inits the map.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
*/
|
||||
public void loadMapTable(final File source)
|
||||
{
|
||||
if (source != null)
|
||||
{
|
||||
this.map.addAll(AnonMapFile.load(source));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save map table.
|
||||
*
|
||||
* @param target
|
||||
* the target
|
||||
*/
|
||||
public void SaveMapTable(final File target)
|
||||
{
|
||||
if (target != null)
|
||||
{
|
||||
AnonMapFile.save(target, this.map);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* 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.anonymizer;
|
||||
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Class RandomIpv4Generator.
|
||||
*/
|
||||
public final class Ipv4Generator
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(Ipv4Generator.class);
|
||||
|
||||
/**
|
||||
* Instantiates a new random ipv 4 generator.
|
||||
*/
|
||||
private Ipv4Generator()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ipv 4 max length part.
|
||||
*
|
||||
* @param length
|
||||
* the length (1..12)
|
||||
* @param column
|
||||
* the column (4...1)
|
||||
* @return the ipv 4 max length part
|
||||
*/
|
||||
public static int getIpv4MaxLengthPart(final int length, final int column)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((length < 1) || (length > 12))
|
||||
{
|
||||
throw new IllegalArgumentException("Bad length value: " + length);
|
||||
}
|
||||
else if ((column < 1) || (column > 12))
|
||||
{
|
||||
throw new IllegalArgumentException("Bad column value:" + column);
|
||||
}
|
||||
else
|
||||
{
|
||||
final int[] col4 = { 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3 };
|
||||
final int[] col3 = { 0, 0, 1, 2, 3, 3, 3, 3, 3, 0, 0, 0 };
|
||||
final int[] col2 = { 0, 1, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0 };
|
||||
final int[] col1 = { 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
final int[][] table = { col1, col2, col3, col4 };
|
||||
|
||||
result = table[column - 1][length - 1];
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
throw new IllegalArgumentException(String.format("Zero detected (%d, %d).", length, column));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ipv 4 max value part.
|
||||
*
|
||||
* @param length
|
||||
* the length
|
||||
* @param column
|
||||
* the column
|
||||
* @return the ipv 4 max value part
|
||||
*/
|
||||
public static int getIpv4MaxValuePart(final int length, final int column)
|
||||
{
|
||||
int result;
|
||||
|
||||
int max = getIpv4MaxLengthPart(length, column);
|
||||
|
||||
switch (max)
|
||||
{
|
||||
case 1:
|
||||
result = 9;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
result = 99;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
result = 255;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Bad value: " + max);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ipv 4 min length part.
|
||||
*
|
||||
* @param length
|
||||
* the length (1..12)
|
||||
* @param column
|
||||
* the column (4...1)
|
||||
* @return the ipv 4 min length part
|
||||
*/
|
||||
public static int getIpv4MinLengthPart(final int length, final int column)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((length < 1) || (length > 12))
|
||||
{
|
||||
throw new IllegalArgumentException("Bad length value: " + length);
|
||||
}
|
||||
else if ((column < 1) || (column > 12))
|
||||
{
|
||||
throw new IllegalArgumentException("Bad column value:" + column);
|
||||
}
|
||||
else
|
||||
{
|
||||
final int[] col4 = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 3 };
|
||||
final int[] col3 = { 0, 0, 1, 1, 1, 1, 1, 2, 3, 0, 0, 0 };
|
||||
final int[] col2 = { 0, 1, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0 };
|
||||
final int[] col1 = { 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
final int[][] table = { col1, col2, col3, col4 };
|
||||
|
||||
result = table[column - 1][length - 1];
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
throw new IllegalArgumentException(String.format("Zero detected (%d, %d).", length, column));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int getIpv4MinValuePart(final int length, final int column)
|
||||
{
|
||||
int result;
|
||||
|
||||
int max = getIpv4MinLengthPart(length, column);
|
||||
|
||||
switch (max)
|
||||
{
|
||||
case 1:
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
result = 10;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
result = 100;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Bad value: " + max);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a ipv4 of a fixed length.
|
||||
*
|
||||
* @param length
|
||||
* the length
|
||||
* @return the string
|
||||
*/
|
||||
public static String random(final int length)
|
||||
{
|
||||
String result;
|
||||
|
||||
if ((length < 7) || (length > 15))
|
||||
{
|
||||
throw new IllegalArgumentException("Bad parameter: " + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = length - 3;
|
||||
|
||||
int a = (int) RandomUtils.nextLong(getIpv4MinValuePart(size, 4), getIpv4MaxValuePart(size, 4) + 1);
|
||||
size -= String.valueOf(a).length();
|
||||
|
||||
int b = (int) RandomUtils.nextLong(getIpv4MinValuePart(size, 3), getIpv4MaxValuePart(size, 3) + 1);
|
||||
size -= String.valueOf(b).length();
|
||||
|
||||
int c = (int) RandomUtils.nextLong(getIpv4MinValuePart(size, 2), getIpv4MaxValuePart(size, 2) + 1);
|
||||
size -= String.valueOf(c).length();
|
||||
|
||||
int d = (int) RandomUtils.nextLong(getIpv4MinValuePart(size, 1), getIpv4MaxValuePart(size, 1) + 1);
|
||||
size -= String.valueOf(d).length();
|
||||
|
||||
result = String.format("%d.%d.%d.%d", a, b, c, d);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a ipv4 with the same length than the parameter.
|
||||
*
|
||||
* @param ip
|
||||
* the source
|
||||
* @return the string
|
||||
*/
|
||||
public static String random(final String ip)
|
||||
{
|
||||
String result;
|
||||
|
||||
if (ip == null)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = random(ip.length());
|
||||
|
||||
if (result.equals(ip))
|
||||
{
|
||||
random(ip);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.anonymizer;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Class RandomIpv6Generator.
|
||||
*/
|
||||
public final class Ipv6Generator
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(Ipv6Generator.class);
|
||||
|
||||
/**
|
||||
* Instantiates a new random ipv 6 generator.
|
||||
*/
|
||||
private Ipv6Generator()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Random.
|
||||
*
|
||||
* @param ip
|
||||
* the source
|
||||
* @return the string
|
||||
*/
|
||||
public static String random(final String ip)
|
||||
{
|
||||
String result;
|
||||
|
||||
if (ip == null)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer(ip.length());
|
||||
for (int index = 0; index < ip.length(); index++)
|
||||
{
|
||||
char c = ip.charAt(index);
|
||||
if (c == ':')
|
||||
{
|
||||
buffer.append(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.append(RandomStringUtils.random(1, "0123456789abcdef"));
|
||||
}
|
||||
}
|
||||
result = buffer.toString();
|
||||
|
||||
if (result.equals(ip))
|
||||
{
|
||||
random(ip);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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.anonymizer;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Class RandomUserGenerator.
|
||||
*/
|
||||
public final class UserGenerator
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(UserGenerator.class);
|
||||
|
||||
/**
|
||||
* Instantiates a new random user generator.
|
||||
*/
|
||||
private UserGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Random.
|
||||
*
|
||||
* @param length
|
||||
* the length
|
||||
* @return the string
|
||||
*/
|
||||
public static String random(final int length)
|
||||
{
|
||||
String result;
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Bad parameter: " + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = RandomStringUtils.random(length);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Random.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @return the string
|
||||
*/
|
||||
public static String random(final String source)
|
||||
{
|
||||
String result;
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
else if (source.equals("-"))
|
||||
{
|
||||
result = source;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = RandomStringUtils.random(source.length(), "abcdefghijklmnopqrstuvwxyz");
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Class Log.
|
||||
*/
|
||||
public final class Log
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(Log.class);
|
||||
|
||||
// Generic attributes.
|
||||
private String line;
|
||||
private LocalDateTime datetime;
|
||||
private String datetimeValue;
|
||||
|
||||
// Specific access log attributes.
|
||||
private String ip;
|
||||
private String user;
|
||||
private String request;
|
||||
private String status;
|
||||
private String bodyByteSent;
|
||||
private String referer;
|
||||
private String userAgent;
|
||||
|
||||
// Specific error log attributes.
|
||||
private String level;
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Instantiates a new log.
|
||||
*
|
||||
* @param log
|
||||
* the log
|
||||
*/
|
||||
public Log(final Log log)
|
||||
{
|
||||
this.line = log.getLine();
|
||||
this.datetime = log.getDatetime();
|
||||
this.datetimeValue = log.getDatetimeValue();
|
||||
|
||||
this.ip = log.getIp();
|
||||
this.user = log.getUser();
|
||||
this.request = log.getRequest();
|
||||
this.status = log.getStatus();
|
||||
this.bodyByteSent = log.getBodyByteSent();
|
||||
this.referer = log.getReferer();
|
||||
this.userAgent = log.getUserAgent();
|
||||
|
||||
this.level = log.getLevel();
|
||||
this.message = log.getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new log.
|
||||
*/
|
||||
public Log(final String line, final LocalDateTime datetime)
|
||||
{
|
||||
this.line = line;
|
||||
this.datetime = datetime;
|
||||
this.datetimeValue = null;
|
||||
|
||||
this.ip = null;
|
||||
this.user = null;
|
||||
this.request = null;
|
||||
this.referer = null;
|
||||
this.userAgent = null;
|
||||
|
||||
this.level = null;
|
||||
this.message = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concate access log.
|
||||
*/
|
||||
public void concateAccessLog()
|
||||
{
|
||||
this.line = String.format("%s - %s [%s] \"%s\" %s %s \"%s\" \"%s\"",
|
||||
this.ip, this.user, this.datetimeValue, this.request, this.status, this.bodyByteSent, this.referer, this.userAgent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concate error log.
|
||||
*/
|
||||
public void concateErrorLog()
|
||||
{
|
||||
this.line = String.format("%s [%s] %s",
|
||||
this.datetimeValue, this.level, this.message);
|
||||
}
|
||||
|
||||
public String getBodyByteSent()
|
||||
{
|
||||
return this.bodyByteSent;
|
||||
}
|
||||
|
||||
public LocalDateTime getDatetime()
|
||||
{
|
||||
return this.datetime;
|
||||
}
|
||||
|
||||
public String getDatetimeValue()
|
||||
{
|
||||
return this.datetimeValue;
|
||||
}
|
||||
|
||||
public String getIp()
|
||||
{
|
||||
return this.ip;
|
||||
}
|
||||
|
||||
public String getLevel()
|
||||
{
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public String getLine()
|
||||
{
|
||||
return this.line;
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return this.message;
|
||||
}
|
||||
|
||||
public String getReferer()
|
||||
{
|
||||
return this.referer;
|
||||
}
|
||||
|
||||
public String getRequest()
|
||||
{
|
||||
return this.request;
|
||||
}
|
||||
|
||||
public String getStatus()
|
||||
{
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public String getUser()
|
||||
{
|
||||
return this.user;
|
||||
}
|
||||
|
||||
public String getUserAgent()
|
||||
{
|
||||
return this.userAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce.
|
||||
*/
|
||||
public void reduce()
|
||||
{
|
||||
this.datetimeValue = null;
|
||||
this.request = null;
|
||||
this.referer = null;
|
||||
this.userAgent = null;
|
||||
this.status = null;
|
||||
this.bodyByteSent = null;
|
||||
|
||||
this.level = null;
|
||||
this.message = null;
|
||||
}
|
||||
|
||||
public void setBodyByteSent(final String bodyByteSent)
|
||||
{
|
||||
this.bodyByteSent = bodyByteSent;
|
||||
}
|
||||
|
||||
public void setDatetimeValue(final String datetimeValue)
|
||||
{
|
||||
this.datetimeValue = datetimeValue;
|
||||
}
|
||||
|
||||
public void setIp(final String ip)
|
||||
{
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public void setLevel(final String level)
|
||||
{
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public void setMessage(final String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void setReferer(final String referer)
|
||||
{
|
||||
this.referer = referer;
|
||||
}
|
||||
|
||||
public void setRequest(final String request)
|
||||
{
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public void setStatus(final String status)
|
||||
{
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public void setUser(final String user)
|
||||
{
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user agent.
|
||||
*
|
||||
* @param userAgent
|
||||
* the new user agent
|
||||
*/
|
||||
public void setUserAgent(final String userAgent)
|
||||
{
|
||||
this.userAgent = userAgent;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String result;
|
||||
|
||||
result = this.line;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.april.logar.util.CompareUtils;
|
||||
|
||||
/**
|
||||
* The Class LogComparator.
|
||||
*/
|
||||
public class LogComparator implements Comparator<Log>
|
||||
{
|
||||
public enum Sorting
|
||||
{
|
||||
DATETIME
|
||||
}
|
||||
|
||||
private Sorting sorting;
|
||||
|
||||
/**
|
||||
* Instantiates a new organization comparator.
|
||||
*
|
||||
* @param sorting
|
||||
* the sorting
|
||||
*/
|
||||
public LogComparator(final Sorting sorting)
|
||||
{
|
||||
this.sorting = sorting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare.
|
||||
*
|
||||
* @param alpha
|
||||
* the alpha
|
||||
* @param bravo
|
||||
* the bravo
|
||||
* @return the int
|
||||
*/
|
||||
@Override
|
||||
public int compare(final Log alpha, final Log bravo)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = compare(alpha, bravo, this.sorting);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare.
|
||||
*
|
||||
* @param alpha
|
||||
* the alpha
|
||||
* @param bravo
|
||||
* the bravo
|
||||
* @param sorting
|
||||
* the sorting
|
||||
* @return the int
|
||||
*/
|
||||
public static int compare(final Log alpha, final Log bravo, final Sorting sorting)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (sorting == null)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (sorting)
|
||||
{
|
||||
default:
|
||||
case DATETIME:
|
||||
result = CompareUtils.compare(getDatetime(alpha), getDatetime(bravo));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the datetime.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @return the datetime
|
||||
*/
|
||||
public static LocalDateTime getDatetime(final Log source)
|
||||
{
|
||||
LocalDateTime result;
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = source.getDatetime();
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.april.logar.util.LineIterator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import fr.devinsy.cmdexec.CmdExecException;
|
||||
import fr.devinsy.cmdexec.CmdExecUtils;
|
||||
|
||||
/**
|
||||
* The Class LogFile.
|
||||
*/
|
||||
public final class LogFile
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(LogFile.class);
|
||||
|
||||
/**
|
||||
* Instantiates a new log file.
|
||||
*/
|
||||
private LogFile()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Load access log.
|
||||
*
|
||||
* @param file
|
||||
* the file
|
||||
* @return the logs
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public static Logs loadAccessLog(final File file) throws IOException
|
||||
{
|
||||
Logs result;
|
||||
|
||||
result = loadAccessLog(file, LogMode.NORMAL);
|
||||
|
||||
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();
|
||||
Log log = LogParser.parseAccessLog(line);
|
||||
if (mode == LogMode.REDUCED)
|
||||
{
|
||||
log.reduce();
|
||||
}
|
||||
result.add(log);
|
||||
}
|
||||
|
||||
//
|
||||
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();
|
||||
Log log = LogParser.parseErrorLog(line);
|
||||
result.add(log);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load log file.
|
||||
*
|
||||
* @param file
|
||||
* the file
|
||||
* @return the logs
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public static Logs loadLogFile(final File file) throws IOException
|
||||
{
|
||||
Logs result;
|
||||
|
||||
result = loadLogFile(file, LogMode.NORMAL);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load log file.
|
||||
*
|
||||
* @param file
|
||||
* the file
|
||||
* @param mode
|
||||
* the mode
|
||||
* @return the logs
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public static Logs loadLogFile(final File file, final LogMode mode) throws IOException
|
||||
{
|
||||
Logs result;
|
||||
|
||||
if (file == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Null parameter.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file.getName().contains("access"))
|
||||
{
|
||||
result = loadAccessLog(file, mode);
|
||||
}
|
||||
else if (file.getName().contains("error"))
|
||||
{
|
||||
result = loadErrorLog(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Bad named file (missing access or error).");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save access log.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @throws IOException
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public static void saveLogs(final File target, final Logs logs) throws FileNotFoundException, IOException
|
||||
{
|
||||
PrintWriter out = null;
|
||||
try
|
||||
{
|
||||
if (target.getName().endsWith(".gz"))
|
||||
{
|
||||
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(target)));
|
||||
}
|
||||
else
|
||||
{
|
||||
out = new PrintWriter(new FileOutputStream(target));
|
||||
}
|
||||
|
||||
for (Log log : logs)
|
||||
{
|
||||
out.println(log.getLine());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort access log.
|
||||
*
|
||||
* @param target
|
||||
* the target
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void sortLogFile(final File file) throws IOException
|
||||
{
|
||||
File workFile = new File(file.getParent(), file.getName() + ".tmp");
|
||||
|
||||
Logs logs = loadLogFile(file, LogMode.REDUCED);
|
||||
logs.sortByDatetime();
|
||||
saveLogs(workFile, logs);
|
||||
|
||||
File backup = new File(file.getParentFile(), file.getName() + ".bak");
|
||||
if (file.renameTo(backup))
|
||||
{
|
||||
if (!workFile.renameTo(file))
|
||||
{
|
||||
backup.renameTo(file);
|
||||
}
|
||||
}
|
||||
|
||||
// Check.
|
||||
try
|
||||
{
|
||||
String out = CmdExecUtils.run("/bin/bash -c \"zcat " + file.getAbsolutePath() + "| sort | sha1sum \"");
|
||||
System.out.print(out);
|
||||
out = CmdExecUtils.run("/bin/bash -c \"zcat " + file.getAbsolutePath() + ".bak | sort | sha1sum \"");
|
||||
System.out.println(out);
|
||||
}
|
||||
catch (CmdExecException exception)
|
||||
{
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 LogMode.
|
||||
*/
|
||||
public enum LogMode
|
||||
{
|
||||
NORMAL,
|
||||
REDUCED;
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* The Class LogParser.
|
||||
*/
|
||||
public final class LogParser
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(LogParser.class);
|
||||
|
||||
public static Pattern NGINX_ACCESSLOG_LINE_PATTERN = Pattern.compile(
|
||||
"^(?<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.
|
||||
*/
|
||||
private LogParser()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* From access log.
|
||||
*
|
||||
* @param line
|
||||
* the line
|
||||
* @return the log
|
||||
*
|
||||
* log_format combined '$remote_addr - $remote_user [$time_local] '
|
||||
* '"$request" $status $body_bytes_sent ' '"$http_referer"
|
||||
* "$http_user_agent"';
|
||||
*/
|
||||
public static Log parseAccessLog(final String line)
|
||||
{
|
||||
Log result;
|
||||
|
||||
try
|
||||
{
|
||||
Matcher matcher = NGINX_ACCESSLOG_LINE_PATTERN.matcher(line);
|
||||
if (matcher.matches())
|
||||
{
|
||||
String dateTimeValue = matcher.group("datetime");
|
||||
LocalDateTime dateTime = LocalDateTime.parse(dateTimeValue, DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z").withLocale(Locale.ENGLISH));
|
||||
|
||||
result = new Log(line, dateTime);
|
||||
|
||||
result.setDatetimeValue(matcher.group("datetime"));
|
||||
result.setIp(matcher.group("remoteAddress"));
|
||||
result.setUser(matcher.group("remoteUser"));
|
||||
result.setRequest(matcher.group("request"));
|
||||
result.setStatus(matcher.group("status"));
|
||||
result.setBodyByteSent(matcher.group("bodyBytesSent"));
|
||||
result.setReferer(matcher.group("referer"));
|
||||
result.setUserAgent(matcher.group("userAgent"));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Bad line format: " + line);
|
||||
}
|
||||
}
|
||||
catch (DateTimeParseException exception)
|
||||
{
|
||||
throw new IllegalArgumentException("Bad line format (date): " + line);
|
||||
}
|
||||
|
||||
//
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Class LogUtils.
|
||||
*/
|
||||
public final class LogUtils
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(LogUtils.class);
|
||||
|
||||
/**
|
||||
* Instantiates a new log utils.
|
||||
*/
|
||||
private LogUtils()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The Class Logs.
|
||||
*/
|
||||
public class Logs extends ArrayList<Log>
|
||||
{
|
||||
private static final long serialVersionUID = 869606603972696142L;
|
||||
|
||||
/**
|
||||
* Instantiates a new logs.
|
||||
*/
|
||||
public Logs()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new logs.
|
||||
*
|
||||
* @param initialCapacity
|
||||
* the initial capacity
|
||||
*/
|
||||
public Logs(final int initialCapacity)
|
||||
{
|
||||
super(initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort.
|
||||
*
|
||||
* @param sorting
|
||||
* the sorting
|
||||
* @return the logs
|
||||
*/
|
||||
public Logs sort(final LogComparator.Sorting sorting)
|
||||
{
|
||||
Logs result;
|
||||
|
||||
sort(new LogComparator(sorting));
|
||||
|
||||
result = this;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by datetime.
|
||||
*
|
||||
* @return the logs
|
||||
*/
|
||||
public Logs sortByDatetime()
|
||||
{
|
||||
Logs result;
|
||||
|
||||
result = sort(LogComparator.Sorting.DATETIME);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ import org.april.logar.util.BuildInformation;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import fr.devinsy.logar.app.DryOption;
|
||||
import fr.devinsy.logar.app.Logar;
|
||||
import fr.devinsy.strings.StringList;
|
||||
|
||||
|
@ -53,10 +54,14 @@ public final class LogarCLI
|
|||
message.append("Logar CLI version ").appendln(BuildInformation.instance().version());
|
||||
message.appendln("Usage:");
|
||||
message.appendln(" logar [ -h | -help | --help ]");
|
||||
message.appendln(" logar -version");
|
||||
message.appendln(" logar archive source target");
|
||||
message.appendln(" logar test source");
|
||||
message.appendln(" logar anonymize source target");
|
||||
message.appendln(" logar [ -v | -version | --version ]");
|
||||
message.appendln(" logar anonymize fileordirectory [mapfile] anonymize ip and user");
|
||||
message.appendln(" logar archive source target archive previous month from /var/log/nginx/ tree");
|
||||
message.appendln(" logar check fileordirectory check line format in log file");
|
||||
message.appendln(" logar checksort fileordirectory check sort in log file");
|
||||
message.appendln(" logar sort fileordirectory sort log files by datetime");
|
||||
message.appendln(" logar testarchive source test archive without writing");
|
||||
message.appendln(" logar testconcate fileordirectory test line concate in log file");
|
||||
|
||||
logger.info(message.toString());
|
||||
}
|
||||
|
@ -163,69 +168,84 @@ public final class LogarCLI
|
|||
}
|
||||
});
|
||||
|
||||
logger.info("{} Logar call: {}", LocalDateTime.now(), new StringList(args).toStringSeparatedBy(" "));
|
||||
try
|
||||
{
|
||||
logger.info("{} Logar call: {}", LocalDateTime.now(), new StringList(args).toStringSeparatedBy(" "));
|
||||
|
||||
if (isMatching(args))
|
||||
{
|
||||
logger.info("No parameter.");
|
||||
displayHelp();
|
||||
}
|
||||
else if (isMatching(args, "(-h|--h|--help)"))
|
||||
{
|
||||
displayHelp();
|
||||
}
|
||||
else if (isMatching(args, "(-v|-version|--version)"))
|
||||
{
|
||||
displayVersion();
|
||||
}
|
||||
else if (isMatching(args, "anonymize", "\\s*\\S+\\s*", "\\s*\\S+\\s*"))
|
||||
{
|
||||
try
|
||||
if (isMatching(args))
|
||||
{
|
||||
logger.info("No parameter.");
|
||||
displayHelp();
|
||||
}
|
||||
else if (isMatching(args, "(-h|--h|--help)"))
|
||||
{
|
||||
displayHelp();
|
||||
}
|
||||
else if (isMatching(args, "(-v|-version|--version)"))
|
||||
{
|
||||
displayVersion();
|
||||
}
|
||||
else if (isMatching(args, "anonymize", "\\s*\\S+\\s*"))
|
||||
{
|
||||
File source = new File(args[1]);
|
||||
|
||||
Logar.anonymize(source);
|
||||
}
|
||||
else if (isMatching(args, "anonymize", "\\s*\\S+\\s*", "\\s*\\S+\\s*"))
|
||||
{
|
||||
File source = new File(args[1]);
|
||||
File map = new File(args[2]);
|
||||
|
||||
Logar.anonymize(source, map);
|
||||
}
|
||||
else if (isMatching(args, "archive", "\\s*\\S+\\s*", "\\s*\\S+\\s*"))
|
||||
{
|
||||
File source = new File(args[1]);
|
||||
File target = new File(args[2]);
|
||||
|
||||
Logar.anonymize(source, target);
|
||||
Logar.archive(source, target, DryOption.OFF);
|
||||
}
|
||||
catch (Exception exception)
|
||||
else if (isMatching(args, "check", "\\s*\\S+\\s*"))
|
||||
{
|
||||
logger.error("Error: {}", exception.getMessage());
|
||||
exception.printStackTrace();
|
||||
File source = new File(args[1]);
|
||||
|
||||
Logar.checkLogFiles(source);
|
||||
}
|
||||
}
|
||||
else if (isMatching(args, "archive", "\\s*\\S+\\s*", "\\s*\\S+\\s*"))
|
||||
{
|
||||
try
|
||||
else if (isMatching(args, "checksort", "\\s*\\S+\\s*"))
|
||||
{
|
||||
File source = new File(args[1]);
|
||||
|
||||
Logar.checkSort(source);
|
||||
}
|
||||
else if (isMatching(args, "sort", "\\s*\\S+\\s*"))
|
||||
{
|
||||
File source = new File(args[1]);
|
||||
|
||||
Logar.sort(source);
|
||||
}
|
||||
else if (isMatching(args, "testarchive", "\\s*\\S+\\s*", "\\s*\\S+\\s*"))
|
||||
{
|
||||
File source = new File(args[1]);
|
||||
File target = new File(args[2]);
|
||||
|
||||
Logar.archive(source, target);
|
||||
Logar.archive(source, target, DryOption.ON);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.error("Error: {}", exception.getMessage());
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
else if (isMatching(args, "test", "\\s*\\S+\\s*"))
|
||||
{
|
||||
try
|
||||
else if (isMatching(args, "testconcate", "\\s*\\S+\\s*"))
|
||||
{
|
||||
File source = new File(args[1]);
|
||||
|
||||
Logar.testParsing(source);
|
||||
Logar.testConcate(source);
|
||||
}
|
||||
catch (Exception exception)
|
||||
else
|
||||
{
|
||||
logger.error("Error: {}", exception.getMessage());
|
||||
exception.printStackTrace();
|
||||
logger.info("Bad usage.");
|
||||
displayHelp();
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.info("Bad usage.");
|
||||
displayHelp();
|
||||
logger.error("Error: {}", exception.getMessage());
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
package org.april.logar.util;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -235,6 +237,49 @@ public class CompareUtils
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare natural.
|
||||
*
|
||||
* @param alpha
|
||||
* the alpha
|
||||
* @param bravo
|
||||
* the bravo
|
||||
* @return the int
|
||||
*/
|
||||
public static int compareNatural(final String alpha, final String bravo)
|
||||
{
|
||||
int result;
|
||||
|
||||
Pattern pattern = Pattern.compile("(?<left>.*)(?<digits>\\d+)(?<right>.*)");
|
||||
|
||||
Matcher matcherA = pattern.matcher(alpha);
|
||||
Matcher matcherB = pattern.matcher(bravo);
|
||||
if ((matcherA.find()) && (matcherB.find()))
|
||||
{
|
||||
result = StringUtils.compare(matcherA.group("left"), matcherB.group("left"));
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
Long a = Long.valueOf(matcherA.group("digits"));
|
||||
Long b = Long.valueOf(matcherB.group("digits"));
|
||||
|
||||
result = compare(a, b);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
result = compareNatural(matcherA.group("right"), matcherB.group("right"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = StringUtils.compare(alpha, bravo);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare reverse.
|
||||
*
|
||||
|
|
|
@ -89,7 +89,7 @@ public class FileComparator implements Comparator<File>
|
|||
{
|
||||
default:
|
||||
case NAME:
|
||||
result = CompareUtils.compare(getName(alpha), getName(bravo));
|
||||
result = CompareUtils.compareNatural(getName(alpha), getName(bravo));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.april.logar.util;
|
|||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The Class Files.
|
||||
|
@ -47,6 +49,163 @@ public class Files extends ArrayList<File>
|
|||
super(initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep.
|
||||
*
|
||||
* @param regex
|
||||
* the regex
|
||||
* @return the files
|
||||
*/
|
||||
public Files keep(final String regex)
|
||||
{
|
||||
Files result;
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
|
||||
Iterator<File> iterator = iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
File file = iterator.next();
|
||||
|
||||
if (!pattern.matcher(file.getName()).matches())
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
result = this;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep directories.
|
||||
*
|
||||
* @return the files
|
||||
*/
|
||||
public Files keepDirectoryType()
|
||||
{
|
||||
Files result;
|
||||
|
||||
Iterator<File> iterator = iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
File file = iterator.next();
|
||||
if (!file.isDirectory())
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
result = this;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep file type.
|
||||
*
|
||||
* @return the files
|
||||
*/
|
||||
public Files keepFileType()
|
||||
{
|
||||
Files result;
|
||||
|
||||
Iterator<File> iterator = iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
File file = iterator.next();
|
||||
if (!file.isFile())
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
result = this;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the containing.
|
||||
*
|
||||
* @param token
|
||||
* the token
|
||||
* @return the files
|
||||
*/
|
||||
public Files removeContaining(final String token)
|
||||
{
|
||||
Files result;
|
||||
|
||||
Iterator<File> iterator = iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
File file = iterator.next();
|
||||
if (file.getName().contains(token))
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
result = this;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the file type.
|
||||
*
|
||||
* @return the files
|
||||
*/
|
||||
public Files removeFileType()
|
||||
{
|
||||
Files result;
|
||||
|
||||
Iterator<File> iterator = iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
File file = iterator.next();
|
||||
if (file.isFile())
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
result = this;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the hidden.
|
||||
*
|
||||
* @return the files
|
||||
*/
|
||||
public Files removeHidden()
|
||||
{
|
||||
Files result;
|
||||
|
||||
Iterator<File> iterator = iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
File file = iterator.next();
|
||||
if (file.getName().startsWith("."))
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
result = this;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort.
|
||||
*
|
||||
|
@ -81,6 +240,16 @@ public class Files extends ArrayList<File>
|
|||
return result;
|
||||
}
|
||||
|
||||
public Files sortByPathname()
|
||||
{
|
||||
Files result;
|
||||
|
||||
result = sort(FileComparator.Sorting.NAME);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Of.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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 org.april.logar.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* The Class FilesUtils.
|
||||
*/
|
||||
public class FilesUtils
|
||||
{
|
||||
|
||||
/**
|
||||
* Instantiates a new files utils.
|
||||
*/
|
||||
private FilesUtils()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* List recursively.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @return the files
|
||||
*/
|
||||
public static Files listRecursively(final File source)
|
||||
{
|
||||
Files result;
|
||||
|
||||
result = new Files();
|
||||
if (source != null)
|
||||
{
|
||||
if (source.isFile())
|
||||
{
|
||||
result.add(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (File file : source.listFiles())
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
result.addAll(listRecursively(file));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* List recursively.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @param extensions
|
||||
* the extensions
|
||||
* @return the files
|
||||
*/
|
||||
public static Files searchEndingWith(final File source, final String... extensions)
|
||||
{
|
||||
Files result;
|
||||
|
||||
result = new Files();
|
||||
|
||||
Files full = listRecursively(source);
|
||||
for (File file : full)
|
||||
{
|
||||
if (StringUtils.endsWithAny(file.getName(), extensions))
|
||||
{
|
||||
result.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search recursively.
|
||||
*
|
||||
* @param source
|
||||
* the source
|
||||
* @param regex
|
||||
* the regex
|
||||
* @return the files
|
||||
*/
|
||||
public static Files search(final File source, final String regex)
|
||||
{
|
||||
Files result;
|
||||
|
||||
result = new Files();
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
|
||||
Files full = listRecursively(source);
|
||||
for (File file : full)
|
||||
{
|
||||
if (pattern.matcher(file.getName()).matches())
|
||||
{
|
||||
result.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Test;
|
||||
|
||||
import fr.devinsy.logar.app.LogarException;
|
||||
import fr.devinsy.logar.app.anonymizer.Ipv4Generator;
|
||||
|
||||
/**
|
||||
* The Class VisitCountersTest.
|
||||
|
@ -47,6 +48,20 @@ public class TestFoo
|
|||
Assert.assertEquals(1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test02() throws Exception
|
||||
{
|
||||
System.out.println(" 7: " + Ipv4Generator.random(7));
|
||||
System.out.println(" 8: " + Ipv4Generator.random(8));
|
||||
System.out.println(" 9: " + Ipv4Generator.random(9));
|
||||
System.out.println("10: " + Ipv4Generator.random(10));
|
||||
System.out.println("11: " + Ipv4Generator.random(11));
|
||||
System.out.println("12: " + Ipv4Generator.random(12));
|
||||
System.out.println("13: " + Ipv4Generator.random(13));
|
||||
System.out.println("14: " + Ipv4Generator.random(14));
|
||||
System.out.println("15: " + Ipv4Generator.random(15));
|
||||
}
|
||||
|
||||
/**
|
||||
* After class.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue