package com.equalexperts.logging.impl; import java.io.IOException; import java.io.PrintStream; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; import static java.nio.file.StandardOpenOption.CREATE_NEW; import static java.nio.file.StandardOpenOption.WRITE; /** * A stack trace processor that stores the stack trace in a uniquely fingerprinted file in a given destination. * The URI of the file (whether new or existing) is included in the log message. */ public class FilesystemStackTraceProcessor implements StackTraceProcessor { private final Path destination; private final ThrowableFingerprintCalculator fingerprintCalculator; public FilesystemStackTraceProcessor(Path destination, ThrowableFingerprintCalculator fingerprintCalculator) { this.destination = destination; this.fingerprintCalculator = fingerprintCalculator; } @Override public void process(Throwable throwable, StringBuilder output) throws Exception { Path stackTraceFile = calculateFilenameForException(throwable); writeStacktraceToPathIfNecessary(throwable, stackTraceFile); printSubstituteMessage(output, throwable, stackTraceFile); } public Path getDestination() { return destination; } private void writeStacktraceToPathIfNecessary(Throwable throwable, Path stackTraceFile) throws IOException { if (Files.notExists(stackTraceFile)) { try(PrintStream out = new PrintStream(Files.newOutputStream(stackTraceFile, CREATE_NEW, WRITE))) { throwable.printStackTrace(out); } catch (FileAlreadyExistsException ignore) { //the exception is being written to (probably right now) } } } private void printSubstituteMessage(StringBuilder output, Throwable throwable, Path stackTraceFile) { output.append(throwable.toString()); output.append(" ("); output.append(stackTraceFile.toUri().toString()); output.append(")"); } private Path calculateFilenameForException(Throwable throwable) { String fingerprint = fingerprintCalculator.calculateFingerprint(throwable); String filePath = "stacktrace_" + fingerprint + ".txt"; return destination.resolve(filePath); } }