package edu.berkeley.nlp.lm.util; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.util.Stack; /** * Basic logging singleton class. The underlying LogInterface instance can be * changed to customize logging behaviour by calling setGlobalLogger. * * @author adampauls * */ @SuppressWarnings("ucd") public class Logger { /** * Logging interface. * * @author adampauls * */ public static interface LogInterface { /** * Log a string, but only once in a while. This is useful when we are * logging frequently and only wish to see lines every second or so. How * often logging is done is up to the implementation. * * @param s * printf style string * @param args * printf args */ public void logs(String s, Object... args); /** * Always log this string. * * @param s */ public void logss(String s); public void logss(String string, Object... args); /** * Start a track (a function, or some other logical unit of computation) * with a name given by <code>s</code>. * * @param s */ public void startTrack(String s); /** * Ends a track, printing out how long the track took. */ public void endTrack(); public void dbg(String s); public void err(String s); public void err(String s, Object... args); public void warn(String s); public void warn(String string, Object... args); } /** * Logs to System.out and System.err * * @author Aria Haghighi * */ @SuppressWarnings("ucd") public static class SystemLogger implements LogInterface { private final PrintStream out; private final PrintStream err; private int trackLevel = 0; private final boolean debug = true; public SystemLogger(final PrintStream out, final PrintStream err) { this.out = out; this.err = err; } public void close() { if (out != null) { out.close(); } if (err != null) { err.close(); } } public SystemLogger(final String outFile, final String errFile) throws FileNotFoundException { this(outFile != null ? new PrintStream(new FileOutputStream(outFile)) : null, errFile != null ? new PrintStream(new FileOutputStream(errFile)) : null); } public SystemLogger() { this(System.out, System.err); } private final Stack<Long> trackStartTimes = new Stack<Long>(); private String getIndentPrefix() { final StringBuilder builder = new StringBuilder(); for (int i = 0; i < trackLevel; ++i) { builder.append("\t"); } return builder.toString(); } private void output(final PrintStream o, final String txt) { if (o == null) return; final String[] lines = txt.split("\n"); final String prefix = getIndentPrefix(); for (final String line : lines) { o.println(prefix + line); } } @Override public void dbg(final String s) { if (debug) output(out, "[dbg] " + s); } private String timeString(final double milliSecs_) { double milliSecs = milliSecs_; String timeStr = ""; final int hours = (int) (milliSecs / (1000 * 60 * 60)); if (hours > 0) { milliSecs -= hours * 1000 * 60 * 60; timeStr += hours + "h"; } final int mins = (int) (milliSecs / (1000 * 60)); if (mins > 0) { milliSecs -= mins * 1000.0 * 60.0; timeStr += mins + "m"; } final int secs = (int) (milliSecs / 1000.0); //if (secs > 0) { //milliSecs -= secs * 1000.0; timeStr += secs + "s"; //} return timeStr; } @Override public void endTrack() { String timeStr = null; synchronized (this) { trackLevel--; final double milliSecs = System.currentTimeMillis() - trackStartTimes.pop(); timeStr = timeString(milliSecs); } output(out, "} " + (timeStr != null ? "[" + timeStr + "]" : "")); } @Override public void err(final String s) { err.println(s); } public void logs(final String s) { output(out, s); } @Override public void logss(final String s) { output(out, s); } @Override public void startTrack(final String s) { output(out, s + " {"); synchronized (this) { trackLevel++; trackStartTimes.push(System.currentTimeMillis()); } } @Override public void warn(final String s) { output(err, "[warn] " + s); } @Override public void logs(final String s, final Object... args) { logs(String.format(s, args)); } @Override public void err(final String s, final Object... args) { output(err, "[err] " + String.format(s, args)); } @Override public void warn(final String string, final Object... args) { warn(String.format(string, args)); } @Override public void logss(final String string, final Object... args) { logss(String.format(string, args)); } } /** * Default logging goes nowhere. * * @author adampauls * */ @SuppressWarnings("ucd") public static class NullLogger implements LogInterface { @Override public void logs(final String s, final Object... args) { } @Override public void logss(final String s) { } @Override public void startTrack(final String s) { } @Override public void endTrack() { } @Override public void dbg(final String s) { } @Override public void err(final String s) { } @Override public void err(final String s, final Object... args) { } @Override public void warn(final String s) { } @Override public void warn(final String string, final Object... args) { } @Override public void logss(final String string, final Object... args) { } } /** * Convenience class for stringing together loggers. * * @author adampauls * * */ @SuppressWarnings("ucd") public static class CompoundLogger implements LogInterface { private final LogInterface[] loggers; public CompoundLogger(final LogInterface... loggers) { this.loggers = loggers; } @Override public void logs(final String s, final Object... args) { for (final LogInterface logger : loggers) { logger.logs(s, args); } } @Override public void logss(final String s) { for (final LogInterface logger : loggers) { logger.logss(s); } } @Override public void startTrack(final String s) { for (final LogInterface logger : loggers) { logger.startTrack(s); } } @Override public void endTrack() { for (final LogInterface logger : loggers) { logger.endTrack(); } } @Override public void dbg(final String s) { for (final LogInterface logger : loggers) { logger.dbg(s); } } @Override public void err(final String s) { for (final LogInterface logger : loggers) { logger.err(s); } } @Override public void err(final String s, final Object... args) { for (final LogInterface logger : loggers) { logger.err(s, args); } } @Override public void warn(final String s) { for (final LogInterface logger : loggers) { logger.warn(s); } } @Override public void warn(final String string, final Object... args) { for (final LogInterface logger : loggers) { logger.warn(string, args); } } @Override public void logss(final String string, final Object... args) { for (final LogInterface logger : loggers) { logger.logss(string, args); } } } public synchronized static void setGlobalLogger(final LogInterface logger) { instance = logger; } public synchronized static LogInterface getGlobalLogger() { return instance; } private static LogInterface instance = new NullLogger(); public static LogInterface i() { return instance; } public static void setLogger(final LogInterface i) { instance = i; } public static void logs(final String s) { i().logs(s); } // Static Logger Methods public static void logs(final String s, final Object... args) { i().logs(s, args); } public static void logss(final String s) { i().logss(s); } public static void startTrack(final String s, final Object... args) { i().startTrack(String.format(s, args)); } public static void endTrack() { i().endTrack(); } public static void dbg(final String s) { i().dbg(s); } public static void err(final String s) { i().err(s); } public static void err(final String s, final Object... args) { i().err(s, args); } public static void warn(final String s) { i().warn(s); } public static void warn(final String string, final Object... args) { i().warn(string, args); } public static void logss(final String string, final Object... args) { i().logss(string, args); } }