Package winterwell.utils.reporting

Source Code of winterwell.utils.reporting.LogFile

package winterwell.utils.reporting;

import java.io.Closeable;
import java.io.File;

import winterwell.utils.Utils;
import winterwell.utils.io.FileUtils;
import winterwell.utils.time.Dt;
import winterwell.utils.time.Time;

/**
* Pipe log reports out to a file.
* <p>
* Reports are written and flushed immediately. This is not the most efficient
* thing, but it guarantees that the log will not lose the reports leading up to
* a crash (ie. the important ones).
* <p>
* LogFile's stay alive until they are closed! Use {@link #close()} to remove
* this LogFile from the log listeners.
*
* @author daniel
* @testedby {@link LogFileTest}
*/
public class LogFile implements ILogListener, Closeable {

  private final File file;

  Time nextRotation;

  int rotationHistory;

  Dt rotationInterval;

  /**
   * Create a .log file named after the calling class. Will append if the file
   * already exists.
   * <p>
   * This is a wrapper for {@link #LogFile(File)}.
   */
  public LogFile() {
    this(new File(Utils.getCaller().getClassName() + ".log"));
  }

  /**
   * Create a log-listener and attach it to the Log.
   *
   * @param f
   */
  public LogFile(File f) {
    file = f;
    if (file.getParentFile() != null) {
      file.getParentFile().mkdirs();
    }
    Log.addListener(this);
  }

  /**
   * Delete all log entries from the file. The file will still exist but it
   * will be empty.
   */
  public void clear() {
    FileUtils.write(file, "");
  }

  /**
   * Stop listening to log events
   */
  @Override
  public void close() {
    Log.removeListener(this);
  }

  public File getFile() {
    return file;
  }

  @Override
  public void listen(Report report) {
    if (nextRotation != null && nextRotation.isBefore(report.getTime())) {
      rotateLogFiles();
    }
    // a single line for each report to make it easier to grep
    String line = report.toString().replaceAll("[\r\n]", " ") + "\n";
    // append to file (flushes immediately)
    synchronized (file) {
      FileUtils.append(line, file);
    }
  }

  /**
   * Move all the log files down one.
   */
  private synchronized void rotateLogFiles() {
    // advance the trigger
    nextRotation = nextRotation.plus(rotationInterval);
    // just nuke the current log?
    if (rotationHistory < 1) {
      FileUtils.delete(file);
      return;
    }
    // rotate the old logs
    for (int i = rotationHistory - 1; i != 0; i--) {
      File src = new File(file.getAbsolutePath() + "." + i);
      File dest = new File(file.getAbsolutePath() + "." + (i + 1));
      if (src.exists()) {
        FileUtils.move(src, dest);
      } else {
        FileUtils.delete(dest);
      }
    }
    // move the current log
    File src = file;
    File dest = new File(file.getAbsolutePath() + ".1");
    if (src.exists()) {
      FileUtils.move(src, dest);
    }
  }

  /**
   * By default, this class builds one giant log file. If this is set, logs
   * will get rotated - but only if this JVM keeps running for long enough!
   *
   * @param interval
   *            How often to rotate
   * @param history
   *            How many old log files to keep. 0 means just the current one.
   * @testedby {@link LogFileTest#testRotation()}
   */
  public void setLogRotation(Dt interval, int history) {
    this.rotationInterval = interval;
    this.rotationHistory = history;
    // FIXME how do we get the file created time?
    Time created = file.exists() ? new Time(file.lastModified())
        : new Time();
    nextRotation = created.plus(interval);
  }

  @Override
  public String toString() {
    return "LogFile:" + file.getAbsolutePath();
  }

}
TOP

Related Classes of winterwell.utils.reporting.LogFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.