Improved log message in Backup engine

This commit is contained in:
Marc Baloup 2022-12-15 00:22:43 +01:00
parent 148099a4d2
commit dcfbb3e06a
Signed by: marcbal
GPG Key ID: BBC0FE3ABC30B893
5 changed files with 128 additions and 89 deletions

View File

@ -1,5 +1,9 @@
package fr.pandacube.lib.paper.modules.backup; package fr.pandacube.lib.paper.modules.backup;
import fr.pandacube.lib.chat.Chat;
import fr.pandacube.lib.util.Log;
import org.bukkit.ChatColor;
import java.io.File; import java.io.File;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
@ -10,10 +14,12 @@ import java.util.TreeSet;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import fr.pandacube.lib.util.Log; import static fr.pandacube.lib.chat.ChatStatic.text;
public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTime>> { public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTime>> {
private static final boolean testOnly = true; // if true, no files are deleted
public static BackupCleaner KEEPING_N_LAST(int n) { public static BackupCleaner KEEPING_N_LAST(int n) {
return new BackupCleaner() { return new BackupCleaner() {
@Override @Override
@ -66,17 +72,17 @@ public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTi
public void cleanupArchives(File archiveDir) { public void cleanupArchives(File archiveDir, String compressDisplayName) {
String[] files = archiveDir.list(); String[] files = archiveDir.list();
Log.info("[Backup] Cleaning up backup directory " + archiveDir + "..."); Log.info("[Backup] Cleaning up backup directory " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + "...");
TreeMap<LocalDateTime, File> datedFiles = new TreeMap<>(); TreeMap<LocalDateTime, File> datedFiles = new TreeMap<>();
for (String filename : files) { for (String filename : files) {
File file = new File(archiveDir, filename); File file = new File(archiveDir, filename);
if (!filename.matches("\\d{8}-\\d{6}\\.zip")) { if (!filename.matches("\\d{8}-\\d{6}\\.zip")) {
Log.warning("[Backup] Invalid file in backup directory: " + file); Log.warning("[Backup] " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + " Invalid file in backup directory: " + filename);
continue; continue;
} }
@ -85,7 +91,7 @@ public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTi
try { try {
ldt = LocalDateTime.parse(dateTimeStr, CompressProcess.dateFileNameFormatter); ldt = LocalDateTime.parse(dateTimeStr, CompressProcess.dateFileNameFormatter);
} catch (DateTimeParseException e) { } catch (DateTimeParseException e) {
Log.warning("Unable to parse file name to a date-time: " + file, e); Log.warning("[Backup] " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + " Unable to parse file name to a date-time: " + filename, e);
continue; continue;
} }
@ -94,14 +100,31 @@ public abstract class BackupCleaner implements UnaryOperator<TreeSet<LocalDateTi
TreeSet<LocalDateTime> keptFiles = apply(new TreeSet<>(datedFiles.keySet())); TreeSet<LocalDateTime> keptFiles = apply(new TreeSet<>(datedFiles.keySet()));
Chat c = text("[Backup] ")
.then(text(compressDisplayName).gray())
.thenText(testOnly ? " Archive cleanup debug (no files are actually deleted):" : "Deleted archive files:\n");
boolean oneDeleted = false;
for (Entry<LocalDateTime, File> datedFile : datedFiles.entrySet()) { for (Entry<LocalDateTime, File> datedFile : datedFiles.entrySet()) {
if (keptFiles.contains(datedFile.getKey())) if (keptFiles.contains(datedFile.getKey())) {
if (testOnly)
c.thenText("- " + datedFile.getValue().getName() + " ")
.thenSuccess("kept")
.thenText(".\n");
continue; continue;
// datedFile.getValue().delete(); // TODO check if the filtering is ok before actually removing files }
Log.info("[Backup] Removed expired backup file " + datedFile.getValue()); oneDeleted = true;
c.thenText("- " + datedFile.getValue().getName() + " ");
if (testOnly)
c.thenFailure("deleted")
.thenText(".\n");
else
datedFile.getValue().delete();
} }
Log.info("[Backup] Backup directory " + archiveDir + " cleaned."); if (testOnly || oneDeleted)
Log.warning(c.getLegacyText());
Log.info("[Backup] Backup directory " + ChatColor.GRAY + compressDisplayName + ChatColor.RESET + " cleaned.");
} }

View File

@ -51,102 +51,107 @@ public abstract class CompressProcess implements Comparable<CompressProcess>, Ru
protected abstract void onCompressEnd(boolean success); protected abstract void onCompressEnd(boolean success);
protected abstract File getTargetDir(); protected abstract File getTargetDir();
protected abstract String getDisplayName();
@Override @Override
public void run() { public void run() {
backupManager.compressRunning.set(this); backupManager.compressRunning.set(this);
BiPredicate<File, String> filter = getFilenameFilter(); try {
File sourceDir = getSourceDir(); BiPredicate<File, String> filter = getFilenameFilter();
File sourceDir = getSourceDir();
if (!sourceDir.exists()) {
Log.warning(String.format("%% unable to compress %s (check path: %s)", name, sourceDir.getPath())); if (!sourceDir.exists()) {
Log.warning("[Backup] Unable to compress " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + ": source directory " + sourceDir + " doesnt exist");
return;
}
File targetDir = getTargetDir();
File target = new File(targetDir, getDateFileName() + ".zip");
BossBar bossBar = BossBar.bossBar(Chat.text("Archivage"), 0, Color.YELLOW, Overlay.NOTCHED_20);
AutoUpdatedBossBar auBossBar = new AutoUpdatedBossBar(bossBar, (bar) -> {
bar.setTitle(Chat.infoText("Archivage ")
.thenData(getDisplayName())
.thenText(" : ")
.then(compressor == null
? Chat.text("Démarrage...")
: compressor.getState()
)
);
bar.setProgress(compressor == null ? 0 : compressor.getProgress());
});
auBossBar.scheduleUpdateTimeSyncThreadAsync(100, 100);
onCompressStart();
Bukkit.getScheduler().runTaskAsynchronously(PandaLibPaper.getPlugin(), () -> {
Log.info("[Backup] Starting for " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " ...");
compressor = new ZipCompressor(sourceDir, target, 9, filter);
PerformanceAnalysisManager.getInstance().addBossBar(bossBar);
boolean success = false;
try {
compressor.compress();
success = true;
Log.info("[Backup] Finished for " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET);
backupManager.persist.updateDirtyStatusAfterCompress(type, name);
displayDirtynessStatus();
try {
type.backupCleaner(backupManager.config).cleanupArchives(targetDir, getDisplayName());
} catch (Exception e) {
Log.severe(e);
}
}
catch (final Exception e) {
Log.severe("[Backup] Failed: " + sourceDir + " -> " + target, e);
FileUtils.delete(target);
if (target.exists())
Log.warning("unable to delete: " + target);
} finally {
backupManager.compressRunning.set(null);
boolean successF = success;
Bukkit.getScheduler().runTask(PandaLibPaper.getPlugin(), () -> onCompressEnd(successF));
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
PerformanceAnalysisManager.getInstance().removeBossBar(bossBar);
}
});
} finally {
backupManager.compressRunning.set(null); backupManager.compressRunning.set(null);
return;
} }
File targetDir = getTargetDir();
File target = new File(targetDir, getDateFileName() + ".zip");
BossBar bossBar = BossBar.bossBar(Chat.text("Archivage"), 0, Color.YELLOW, Overlay.NOTCHED_20);
AutoUpdatedBossBar auBossBar = new AutoUpdatedBossBar(bossBar, (bar) -> {
bar.setTitle(Chat.infoText("Archivage ")
.thenData(type + "\\" + name)
.thenText(" : ")
.then(compressor == null
? Chat.text("Démarrage...")
: compressor.getState()
)
);
bar.setProgress(compressor == null ? 0 : compressor.getProgress());
});
auBossBar.scheduleUpdateTimeSyncThreadAsync(100, 100);
onCompressStart();
Bukkit.getScheduler().runTaskAsynchronously(PandaLibPaper.getPlugin(), () -> {
Log.info("[Backup] starting for " + ChatColor.GRAY + type + "\\" + name + ChatColor.RESET + " ...");
compressor = new ZipCompressor(sourceDir, target, 9, filter);
PerformanceAnalysisManager.getInstance().addBossBar(bossBar);
boolean success = false;
try {
compressor.compress();
success = true;
Log.info("[Backup] finished for " + ChatColor.GRAY + type + "\\" + name + ChatColor.RESET);
backupManager.persist.updateDirtyStatusAfterCompress(type, name);
displayDirtynessStatus();
try {
type.backupCleaner(backupManager.config).cleanupArchives(targetDir);
} catch (Exception e) {
Log.severe(e);
}
}
catch (final Exception e) {
Log.severe("[Backup] Failed: " + sourceDir + " -> " + target, e);
FileUtils.delete(target);
if (target.exists())
Log.warning("unable to delete: " + target);
} finally {
backupManager.compressRunning.set(null);
boolean successF = success;
Bukkit.getScheduler().runTask(PandaLibPaper.getPlugin(), () -> onCompressEnd(successF));
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
PerformanceAnalysisManager.getInstance().removeBossBar(bossBar);
}
});
} }
public void displayDirtynessStatus() { public void displayDirtynessStatus() {
if (hasNextScheduled() && type == Type.WORLDS) { if (hasNextScheduled() && type == Type.WORLDS) {
Log.info("[Backup] " + ChatColor.GRAY + type + "\\" + name + ChatColor.RESET + " is dirty. Next backup on " Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " is dirty. Next backup on "
+ DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(getNext()))); + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(getNext())));
} }
else if (hasNextScheduled()) { else if (hasNextScheduled()) {
Log.info("[Backup] " + ChatColor.GRAY + type + "\\" + name + ChatColor.RESET + " next backup on " Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " next backup on "
+ DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(getNext()))); + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date(getNext())));
} }
else { else {
Log.info("[Backup] " + ChatColor.GRAY + type + "\\" + name + ChatColor.RESET + " is clean. Next backup not scheduled."); Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + " is clean. Next backup not scheduled.");
} }
} }
@ -170,7 +175,7 @@ public abstract class CompressProcess implements Comparable<CompressProcess>, Ru
public void logProgress() { public void logProgress() {
if (compressor == null) if (compressor == null)
return; return;
Log.info("[Backup] " + ChatColor.GRAY + type + "\\" + name + ChatColor.RESET + ": " + compressor.getState().getLegacyText()); Log.info("[Backup] " + ChatColor.GRAY + getDisplayName() + ChatColor.RESET + ": " + compressor.getState().getLegacyText());
} }

View File

@ -64,6 +64,11 @@ public class CompressWorkdirProcess extends CompressProcess {
@Override @Override
protected File getTargetDir() { protected File getTargetDir() {
return new File(backupManager.config.backupDirectory, "workdir"); return new File(backupManager.config.backupDirectory, type.toString());
}
@Override
protected String getDisplayName() {
return type.toString();
} }
} }

View File

@ -49,6 +49,11 @@ public class CompressWorldProcess extends CompressProcess {
@Override @Override
protected File getTargetDir() { protected File getTargetDir() {
return new File(backupManager.config.backupDirectory, type.toString() + "/" + name); return new File(backupManager.config.backupDirectory, type + "/" + name);
}
@Override
protected String getDisplayName() {
return type + "/" + name;
} }
} }

View File

@ -6,6 +6,7 @@ import java.io.IOException;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.Date; import java.util.Date;
import org.bukkit.ChatColor;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
@ -74,7 +75,7 @@ public class Persist extends YamlConfiguration {
return; return;
if (!isDirty(Type.WORLDS, world.getName())) { // don't set dirty if it is already if (!isDirty(Type.WORLDS, world.getName())) { // don't set dirty if it is already
setDirtySinceNow(Type.WORLDS, world.getName()); setDirtySinceNow(Type.WORLDS, world.getName());
Log.info("[Backup] " + Type.WORLDS + "\\" + world.getName() + " was saved and is now dirty. Next backup on " Log.info("[Backup] " + ChatColor.GRAY + Type.WORLDS + "/" + world.getName() + ChatColor.RESET + " was saved and is now dirty. Next backup on "
+ DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG) + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG)
.format(new Date(backupManager.getNextCompress(System.currentTimeMillis()))) .format(new Date(backupManager.getNextCompress(System.currentTimeMillis())))
); );