From 7142cd06dd6e007a84ee6fdd869689760479b30c Mon Sep 17 00:00:00 2001 From: HorizonCode Date: Mon, 25 Jul 2022 09:27:49 +0200 Subject: [PATCH] add Logger --- pom.xml | 5 ++ src/main/java/Bootstrapper.java | 18 +----- .../net/horizoncode/sysbackup/SysBackup.java | 29 ++++++++++ .../sysbackup/cli/CLIProcessor.java | 55 ++++++++++++------- .../horizoncode/sysbackup/logging/Logger.java | 48 ++++++++++++++++ .../sysbackup/tasks/TaskBuilder.java | 21 ++++--- .../sysbackup/tasks/impl/DatabaseTask.java | 13 ++++- .../sysbackup/tasks/impl/FileSystemTask.java | 11 +++- .../sysbackup/threading/ThreadPool.java | 8 +-- 9 files changed, 153 insertions(+), 55 deletions(-) create mode 100644 src/main/java/net/horizoncode/sysbackup/SysBackup.java create mode 100644 src/main/java/net/horizoncode/sysbackup/logging/Logger.java diff --git a/pom.xml b/pom.xml index a980494..9f1694b 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,11 @@ commons-lang3 3.12.0 + + com.diogonunes + JColor + 5.5.1 + junit diff --git a/src/main/java/Bootstrapper.java b/src/main/java/Bootstrapper.java index 41ab6b2..444f6c3 100644 --- a/src/main/java/Bootstrapper.java +++ b/src/main/java/Bootstrapper.java @@ -1,24 +1,10 @@ -import net.horizoncode.sysbackup.cli.CLIProcessor; +import net.horizoncode.sysbackup.SysBackup; -import java.io.File; import java.net.URISyntaxException; public class Bootstrapper { public static void main(String[] args) throws URISyntaxException { - - File jarFile = - new File(Bootstrapper.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - - File executionPath = - new File( - new File(Bootstrapper.class.getProtectionDomain().getCodeSource().getLocation().toURI()) - .getParent()); - - if (!jarFile.isFile()) System.out.println("Dev environment detected!"); - - CLIProcessor cliProcessor = new CLIProcessor(); - cliProcessor.startCLI( - args, jarFile.isFile() ? executionPath : new File(System.getProperty("user.dir"))); + new SysBackup().start(args); } } diff --git a/src/main/java/net/horizoncode/sysbackup/SysBackup.java b/src/main/java/net/horizoncode/sysbackup/SysBackup.java new file mode 100644 index 0000000..652a263 --- /dev/null +++ b/src/main/java/net/horizoncode/sysbackup/SysBackup.java @@ -0,0 +1,29 @@ +package net.horizoncode.sysbackup; + +import lombok.Getter; +import net.horizoncode.sysbackup.cli.CLIProcessor; +import net.horizoncode.sysbackup.logging.Logger; + +import java.io.File; +import java.net.URISyntaxException; + +public class SysBackup { + + @Getter private static final Logger logger = Logger.builder().logFile(new File("log")).build(); + + public void start(String[] args) throws URISyntaxException { + File jarFile = + new File(SysBackup.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + + File executionPath = + new File( + new File(SysBackup.class.getProtectionDomain().getCodeSource().getLocation().toURI()) + .getParent()); + + if (!jarFile.isFile()) getLogger().log(Logger.LogLevel.INFO, "Dev environment detected!"); + + CLIProcessor cliProcessor = new CLIProcessor(); + cliProcessor.startCLI( + args, jarFile.isFile() ? executionPath : new File(System.getProperty("user.dir"))); + } +} diff --git a/src/main/java/net/horizoncode/sysbackup/cli/CLIProcessor.java b/src/main/java/net/horizoncode/sysbackup/cli/CLIProcessor.java index 9053eee..7579671 100644 --- a/src/main/java/net/horizoncode/sysbackup/cli/CLIProcessor.java +++ b/src/main/java/net/horizoncode/sysbackup/cli/CLIProcessor.java @@ -1,6 +1,8 @@ package net.horizoncode.sysbackup.cli; +import net.horizoncode.sysbackup.SysBackup; import net.horizoncode.sysbackup.config.Config; +import net.horizoncode.sysbackup.logging.Logger; import net.horizoncode.sysbackup.tasks.TaskBuilder; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; @@ -27,7 +29,7 @@ public class CLIProcessor { " java -jar sysbackup.jar generateTaskConf magento", " java -jar sysbackup.jar backup magento" }; - Arrays.stream(usage).forEachOrdered(System.out::println); + Arrays.stream(usage).forEach(System.out::println); } public void startCLI(String[] args, File executionPath) { @@ -37,25 +39,28 @@ public class CLIProcessor { return; } + Logger logger = SysBackup.getLogger(); + for (int index = 0; index < args.length; index++) { switch (args[index].toLowerCase(Locale.ROOT)) { case "backup": { if (args.length <= 1) { - System.err.println("Please specify a output task config name!"); + logger.log(Logger.LogLevel.WARN, "Please specify a output task config name!"); return; } String fileName = args[1]; File tasksFolder = new File(executionPath, "tasks"); if (!tasksFolder.exists()) - if (!tasksFolder.mkdir()) System.err.println("Failed to create tasks folder!"); + if (!tasksFolder.mkdir()) + logger.log(Logger.LogLevel.ERROR, "Failed to create tasks folder!"); File taskFile = new File(tasksFolder, fileName + ".toml"); if (!taskFile.exists()) { - System.err.println("TaskFile " + fileName + ".toml does not exist!"); + logger.log(Logger.LogLevel.ERROR, "TaskFile %s.toml does not exist!", fileName); return; } - System.out.println("setuping TaskBuilder..."); + logger.log(Logger.LogLevel.INFO, "setupping TaskBuilder..."); Config taskConfig = new Config(taskFile); TaskBuilder taskBuilder = TaskBuilder.builder() @@ -69,48 +74,57 @@ public class CLIProcessor { case "generatetaskconf": { if (args.length <= 1) { - System.err.println("Please specify a output task config name!"); + logger.log(Logger.LogLevel.ERROR, "Please specify a output task config name!"); return; } String fileName = args[1]; File tasksFolder = new File(executionPath, "tasks"); if (!tasksFolder.exists()) - if (!tasksFolder.mkdir()) System.err.println("Failed to create tasks folder!"); - System.out.println("Saving task config " + fileName + ".toml..."); - FileUtils.copyInputStreamToFile( - Objects.requireNonNull(getClass().getResourceAsStream("/" + "exampletask.toml")), - new File(tasksFolder, fileName + ".toml")); - System.out.println(fileName + ".toml saved!"); + if (!tasksFolder.mkdir()) + logger.log(Logger.LogLevel.ERROR, "Failed to create tasks folder!"); + logger.log(Logger.LogLevel.INFO, "Saving task config %s.toml...", fileName); + try { + FileUtils.copyInputStreamToFile( + Objects.requireNonNull( + getClass().getResourceAsStream("/" + "exampletask.toml")), + new File(tasksFolder, fileName + ".toml")); + } catch (IOException exception) { + logger.log(Logger.LogLevel.ERROR, "Failed to save task config."); + } + logger.log(Logger.LogLevel.INFO, "%s.toml saved!", fileName); break; } case "checktaskconf": { if (args.length <= 1) { - System.err.println("Please specify a output task config name!"); + logger.log(Logger.LogLevel.ERROR, "Please specify a output task config name!"); return; } String fileName = args[1]; File tasksFolder = new File(executionPath, "tasks"); if (!tasksFolder.exists()) - if (!tasksFolder.mkdir()) System.err.println("Failed to create tasks folder!"); + if (!tasksFolder.mkdir()) + logger.log(Logger.LogLevel.ERROR, "Failed to create tasks folder!"); File taskFile = new File(tasksFolder, fileName + ".toml"); if (!taskFile.exists()) { - System.err.println("TaskFile " + fileName + ".toml does not exist!"); + logger.log(Logger.LogLevel.ERROR, "TaskFile %s.toml does not exist!", fileName); return; } TomlParseResult toml; try { toml = Toml.parse(taskFile.toPath()); } catch (IOException e) { - System.err.println("failed to read TaskFile."); + logger.log(Logger.LogLevel.ERROR, "failed to read TaskFile."); throw new RuntimeException(e); } if (toml.hasErrors()) { - System.err.printf( - "TaskFile checked: found %d issues!:\n", (long) toml.errors().size()); - toml.errors().forEach(error -> System.err.println(error.toString())); + logger.log( + Logger.LogLevel.ERROR, + "TaskFile checked: found %d issues!:\n", + (long) toml.errors().size()); + toml.errors().forEach(error -> logger.log(Logger.LogLevel.ERROR, error.toString())); } else { - System.out.println("TaskFile checked successfully: no issues found!"); + logger.log(Logger.LogLevel.INFO, "TaskFile checked successfully: no issues found!"); } break; } @@ -122,6 +136,7 @@ public class CLIProcessor { } } } catch (Throwable t) { + SysBackup.getLogger().log(Logger.LogLevel.ERROR, t.getMessage()); t.printStackTrace(); } } diff --git a/src/main/java/net/horizoncode/sysbackup/logging/Logger.java b/src/main/java/net/horizoncode/sysbackup/logging/Logger.java new file mode 100644 index 0000000..ea1fc39 --- /dev/null +++ b/src/main/java/net/horizoncode/sysbackup/logging/Logger.java @@ -0,0 +1,48 @@ +package net.horizoncode.sysbackup.logging; + +import com.diogonunes.jcolor.Ansi; +import com.diogonunes.jcolor.Attribute; +import lombok.Builder; +import lombok.Getter; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; + +@Builder +public class Logger { + private File logFile; + + public void log(LogLevel logLevel, String message, Object... args) { + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); + String prefix = + String.format( + "[%s - %s] ", + sdf.format(new Date()), Ansi.colorize(logLevel.name(), logLevel.getColor())); + String line = prefix + message; + System.out.printf(line + "\r\n", args); + + // append to logfile + try { + FileUtils.writeStringToFile( + logFile, line.replaceAll("\u001B\\[[;\\d]*m", "") + "\r\n", StandardCharsets.UTF_8, true); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + public enum LogLevel { + INFO(Attribute.CYAN_TEXT()), + WARN(Attribute.YELLOW_TEXT()), + ERROR(Attribute.RED_TEXT()); + + @Getter private final Attribute color; + + LogLevel(Attribute color) { + this.color = color; + } + } +} diff --git a/src/main/java/net/horizoncode/sysbackup/tasks/TaskBuilder.java b/src/main/java/net/horizoncode/sysbackup/tasks/TaskBuilder.java index d00038d..440259b 100644 --- a/src/main/java/net/horizoncode/sysbackup/tasks/TaskBuilder.java +++ b/src/main/java/net/horizoncode/sysbackup/tasks/TaskBuilder.java @@ -2,7 +2,9 @@ package net.horizoncode.sysbackup.tasks; import lombok.Builder; import lombok.Getter; +import net.horizoncode.sysbackup.SysBackup; import net.horizoncode.sysbackup.config.Config; +import net.horizoncode.sysbackup.logging.Logger; import net.horizoncode.sysbackup.tasks.impl.DatabaseTask; import net.horizoncode.sysbackup.tasks.impl.FileSystemTask; import net.horizoncode.sysbackup.tasks.impl.VacuumTask; @@ -32,17 +34,19 @@ public class TaskBuilder { public void start() { + Logger logger = SysBackup.getLogger(); + File rootBackupDir = new File(executionPath, "backups"); if (!rootBackupDir.exists()) if (!rootBackupDir.mkdir()) { - System.err.println("Failed to create root backup directory!"); + logger.log(Logger.LogLevel.ERROR, "Failed to create root backup directory!"); System.exit(2); } File backupDir = new File(rootBackupDir, getTaskName()); if (!backupDir.exists()) if (!backupDir.mkdir()) { - System.err.println("Failed to create backup directory!"); + logger.log(Logger.LogLevel.ERROR, "Failed to create backup directory!"); System.exit(2); } @@ -71,7 +75,8 @@ public class TaskBuilder { int value = getTaskConfig().getIntOrDefault("vacuum.time", 5); - System.out.printf("Adding VacuumTask with lifetime of %d %s%n", value, unit.name()); + logger.log( + Logger.LogLevel.INFO, "Adding VacuumTask with lifetime of %d %s%n", value, unit.name()); taskList.add( new VacuumTask(backupDir, unit, value) { @Override @@ -82,14 +87,14 @@ public class TaskBuilder { } if (doFS && getTaskConfig().getToml().contains("filesystem.targets")) { - System.out.println("Adding FileSystemTask..."); + logger.log(Logger.LogLevel.INFO, "Adding FileSystemTask..."); TomlArray filesArray = getTaskConfig().getArray("filesystem.targets"); IntStream.range(0, filesArray.size()) .forEach( value -> { String target = filesArray.getString(value); - System.out.println("Adding \"" + target + "\""); + logger.log(Logger.LogLevel.INFO, "Adding \"%s\"", target); taskList.add( new FileSystemTask(target, outputFile) { @Override @@ -113,7 +118,7 @@ public class TaskBuilder { .password(password.toCharArray()) .build(); - System.out.println("Adding DatabaseTask for database \"" + database + "\""); + logger.log(Logger.LogLevel.INFO, "Adding DatabaseTask for database \"%s\"", database); taskList.add( new DatabaseTask(databaseCredentials, outputFile) { @@ -123,7 +128,7 @@ public class TaskBuilder { } }); } else { - System.err.println("username, password or database is empty."); + logger.log(Logger.LogLevel.ERROR, "username, password or database is empty."); } } @@ -134,7 +139,7 @@ public class TaskBuilder { Task nextTask = taskList.poll(); if (nextTask != null) nextTask.start(); else { - System.out.println("Backup completed!"); + SysBackup.getLogger().log(Logger.LogLevel.INFO, "Backup completed!"); System.exit(0); } } diff --git a/src/main/java/net/horizoncode/sysbackup/tasks/impl/DatabaseTask.java b/src/main/java/net/horizoncode/sysbackup/tasks/impl/DatabaseTask.java index 24b6bd7..46dc8b3 100644 --- a/src/main/java/net/horizoncode/sysbackup/tasks/impl/DatabaseTask.java +++ b/src/main/java/net/horizoncode/sysbackup/tasks/impl/DatabaseTask.java @@ -5,6 +5,8 @@ import lombok.Getter; import me.tongfei.progressbar.ProgressBar; import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarStyle; +import net.horizoncode.sysbackup.SysBackup; +import net.horizoncode.sysbackup.logging.Logger; import net.horizoncode.sysbackup.tasks.Task; import net.lingala.zip4j.ZipFile; import net.lingala.zip4j.progress.ProgressMonitor; @@ -29,6 +31,7 @@ public class DatabaseTask extends Task { @Override public void start() { try { + Logger logger = SysBackup.getLogger(); String commandArgs = "mysqldump -u " + getDatabaseCredentials().username @@ -51,6 +54,7 @@ public class DatabaseTask extends Task { .lines() .collect(Collectors.joining("\n")); } catch (InterruptedException e) { + logger.log(Logger.LogLevel.ERROR, e.getMessage()); throw new RuntimeException(e); } } @@ -63,13 +67,13 @@ public class DatabaseTask extends Task { new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8)) .lines() .collect(Collectors.joining("\n")); - System.out.println(text); + logger.log(Logger.LogLevel.ERROR, text); onDone(); return; } if (databaseContent.isEmpty()) { - System.err.println("database content is empty"); + logger.log(Logger.LogLevel.ERROR, "database content is empty"); onDone(); return; } @@ -84,7 +88,7 @@ public class DatabaseTask extends Task { BufferedWriter writer = new BufferedWriter(new FileWriter(outputSQLFile)); writer.write(databaseContent); writer.close(); - System.out.println("Adding database to backup zip..."); + logger.log(Logger.LogLevel.INFO, "Adding database to backup zip..."); try (ZipFile zipFile = new ZipFile(getOutputFile())) { ProgressMonitor progressMonitor = zipFile.getProgressMonitor(); zipFile.setRunInThread(true); @@ -103,6 +107,7 @@ public class DatabaseTask extends Task { } pb.stepTo(progressMonitor.getTotalWork()); } catch (Exception exception) { + logger.log(Logger.LogLevel.ERROR, exception.getMessage()); exception.printStackTrace(); outputSQLFile.deleteOnExit(); onDone(); @@ -111,11 +116,13 @@ public class DatabaseTask extends Task { outputSQLFile.deleteOnExit(); onDone(); } catch (Exception ex) { + logger.log(Logger.LogLevel.ERROR, ex.getMessage()); ex.printStackTrace(); onDone(); } } catch (IOException e) { + SysBackup.getLogger().log(Logger.LogLevel.ERROR, e.getMessage()); throw new RuntimeException(e); } } diff --git a/src/main/java/net/horizoncode/sysbackup/tasks/impl/FileSystemTask.java b/src/main/java/net/horizoncode/sysbackup/tasks/impl/FileSystemTask.java index 0bfc9c1..f0d1d3c 100644 --- a/src/main/java/net/horizoncode/sysbackup/tasks/impl/FileSystemTask.java +++ b/src/main/java/net/horizoncode/sysbackup/tasks/impl/FileSystemTask.java @@ -3,6 +3,8 @@ package net.horizoncode.sysbackup.tasks.impl; import me.tongfei.progressbar.ProgressBar; import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarStyle; +import net.horizoncode.sysbackup.SysBackup; +import net.horizoncode.sysbackup.logging.Logger; import net.horizoncode.sysbackup.tasks.Task; import net.lingala.zip4j.ZipFile; import net.lingala.zip4j.progress.ProgressMonitor; @@ -17,9 +19,11 @@ public class FileSystemTask extends Task { public FileSystemTask(String folderOrFilePath, File outputZipFile) { this.target = Paths.get(folderOrFilePath).toFile(); + Logger logger = SysBackup.getLogger(); if (!target.exists()) { onDone(); - System.err.println("File or folder named \"" + folderOrFilePath + "\" does not exist."); + logger.log( + Logger.LogLevel.ERROR, "File or folder named \"%s\" does not exist.", folderOrFilePath); System.exit(2); return; } @@ -29,8 +33,9 @@ public class FileSystemTask extends Task { @Override public void start() { + Logger logger = SysBackup.getLogger(); try (ZipFile zipFile = new ZipFile(outputZipFile)) { - System.out.println("Indexing files..."); + logger.log(Logger.LogLevel.INFO, "Indexing files..."); ProgressMonitor progressMonitor = zipFile.getProgressMonitor(); zipFile.setRunInThread(true); zipFile.addFolder(target); @@ -48,12 +53,14 @@ public class FileSystemTask extends Task { } pb.stepTo(progressMonitor.getTotalWork()); } catch (Exception exception) { + logger.log(Logger.LogLevel.ERROR, exception.getMessage()); exception.printStackTrace(); onDone(); } progressMonitor.endProgressMonitor(); onDone(); } catch (Exception ex) { + logger.log(Logger.LogLevel.ERROR, ex.getMessage()); ex.printStackTrace(); onDone(); } diff --git a/src/main/java/net/horizoncode/sysbackup/threading/ThreadPool.java b/src/main/java/net/horizoncode/sysbackup/threading/ThreadPool.java index 564b276..000ddd1 100644 --- a/src/main/java/net/horizoncode/sysbackup/threading/ThreadPool.java +++ b/src/main/java/net/horizoncode/sysbackup/threading/ThreadPool.java @@ -3,7 +3,6 @@ package net.horizoncode.sysbackup.threading; import lombok.Getter; import java.util.concurrent.ExecutorService; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; public class ThreadPool { @@ -11,13 +10,10 @@ public class ThreadPool { @Getter private final ExecutorService pool; public ThreadPool(int corePoolSize, int maxPoolSize) { - this.pool = scheduledExecutorService(corePoolSize, maxPoolSize); - } - - private ScheduledExecutorService scheduledExecutorService(int corePoolSize, int maxPoolSize) { ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(corePoolSize); scheduledThreadPoolExecutor.setMaximumPoolSize(maxPoolSize); - return scheduledThreadPoolExecutor; + + this.pool = scheduledThreadPoolExecutor; } }