SimpleLogFormatter.java

/*
 * SimpleLogFormatter
 *
 * $Id$
 * $HeadURL$
 */
package gov.usgs.util.logging;

import java.util.Date;

import java.util.logging.Formatter;
import java.util.logging.LogRecord;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.time.Instant;
import java.time.temporal.ChronoUnit;

/**
 * Simple(r) log formatter for java.util.logging messages.
 *
 * Outputs unique dates once, with all messages sharing that time tab indented
 * below.
 *
 * Example Format:
 *
 * <pre>
 * Wed Sep 30 19:31:48 GMT 2009
 * INFO    Exit code=0
 * Wed Sep 30 19:32:52 GMT 2009
 * INFO    [polldir] duplicate product id=urn:earthquake-usgs-gov:shakemap-scraper:global:2009medd:1
 * Wed Sep 30 19:32:53 GMT 2009
 * INFO    [polldir] received urn:earthquake-usgs-gov:shakemap-scraper:global:2009medd:1
 * INFO    [losspager] filtering type 'shakemap-scraper', not allowed
 * INFO    [logging_client] received urn:earthquake-usgs-gov:shakemap-scraper:global:2009medd:1
 * INFO    [shakemap] received urn:earthquake-usgs-gov:shakemap-scraper:global:2009medd:1
 * </pre>
 *
 */
public class SimpleLogFormatter extends Formatter {

  /** Milliseconds in a second. */
  public static final long MILLIS_PER_SECOND = 1000;

  /** When the last LogRecord was processed. */
  private long lastMillis = 0;

  /** Whether timestamps are appended to each log entry */
  private boolean timestampsEnabled = false;

  /** Default constructor. */
  public SimpleLogFormatter() {
  }

  /**
   * Constructor with log timestamp option.
   *
   * @param timestampsEnabled flag indicating if timestamps are included or not
   */
  public SimpleLogFormatter(boolean timestampsEnabled) {
    this.timestampsEnabled = timestampsEnabled;
  }

  /**
   * Format a LogRecord for output.
   *
   * @param record LogRecord to format.
   *
   * @return formatted LogRecord as String.
   */
  public final String format(final LogRecord record) {
    StringBuffer buf = new StringBuffer();

    if (lastMillis == 0) {
      // first run...
      buf.append("\n###\n");
    }

    // chop to nearest second, not outputting millis...
    long millis = (record.getMillis() / MILLIS_PER_SECOND) * MILLIS_PER_SECOND;
    if (millis != lastMillis) {
      lastMillis = millis;
      // add date
      buf.append(new Date(lastMillis).toString()).append("\n");
    }

    // append UTC timestamps to each log entry
    if (this.timestampsEnabled) {
      Instant utcDateTime = Instant.now().truncatedTo(ChronoUnit.MILLIS);
      buf.append(utcDateTime).append(" ");
    }

    // add log message
    // buf.append(millis + " ");
    buf.append(record.getLevel().toString());
    buf.append("\tthread=").append(record.getLongThreadID());
    buf.append("\t").append(formatMessage(record));
    buf.append("\n");

    // output any associated exception
    Throwable thrown = record.getThrown();
    if (thrown != null) {
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      thrown.printStackTrace(new PrintStream(out, true));
      buf.append(new String(out.toByteArray()));
    }

    return buf.toString();
  }

  /**
   * Check if time stamps are currently enabled.
   *
   * @return flag indicating if timestamps are currently enabled
   */
  public Boolean getTimestampsEnabled() {
    return this.timestampsEnabled;
  }

  /**
   * Set if timestamps are currently enabled.
   *
   * @param timestampsEnabled True to enable timestamps, false otherwise.
   */
  public void setTimestampsEnabled(Boolean timestampsEnabled) {
    this.timestampsEnabled = timestampsEnabled;
  }

}