add Logger

This commit is contained in:
HorizonCode 2022-07-25 09:27:49 +02:00
parent 8f9d7d5297
commit 7142cd06dd
9 changed files with 153 additions and 55 deletions

View File

@ -59,6 +59,11 @@
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.12.0</version> <version>3.12.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.diogonunes</groupId>
<artifactId>JColor</artifactId>
<version>5.5.1</version>
</dependency>
<!-- testing dependencies --> <!-- testing dependencies -->
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>

View File

@ -1,24 +1,10 @@
import net.horizoncode.sysbackup.cli.CLIProcessor; import net.horizoncode.sysbackup.SysBackup;
import java.io.File;
import java.net.URISyntaxException; import java.net.URISyntaxException;
public class Bootstrapper { public class Bootstrapper {
public static void main(String[] args) throws URISyntaxException { public static void main(String[] args) throws URISyntaxException {
new SysBackup().start(args);
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")));
} }
} }

View File

@ -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")));
}
}

View File

@ -1,6 +1,8 @@
package net.horizoncode.sysbackup.cli; package net.horizoncode.sysbackup.cli;
import net.horizoncode.sysbackup.SysBackup;
import net.horizoncode.sysbackup.config.Config; import net.horizoncode.sysbackup.config.Config;
import net.horizoncode.sysbackup.logging.Logger;
import net.horizoncode.sysbackup.tasks.TaskBuilder; import net.horizoncode.sysbackup.tasks.TaskBuilder;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
@ -27,7 +29,7 @@ public class CLIProcessor {
" java -jar sysbackup.jar generateTaskConf magento", " java -jar sysbackup.jar generateTaskConf magento",
" java -jar sysbackup.jar backup 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) { public void startCLI(String[] args, File executionPath) {
@ -37,25 +39,28 @@ public class CLIProcessor {
return; return;
} }
Logger logger = SysBackup.getLogger();
for (int index = 0; index < args.length; index++) { for (int index = 0; index < args.length; index++) {
switch (args[index].toLowerCase(Locale.ROOT)) { switch (args[index].toLowerCase(Locale.ROOT)) {
case "backup": case "backup":
{ {
if (args.length <= 1) { 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; return;
} }
String fileName = args[1]; String fileName = args[1];
File tasksFolder = new File(executionPath, "tasks"); File tasksFolder = new File(executionPath, "tasks");
if (!tasksFolder.exists()) 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"); File taskFile = new File(tasksFolder, fileName + ".toml");
if (!taskFile.exists()) { 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; return;
} }
System.out.println("setuping TaskBuilder..."); logger.log(Logger.LogLevel.INFO, "setupping TaskBuilder...");
Config taskConfig = new Config(taskFile); Config taskConfig = new Config(taskFile);
TaskBuilder taskBuilder = TaskBuilder taskBuilder =
TaskBuilder.builder() TaskBuilder.builder()
@ -69,48 +74,57 @@ public class CLIProcessor {
case "generatetaskconf": case "generatetaskconf":
{ {
if (args.length <= 1) { 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; return;
} }
String fileName = args[1]; String fileName = args[1];
File tasksFolder = new File(executionPath, "tasks"); File tasksFolder = new File(executionPath, "tasks");
if (!tasksFolder.exists()) if (!tasksFolder.exists())
if (!tasksFolder.mkdir()) System.err.println("Failed to create tasks folder!"); if (!tasksFolder.mkdir())
System.out.println("Saving task config " + fileName + ".toml..."); logger.log(Logger.LogLevel.ERROR, "Failed to create tasks folder!");
FileUtils.copyInputStreamToFile( logger.log(Logger.LogLevel.INFO, "Saving task config %s.toml...", fileName);
Objects.requireNonNull(getClass().getResourceAsStream("/" + "exampletask.toml")), try {
new File(tasksFolder, fileName + ".toml")); FileUtils.copyInputStreamToFile(
System.out.println(fileName + ".toml saved!"); 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; break;
} }
case "checktaskconf": case "checktaskconf":
{ {
if (args.length <= 1) { 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; return;
} }
String fileName = args[1]; String fileName = args[1];
File tasksFolder = new File(executionPath, "tasks"); File tasksFolder = new File(executionPath, "tasks");
if (!tasksFolder.exists()) 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"); File taskFile = new File(tasksFolder, fileName + ".toml");
if (!taskFile.exists()) { 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; return;
} }
TomlParseResult toml; TomlParseResult toml;
try { try {
toml = Toml.parse(taskFile.toPath()); toml = Toml.parse(taskFile.toPath());
} catch (IOException e) { } catch (IOException e) {
System.err.println("failed to read TaskFile."); logger.log(Logger.LogLevel.ERROR, "failed to read TaskFile.");
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if (toml.hasErrors()) { if (toml.hasErrors()) {
System.err.printf( logger.log(
"TaskFile checked: found %d issues!:\n", (long) toml.errors().size()); Logger.LogLevel.ERROR,
toml.errors().forEach(error -> System.err.println(error.toString())); "TaskFile checked: found %d issues!:\n",
(long) toml.errors().size());
toml.errors().forEach(error -> logger.log(Logger.LogLevel.ERROR, error.toString()));
} else { } else {
System.out.println("TaskFile checked successfully: no issues found!"); logger.log(Logger.LogLevel.INFO, "TaskFile checked successfully: no issues found!");
} }
break; break;
} }
@ -122,6 +136,7 @@ public class CLIProcessor {
} }
} }
} catch (Throwable t) { } catch (Throwable t) {
SysBackup.getLogger().log(Logger.LogLevel.ERROR, t.getMessage());
t.printStackTrace(); t.printStackTrace();
} }
} }

View File

@ -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;
}
}
}

View File

@ -2,7 +2,9 @@ package net.horizoncode.sysbackup.tasks;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import net.horizoncode.sysbackup.SysBackup;
import net.horizoncode.sysbackup.config.Config; 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.DatabaseTask;
import net.horizoncode.sysbackup.tasks.impl.FileSystemTask; import net.horizoncode.sysbackup.tasks.impl.FileSystemTask;
import net.horizoncode.sysbackup.tasks.impl.VacuumTask; import net.horizoncode.sysbackup.tasks.impl.VacuumTask;
@ -32,17 +34,19 @@ public class TaskBuilder {
public void start() { public void start() {
Logger logger = SysBackup.getLogger();
File rootBackupDir = new File(executionPath, "backups"); File rootBackupDir = new File(executionPath, "backups");
if (!rootBackupDir.exists()) if (!rootBackupDir.exists())
if (!rootBackupDir.mkdir()) { 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); System.exit(2);
} }
File backupDir = new File(rootBackupDir, getTaskName()); File backupDir = new File(rootBackupDir, getTaskName());
if (!backupDir.exists()) if (!backupDir.exists())
if (!backupDir.mkdir()) { if (!backupDir.mkdir()) {
System.err.println("Failed to create backup directory!"); logger.log(Logger.LogLevel.ERROR, "Failed to create backup directory!");
System.exit(2); System.exit(2);
} }
@ -71,7 +75,8 @@ public class TaskBuilder {
int value = getTaskConfig().getIntOrDefault("vacuum.time", 5); 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( taskList.add(
new VacuumTask(backupDir, unit, value) { new VacuumTask(backupDir, unit, value) {
@Override @Override
@ -82,14 +87,14 @@ public class TaskBuilder {
} }
if (doFS && getTaskConfig().getToml().contains("filesystem.targets")) { 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"); TomlArray filesArray = getTaskConfig().getArray("filesystem.targets");
IntStream.range(0, filesArray.size()) IntStream.range(0, filesArray.size())
.forEach( .forEach(
value -> { value -> {
String target = filesArray.getString(value); String target = filesArray.getString(value);
System.out.println("Adding \"" + target + "\""); logger.log(Logger.LogLevel.INFO, "Adding \"%s\"", target);
taskList.add( taskList.add(
new FileSystemTask(target, outputFile) { new FileSystemTask(target, outputFile) {
@Override @Override
@ -113,7 +118,7 @@ public class TaskBuilder {
.password(password.toCharArray()) .password(password.toCharArray())
.build(); .build();
System.out.println("Adding DatabaseTask for database \"" + database + "\""); logger.log(Logger.LogLevel.INFO, "Adding DatabaseTask for database \"%s\"", database);
taskList.add( taskList.add(
new DatabaseTask(databaseCredentials, outputFile) { new DatabaseTask(databaseCredentials, outputFile) {
@ -123,7 +128,7 @@ public class TaskBuilder {
} }
}); });
} else { } 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(); Task nextTask = taskList.poll();
if (nextTask != null) nextTask.start(); if (nextTask != null) nextTask.start();
else { else {
System.out.println("Backup completed!"); SysBackup.getLogger().log(Logger.LogLevel.INFO, "Backup completed!");
System.exit(0); System.exit(0);
} }
} }

View File

@ -5,6 +5,8 @@ import lombok.Getter;
import me.tongfei.progressbar.ProgressBar; import me.tongfei.progressbar.ProgressBar;
import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarBuilder;
import me.tongfei.progressbar.ProgressBarStyle; import me.tongfei.progressbar.ProgressBarStyle;
import net.horizoncode.sysbackup.SysBackup;
import net.horizoncode.sysbackup.logging.Logger;
import net.horizoncode.sysbackup.tasks.Task; import net.horizoncode.sysbackup.tasks.Task;
import net.lingala.zip4j.ZipFile; import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.progress.ProgressMonitor; import net.lingala.zip4j.progress.ProgressMonitor;
@ -29,6 +31,7 @@ public class DatabaseTask extends Task {
@Override @Override
public void start() { public void start() {
try { try {
Logger logger = SysBackup.getLogger();
String commandArgs = String commandArgs =
"mysqldump -u " "mysqldump -u "
+ getDatabaseCredentials().username + getDatabaseCredentials().username
@ -51,6 +54,7 @@ public class DatabaseTask extends Task {
.lines() .lines()
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.log(Logger.LogLevel.ERROR, e.getMessage());
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@ -63,13 +67,13 @@ public class DatabaseTask extends Task {
new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8)) new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8))
.lines() .lines()
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
System.out.println(text); logger.log(Logger.LogLevel.ERROR, text);
onDone(); onDone();
return; return;
} }
if (databaseContent.isEmpty()) { if (databaseContent.isEmpty()) {
System.err.println("database content is empty"); logger.log(Logger.LogLevel.ERROR, "database content is empty");
onDone(); onDone();
return; return;
} }
@ -84,7 +88,7 @@ public class DatabaseTask extends Task {
BufferedWriter writer = new BufferedWriter(new FileWriter(outputSQLFile)); BufferedWriter writer = new BufferedWriter(new FileWriter(outputSQLFile));
writer.write(databaseContent); writer.write(databaseContent);
writer.close(); 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())) { try (ZipFile zipFile = new ZipFile(getOutputFile())) {
ProgressMonitor progressMonitor = zipFile.getProgressMonitor(); ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
zipFile.setRunInThread(true); zipFile.setRunInThread(true);
@ -103,6 +107,7 @@ public class DatabaseTask extends Task {
} }
pb.stepTo(progressMonitor.getTotalWork()); pb.stepTo(progressMonitor.getTotalWork());
} catch (Exception exception) { } catch (Exception exception) {
logger.log(Logger.LogLevel.ERROR, exception.getMessage());
exception.printStackTrace(); exception.printStackTrace();
outputSQLFile.deleteOnExit(); outputSQLFile.deleteOnExit();
onDone(); onDone();
@ -111,11 +116,13 @@ public class DatabaseTask extends Task {
outputSQLFile.deleteOnExit(); outputSQLFile.deleteOnExit();
onDone(); onDone();
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Logger.LogLevel.ERROR, ex.getMessage());
ex.printStackTrace(); ex.printStackTrace();
onDone(); onDone();
} }
} catch (IOException e) { } catch (IOException e) {
SysBackup.getLogger().log(Logger.LogLevel.ERROR, e.getMessage());
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }

View File

@ -3,6 +3,8 @@ package net.horizoncode.sysbackup.tasks.impl;
import me.tongfei.progressbar.ProgressBar; import me.tongfei.progressbar.ProgressBar;
import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarBuilder;
import me.tongfei.progressbar.ProgressBarStyle; import me.tongfei.progressbar.ProgressBarStyle;
import net.horizoncode.sysbackup.SysBackup;
import net.horizoncode.sysbackup.logging.Logger;
import net.horizoncode.sysbackup.tasks.Task; import net.horizoncode.sysbackup.tasks.Task;
import net.lingala.zip4j.ZipFile; import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.progress.ProgressMonitor; import net.lingala.zip4j.progress.ProgressMonitor;
@ -17,9 +19,11 @@ public class FileSystemTask extends Task {
public FileSystemTask(String folderOrFilePath, File outputZipFile) { public FileSystemTask(String folderOrFilePath, File outputZipFile) {
this.target = Paths.get(folderOrFilePath).toFile(); this.target = Paths.get(folderOrFilePath).toFile();
Logger logger = SysBackup.getLogger();
if (!target.exists()) { if (!target.exists()) {
onDone(); 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); System.exit(2);
return; return;
} }
@ -29,8 +33,9 @@ public class FileSystemTask extends Task {
@Override @Override
public void start() { public void start() {
Logger logger = SysBackup.getLogger();
try (ZipFile zipFile = new ZipFile(outputZipFile)) { try (ZipFile zipFile = new ZipFile(outputZipFile)) {
System.out.println("Indexing files..."); logger.log(Logger.LogLevel.INFO, "Indexing files...");
ProgressMonitor progressMonitor = zipFile.getProgressMonitor(); ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
zipFile.setRunInThread(true); zipFile.setRunInThread(true);
zipFile.addFolder(target); zipFile.addFolder(target);
@ -48,12 +53,14 @@ public class FileSystemTask extends Task {
} }
pb.stepTo(progressMonitor.getTotalWork()); pb.stepTo(progressMonitor.getTotalWork());
} catch (Exception exception) { } catch (Exception exception) {
logger.log(Logger.LogLevel.ERROR, exception.getMessage());
exception.printStackTrace(); exception.printStackTrace();
onDone(); onDone();
} }
progressMonitor.endProgressMonitor(); progressMonitor.endProgressMonitor();
onDone(); onDone();
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Logger.LogLevel.ERROR, ex.getMessage());
ex.printStackTrace(); ex.printStackTrace();
onDone(); onDone();
} }

View File

@ -3,7 +3,6 @@ package net.horizoncode.sysbackup.threading;
import lombok.Getter; import lombok.Getter;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
public class ThreadPool { public class ThreadPool {
@ -11,13 +10,10 @@ public class ThreadPool {
@Getter private final ExecutorService pool; @Getter private final ExecutorService pool;
public ThreadPool(int corePoolSize, int maxPoolSize) { public ThreadPool(int corePoolSize, int maxPoolSize) {
this.pool = scheduledExecutorService(corePoolSize, maxPoolSize);
}
private ScheduledExecutorService scheduledExecutorService(int corePoolSize, int maxPoolSize) {
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =
new ScheduledThreadPoolExecutor(corePoolSize); new ScheduledThreadPoolExecutor(corePoolSize);
scheduledThreadPoolExecutor.setMaximumPoolSize(maxPoolSize); scheduledThreadPoolExecutor.setMaximumPoolSize(maxPoolSize);
return scheduledThreadPoolExecutor;
this.pool = scheduledThreadPoolExecutor;
} }
} }