/* * Copyright (C) 2021 Christian Pierre MOMON * * 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 . */ package fr.devinsy.logar.app; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.time.LocalDateTime; import java.time.YearMonth; import java.time.format.DateTimeParseException; 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. */ public final class Logar { private static Logger logger = LoggerFactory.getLogger(Logar.class); public static String LOGFILE_PATTERN = "^.+(\\.|_)(log|log\\.gz|log\\.\\d+|log\\.\\d+\\.gz)$"; /** * Instantiates a new log tool. */ private Logar() { } /** * Anonymize. * * @param source * the source */ public static void anonymize(final File source) { anonymize(source, null); } /** * Anonymize. * * @param source * the source * @param mapFile * the map file */ 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); } } } /** * Archive. * * @param source * the source * @param target * the target * @throws IOException */ public static void archive(final File source, final File target, final DryOption dry) throws IOException { archiveAccessFiles(source, target, dry); archiveErrorFiles(source, target, dry); } /** * Test archive access files. * * @param source * the source * @throws IOException */ public static void archiveAccessFiles(final File source, final File target, final DryOption dry) throws IOException { if (source == null) { throw new IllegalArgumentException("Null parameter [source]"); } else if (!source.isDirectory()) { throw new IllegalArgumentException("Source parameter is not a directory."); } else if (!target.isDirectory()) { throw new IllegalArgumentException("Target parameter is not a directory."); } else { YearMonth targetYearMonth = YearMonth.now().minusMonths(1); Stats counter = new Stats(); for (File directory : Files.of(source).removeHidden().keepDirectoryType().sortByName()) { 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()) { targetDirectory.mkdirs(); out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(targetFile))); } for (File file : Files.of(directory).sortByName()) { if ((!file.isDirectory()) && (file.getName().contains("access"))) { logger.info(file.getName()); try { LineIterator iterator = new LineIterator(file); while (iterator.hasNext()) { String line = iterator.next(); counter.incLineCount(); try { Log log = LogParser.parseAccessLog(line); counter.incSuccessLineCount(); if (YearMonth.from(log.getDatetime()).equals(targetYearMonth)) { if (dry.isOff()) { out.println(line); } } } 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); } System.out.println("====================================================="); counter.stop(); System.out.println(counter.toString()); } } /** * Archive error files. * * @param source * the source * @param target * the target * @throws IOException * Signals that an I/O exception has occurred. */ public static void archiveErrorFiles(final File source, final File target, final DryOption dry) throws IOException { if (source == null) { throw new IllegalArgumentException("Null parameter [source]"); } else if (!source.isDirectory()) { throw new IllegalArgumentException("Source parameter is not a directory."); } else if (!target.isDirectory()) { throw new IllegalArgumentException("Target parameter is not a directory."); } else { YearMonth targetYearMonth = YearMonth.now().minusMonths(1); Stats counter = new Stats(); counter.start(); for (File directory : Files.of(source).removeHidden().keepDirectoryType().sortByName()) { 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()) { targetDirectory.mkdirs(); out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(targetFile))); } for (File file : Files.of(directory).sortByName()) { if ((!file.isDirectory()) && (file.getName().contains("error"))) { // logger.info(file.getName()); try { LineIterator iterator = new LineIterator(file); while (iterator.hasNext()) { String line = iterator.next(); counter.incLineCount(); try { Log log = LogParser.parseErrorLog(line); counter.incSuccessLineCount(); if (YearMonth.from(log.getDatetime()).equals(targetYearMonth)) { if (dry.isOff()) { out.println(line); } } } 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); } System.out.println("====================================================="); counter.stop(); System.out.println(counter.toString()); } } /** * Check access files. * * @param file * the source */ public static void checkLogFile(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("== Check parse 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 (isAccessFile) { 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(); } if (badLineCount > 0) { System.out.println("Bad line count: " + badLineCount + "/" + lineCount); } } } /** * Check. * * @param source * the source */ public static void checkLogFiles(final File source) { 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 file. * * @param file * the file * @throws IOException * Signals that an I/O exception has occurred. */ public static void checkSortFile(final File file) throws IOException { if (file == null) { throw new IllegalArgumentException("Null parameter [source]"); } else if (!file.isFile()) { throw new IllegalArgumentException("Source parameter is not a file."); } else { 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()) { String line = iterator.next(); lineCount += 1; LocalDateTime date; if (isAccessFile) { date = LogParser.parseAccessLog(line).getDatetime(); } else { date = LogParser.parseErrorLog(line).getDatetime(); } 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); } } /** * Test concate file. * * @param file * the file */ 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 { Log source; Log target; if (isAccessFile) { 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(); } if (badLineCount > 0) { System.out.println("Bad line count: " + badLineCount + "/" + lineCount); } } } }