Make sure log lines are written to the file in order

This commit is contained in:
Vankka 2022-03-28 16:57:02 +03:00
parent 68fa07eb15
commit bea4680739
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0

View File

@ -37,7 +37,9 @@ import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
public class DiscordSRVLogger implements Logger { public class DiscordSRVLogger implements Logger {
@ -45,10 +47,11 @@ public class DiscordSRVLogger implements Logger {
private static final String LOG_LINE_FORMAT = "[%s] [%s] %s"; private static final String LOG_LINE_FORMAT = "[%s] [%s] %s";
private static final String LOG_FILE_NAME_FORMAT = "%s-%s.log"; private static final String LOG_FILE_NAME_FORMAT = "%s-%s.log";
private final Queue<LogEntry> linesToAdd = new ConcurrentLinkedQueue<>();
private final DiscordSRV discordSRV; private final DiscordSRV discordSRV;
private final Path logsDirectory; private final Path logsDirectory;
private final List<Path> debugLogs; private final List<Path> debugLogs;
private final ReentrantLock debugLogLock = new ReentrantLock();
public DiscordSRVLogger(DiscordSRV discordSRV) { public DiscordSRVLogger(DiscordSRV discordSRV) {
this.discordSRV = discordSRV; this.discordSRV = discordSRV;
@ -62,6 +65,7 @@ public class DiscordSRVLogger implements Logger {
} }
this.debugLogs = rotateLog("debug", 3); this.debugLogs = rotateLog("debug", 3);
discordSRV.scheduler().runAtFixedRate(this::processLines, 0, 2, TimeUnit.SECONDS);
} }
public List<Path> getDebugLogs() { public List<Path> getDebugLogs() {
@ -117,16 +121,23 @@ public class DiscordSRVLogger implements Logger {
discordSRV.platformLogger().log(null, logLevel, message, throwable); discordSRV.platformLogger().log(null, logLevel, message, throwable);
} }
// TODO: handle trace // TODO: handle trace & hikari
Path debugLog = debugLogs.isEmpty() ? null : debugLogs.get(0); Path debugLog = debugLogs.isEmpty() ? null : debugLogs.get(0);
if (debugLog == null || logLevel == LogLevel.TRACE) { if (debugLog == null || logLevel == LogLevel.TRACE/* || loggerName.equals("Hikari")*/) {
return; return;
} }
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
discordSRV.scheduler().runFork(() -> writeToFile(loggerName, debugLog, time, logLevel, message, throwable)); linesToAdd.add(new LogEntry(debugLog, loggerName, time, logLevel, message, throwable));
} }
private void writeToFile(String loggerName, Path path, long time, LogLevel logLevel, String message, Throwable throwable) { private void processLines() {
LogEntry entry;
while ((entry = linesToAdd.poll()) != null) {
writeToFile(entry.log(), entry.loggerName(), entry.time(), entry.logLevel(), entry.message(), entry.throwable());
}
}
private void writeToFile(Path path, String loggerName, long time, LogLevel logLevel, String message, Throwable throwable) {
try { try {
if (message == null) { if (message == null) {
message = ""; message = "";
@ -141,25 +152,61 @@ public class DiscordSRVLogger implements Logger {
line += ExceptionUtils.getStackTrace(throwable) + "\n"; line += ExceptionUtils.getStackTrace(throwable) + "\n";
} }
synchronized (debugLogLock) { Path parent = path.getParent();
try { if (!Files.exists(parent)) {
debugLogLock.lock(); Files.createDirectories(parent);
Path parent = path.getParent();
if (!Files.exists(parent)) {
Files.createDirectories(parent);
}
if (!Files.exists(path)) {
Files.createFile(path);
}
Files.write(path, line.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
} finally {
debugLogLock.unlock();
}
} }
if (!Files.exists(path)) {
Files.createFile(path);
}
Files.write(path, line.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
} catch (Throwable e) { } catch (Throwable e) {
// Prevent infinite loop // Prevent infinite loop
discordSRV.platformLogger().error("Failed to write to debug log", e); discordSRV.platformLogger().error("Failed to write to debug log", e);
} }
} }
private static class LogEntry {
private final Path log;
private final String loggerName;
private final long time;
private final LogLevel logLevel;
private final String message;
private final Throwable throwable;
public LogEntry(Path log, String loggerName, long time, LogLevel logLevel, String message, Throwable throwable) {
this.log = log;
this.loggerName = loggerName;
this.time = time;
this.logLevel = logLevel;
this.message = message;
this.throwable = throwable;
}
public Path log() {
return log;
}
public String loggerName() {
return loggerName;
}
public long time() {
return time;
}
public LogLevel logLevel() {
return logLevel;
}
public String message() {
return message;
}
public Throwable throwable() {
return throwable;
}
}
} }