package core.framework.impl.log;
import core.framework.api.util.Charsets;
import core.framework.api.util.Exceptions;
import core.framework.api.util.Randoms;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import static core.framework.api.util.Files.createDir;
import static java.nio.file.Files.createFile;
/**
* @author neo
*/
public final class TraceLogger {
private static final DateTimeFormatter TRACE_LOG_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
public static TraceLogger console() {
return new TraceLogger(null);
}
public static TraceLogger file(Path traceLogPath) {
createDir(traceLogPath);
return new TraceLogger(traceLogPath);
}
private final PrintStream errorLogger = System.err;
private final Path traceLogPath;
private boolean console;
TraceLogger(Path traceLogPath) {
this.traceLogPath = traceLogPath;
}
void write(ActionLog log) {
if (!log.flushTraceLog()) return;
Writer writer = createWriter(log);
try {
for (LogEvent event : log.events) {
String message = event.logMessage();
writer.write(message);
}
} catch (IOException e) {
errorLogger.println("failed to write trace log, error=" + Exceptions.stackTrace(e));
} finally {
close(writer);
}
}
private void close(Writer writer) {
try {
if (console) {
writer.flush(); // do not close System.err (when traceLogPath is null)
} else {
writer.close();
}
} catch (IOException e) {
errorLogger.println("failed to close writer, error=" + Exceptions.stackTrace(e));
}
}
private Writer createWriter(ActionLog log) {
if (traceLogPath != null) {
try {
String logPath = traceLogFilePath(traceLogPath.toString(), LocalDateTime.ofInstant(log.date, ZoneId.systemDefault()), log.action, log.id);
log.context.put("logPath", logPath); // not log as event but add value to context, no need to see logPath in trace
Path path = Paths.get(logPath).toAbsolutePath();
createDir(path.getParent());
createFile(path);
return Files.newBufferedWriter(path, Charsets.UTF_8, StandardOpenOption.APPEND);
} catch (IOException e) {
errorLogger.println("failed to create trace log file, error=" + Exceptions.stackTrace(e));
}
}
console = true;
return new BufferedWriter(new OutputStreamWriter(System.err, Charsets.UTF_8));
}
String traceLogFilePath(String logDirectory, LocalDateTime date, String action, String id) {
String sequence = Randoms.alphaNumeric(5);
return logDirectory + "/" + action + "/" + TRACE_LOG_DATE_FORMAT.format(date) + "." + id + "." + sequence + ".log";
}
}