All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ilex.util.FileLogger Maven / Gradle / Ivy

Go to download

A collection of software for aggregatting and processing environmental data such as from NOAA GOES satellites.

The newest version!
/*
*  $Id$
*/
package ilex.util;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.io.*;
import java.nio.channels.FileChannel;


/**
* Concrete subclass of Logger that Logs messages to a file.
* This provides a facility to limit the size of the log file to some
* set maximum.  The default maximum size of a log file is 10 megabytes.
* 

* If a log file with the given name already exists, new messages are * appended to the end of it. When the log file reaches the maximum * length, it will be closed, ".old" will be appended to its name, and * then a new log file will be opened with the original name. *

*/ public class FileLogger extends Logger { /** * The current output PrintStream */ private final AtomicReference output = new AtomicReference<>(); /** * The filename supplied to the constructor. */ protected String filename = null; /** * File object constructed from the file name. */ protected File outputFile = null; /** * Default length if none supplied by user. */ private static int defaultMaxLength = 10000000; // 10 meg. /** * User-settable maximum log file length. */ private int maxLength = defaultMaxLength; /** * Flag determining whether constructor overwrites or appends. * By default, set to true, meaning that the constructor will append * to an existing file when it starts up. * Set to false to cause the constructor to zero and start a new log. */ public static boolean appendFlag = true; private FileChannel fileChan = null; private AtomicBoolean closeOperations = new AtomicBoolean(false); private BlockingQueue queue = new ArrayBlockingQueue<>(5000); // TODO: intentionally arbitrary number for now.; private Thread writerThread; /** * Construct with a process name and a filename. * @param procName Name of this process, to appear in each log message. * @param filename Name of log file. * @throws FileNotFoundException if can't open file */ public FileLogger( String procName, String filename ) throws FileNotFoundException { this(procName, filename, defaultMaxLength); } /** * Construct with a process name, a filename, and a maximum length. * When it reaches the maximum length, the log file will be closed, * ".old" will be appended to its name, and then a new log file will * be opened with the original name. * @param procName Name of this process, to appear in each log message. * @param filename Name of log file. * @param maxLength Maximum length of log file * @throws FileNotFoundException if can't open file */ public FileLogger( String procName, String filename, int maxLength ) throws FileNotFoundException { super(procName); this.filename = EnvExpander.expand(filename); this.maxLength = maxLength; openNewLog(); writerThread = new Thread(() -> { while(closeOperations.get() == false) { try { String msg = queue.poll(1, TimeUnit.SECONDS); PrintStream ps = output.get(); if (msg != null && ps != null && !ps.checkError()) { ps.println(msg); } } catch (InterruptedException ex) { } } }, "FileLogger-Writer"); writerThread.setDaemon(true); writerThread.start(); } /** * Close this log file. */ public void close( ) { PrintStream ps = output.getAndSet(null); if (ps != null) { ps.close(); } fileChan = null; } /** * Logs a message. The priority has already been checked to make sure * that this message should be logged. * This method is called from the base class log method. * @param priority the priority * @param text the formatted log message text */ public synchronized void doLog( int priority, String text ) { try { queue.put(standardMessage(priority, text)); } catch (InterruptedException ex) { // NOTE: use of STDERR is intentional here. This is an error with logging itself. System.err.println("Unable to put data in the log message queue."); ex.printStackTrace(); } } /** * Closes the current log, renames it with an aging extension, and * opens a new log. */ public synchronized void rotateLogs() { // Note: This needs to be a separate method because it must be // synchronized with doLog(). // And because doLog() calls rotate(), it can't be syncrhonized. rotate(); } /** * Does the actual rotation. * Called internally when the log reaches its maximum size. May also * be called by the synchronized rotateLogs() method which can be * called externally by the application. */ protected void rotate() { close(); renameCurrentLog(); openNewLog(); } protected void openNewLog() { outputFile = new File(filename); try { // NOTE: not ideal to have this special case, but it makes setting up the ant // run task easier and makes sure in windows we have a way to send logs to stdout. // I'm pretty sure just CON: worked on the terminal so it's probably some odd // interaction with ant and how the command itself is run. OutputStream os = null; if (filename.equalsIgnoreCase("CON:")) { os = System.out; } else { os = new FileOutputStream(outputFile, appendFlag); } output.set(new PrintStream(os, true)); } catch(IOException ex) { System.err.println("IOException trying to open log file '" + filename + "': " + ex); throw new RuntimeException("Unable to open log file.",ex); } } /** * Renames the current log with a suffix indicating it is now old. */ protected void renameCurrentLog() { File oldFile = new File(filename + ".old"); if (oldFile.exists()) oldFile.delete(); outputFile.renameTo(oldFile); } /** * Returns the PrintStream currently being used for log output. Allows * caller to print directly to the file. E.g. for exception stack traces. * @return PrintStream for direct log file output */ public PrintStream getLogOutput( ) { return output.get(); } /** * Sets the maximum length of the file. When the file reaches this length * it is renamed with a ".old" extension, and a new file is created. * The software appends log messages until the specified length has * been exceeded. Hence the actual length of the file may be slightly * more than the specified maximum. * * @param len Length of file in bytes. */ public void setMaxLength( int len ) { maxLength = len; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy