| | |
| | | import java.io.File; |
| | | import java.io.FileOutputStream; |
| | | import java.io.IOException; |
| | | import java.nio.charset.Charset; |
| | | import java.nio.file.Files; |
| | | import java.util.Date; |
| | | import java.text.DateFormat; |
| | |
| | | */ |
| | | public static TempLogFile newTempLogFile(final String prefix) |
| | | { |
| | | return newTempLogFile(prefix, null); |
| | | } |
| | | |
| | | /** |
| | | * Creates a new temporary log file in the given directory. |
| | | * <p> |
| | | * The directory is created if it does not exist yet. When it is {@code null} or cannot be |
| | | * used, the log file goes to the OS temporary directory instead, as with |
| | | * {@link #newTempLogFile(String)}. The name of the file follows the pattern |
| | | * prefix-[RANDOM_NUMBER_STRING].log either way. |
| | | * |
| | | * @param prefix |
| | | * log file prefix to which log messages will be written. |
| | | * @param directory |
| | | * the directory to create the log file in, or {@code null} for the OS temporary |
| | | * directory. |
| | | * @return a new temporary log file. |
| | | */ |
| | | public static TempLogFile newTempLogFile(final String prefix, final File directory) |
| | | { |
| | | IOException fallbackReason = null; |
| | | if (directory != null) |
| | | { |
| | | try |
| | | { |
| | | Files.createDirectories(directory.toPath()); |
| | | return new TempLogFile(Files.createTempFile(directory.toPath(), prefix, ".log").toFile()); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | // Nothing can be logged yet: the first publisher is the one the constructor installs |
| | | // below, so the warning has to wait until there is a log to write it to. |
| | | fallbackReason = e; |
| | | } |
| | | } |
| | | try |
| | | { |
| | | return new TempLogFile(Files.createTempFile(prefix, ".log").toFile()); |
| | | final TempLogFile tempLogFile = new TempLogFile(Files.createTempFile(prefix, ".log").toFile()); |
| | | if (fallbackReason != null) |
| | | { |
| | | localizedLogger.warn(LocalizableMessage.raw("Unable to create temp log file in " + directory |
| | | + " because: " + fallbackReason.getMessage() + ", falling back to the temporary directory"), |
| | | fallbackReason); |
| | | } |
| | | return tempLogFile; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | |
| | | { |
| | | this.logFile = null; |
| | | this.writer=null; |
| | | this.startupErrorLogPublisher = null; |
| | | this.startupDebugLogPublisher = null; |
| | | } |
| | | |
| | | final TextWriter writer; |
| | | /** Kept so that they can be taken off the logger singletons again, see {@link #deleteLogFileAfterSuccess()}. */ |
| | | private final ErrorLogPublisher startupErrorLogPublisher; |
| | | private final DebugLogPublisher startupDebugLogPublisher; |
| | | |
| | | private TempLogFile(final File file) throws IOException |
| | | { |
| | |
| | | }else { |
| | | writer=new TextWriter.STREAM(new FileOutputStream(file)); |
| | | } |
| | | ErrorLogPublisher startupErrorLogPublisher = TextErrorLogPublisher.getServerStartupTextErrorPublisher(writer); |
| | | startupErrorLogPublisher = TextErrorLogPublisher.getServerStartupTextErrorPublisher(writer); |
| | | ErrorLogger.getInstance().addLogPublisher(startupErrorLogPublisher); |
| | | DebugLogger.getInstance().addPublisherIfRequired(writer); |
| | | startupDebugLogPublisher = DebugLogger.getInstance().addPublisherIfRequired(writer); |
| | | |
| | | localizedLogger.info(LocalizableMessage.raw("QuickSetup application launched " + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG).format(new Date()), null)); |
| | | } |
| | |
| | | return logFile; |
| | | } |
| | | |
| | | /** Closes the log file handler and delete the temp log file . */ |
| | | /** |
| | | * Closes the log file handler and delete the temp log file . |
| | | * <p> |
| | | * The publishers installed by the constructor go with it: they are held by the logger |
| | | * singletons, which outlive this object, and once the writer is shut everything they are |
| | | * handed is written to a closed stream and swallowed. |
| | | */ |
| | | public void deleteLogFileAfterSuccess() |
| | | { |
| | | if (isEnabled()) |
| | | { |
| | | if (startupErrorLogPublisher != null) { |
| | | ErrorLogger.getInstance().removeLogPublisher(startupErrorLogPublisher); |
| | | } |
| | | if (startupDebugLogPublisher != null) { |
| | | DebugLogger.getInstance().removeLogPublisher(startupDebugLogPublisher); |
| | | } |
| | | if (writer!=null) { |
| | | writer.shutdown(); |
| | | } |
| | |
| | | } |
| | | |
| | | /** |
| | | * Return {@code true} if the temp log file is still on disk and can be read. |
| | | * <p> |
| | | * Unlike {@link #isEnabled()} this is about the file, not the logger: something else may have |
| | | * removed the file while the logger still writes to it (see issue #1030), and then there is |
| | | * nothing to hand over to whoever needs the log. |
| | | * |
| | | * @return {@code true} if the temp log file is there and readable. |
| | | */ |
| | | public boolean isReadable() |
| | | { |
| | | return logFile != null && Files.isReadable(logFile.toPath()) && Files.isRegularFile(logFile.toPath()); |
| | | } |
| | | |
| | | /** |
| | | * Reads the whole temp log file. |
| | | * <p> |
| | | * The file is decoded with the default charset of the JVM, which is the one |
| | | * {@link TextWriter.STREAM} wrote it with: reader and writer are the same JVM, so a |
| | | * non-ASCII path or base DN in a report comes back as it was logged. |
| | | * |
| | | * @return the contents of the temp log file. |
| | | * @throws IOException |
| | | * if the file cannot be read, for instance because it is no longer there. |
| | | */ |
| | | public String readContents() throws IOException |
| | | { |
| | | if (logFile == null) |
| | | { |
| | | throw new IOException("No temp log file"); |
| | | } |
| | | return new String(Files.readAllBytes(logFile.toPath()), Charset.defaultCharset()); |
| | | } |
| | | |
| | | /** |
| | | * Return the absolute path of the temp log file. |
| | | * @return the absolute path of the temp log file. |
| | | */ |