package org.googlecode.perftrace.perf4j; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.logging.Logger; import java.util.logging.Level; import org.googlecode.perftrace.JavaLogPerftrace; /** * This LoggingStopWatch uses a java.util.logging Logger to persist the * StopWatch messages. The various constructors allow you to specify the Logger * to use (defaults to org.perf4j.TimingLogger), the Level at which messages are * normally logged (defaults to INFO) and the Level used for logging if one of * the stop or lap methods that takes an exception is called (defaults to * WARNING). * * @author Alex Devine */ @SuppressWarnings("serial") public class JavaLogStopWatch extends LoggingStopWatch { private transient Logger logger; private Level normalPriority; private Level exceptionPriority; // --- Constructors --- /** * Creates a JavaLogStopWatch with a blank tag, no message and started at * the instant of creation. The Logger with the name * "org.perf4j.TimingLogger" is used to log stop watch messages at the INFO * level, or at the WARNING level if an exception is passed to one of the * stop or lap methods. */ public JavaLogStopWatch() { this("", null, false, Logger.getLogger(DEFAULT_LOGGER_NAME), Level.INFO, Level.WARNING); } /** * Creates a JavaLogStopWatch with a blank tag, no message and started at * the instant of creation, using the specified Logger to log stop watch * messages at the INFO level, or at the WARNING level if an exception is * passed to one of the stop or lap methods. * * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. */ public JavaLogStopWatch(Logger logger) { this("", null, false, logger, Level.INFO, Level.WARNING); } /** * Creates a JavaLogStopWatch with a blank tag, no message and started at * the instant of creation, using the specified Logger to log stop watch * messages at the normalPriority level specified, or at the WARNING level * if an exception is passed to one of the stop or lap methods. * * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. * @param normalPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that does NOT take an exception is called. */ public JavaLogStopWatch(Logger logger, Level normalPriority) { this("", null, false, logger, normalPriority, Level.WARNING); } /** * Creates a JavaLogStopWatch with a blank tag, no message and started at * the instant of creation, using the specified Logger to log stop watch * messages at the normalPriority level specified, or at the * exceptionPriority level if an exception is passed to one of the stop or * lap methods. * * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. * @param normalPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that does NOT take an exception is called. * @param exceptionPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that DOES take an exception is called. */ public JavaLogStopWatch(Logger logger, Level normalPriority, Level exceptionPriority) { this("", null, false, logger, normalPriority, exceptionPriority); } /** * Creates a JavaLogStopWatch with the tag specified, no message and started * at the instant of creation. The Logger with the name * "org.perf4j.TimingLogger" is used to log stop watch messages at the INFO * level, or at the WARNING level if an exception is passed to one of the * stop or lap methods. * * @param tag * The tag name for this timing call. Tags are used to group * timing logs, thus each block of code being timed should have a * unique tag. Note that tags can take a hierarchical format * using dot notation. */ public JavaLogStopWatch(String tag, boolean isRootMethod) { this(tag, null, isRootMethod, Logger.getLogger(DEFAULT_LOGGER_NAME), Level.INFO, Level.WARNING); } /** * Creates a JavaLogStopWatch with the tag specified, no message and started * at the instant of creation, using the specified Logger to log stop watch * messages at INFO level, or at the WARNING level if an exception is passed * to one of the stop or lap methods. * * @param tag * The tag name for this timing call. Tags are used to group * timing logs, thus each block of code being timed should have a * unique tag. Note that tags can take a hierarchical format * using dot notation. * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. */ public JavaLogStopWatch(String tag, boolean isRootMethod, Logger logger) { this(tag, null, isRootMethod, logger, Level.INFO, Level.WARNING); } /** * Creates a JavaLogStopWatch with the tag specified, no message and started * at the instant of creation, using the specified Logger to log stop watch * messages at the normalPriority level specified, or at the WARNING level * if an exception is passed to one of the stop or lap methods. * * @param tag * The tag name for this timing call. Tags are used to group * timing logs, thus each block of code being timed should have a * unique tag. Note that tags can take a hierarchical format * using dot notation. * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. * @param normalPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that does NOT take an exception is called. */ public JavaLogStopWatch(String tag, boolean isRootMethod, Logger logger, Level normalPriority) { this(tag, null, isRootMethod, logger, normalPriority, Level.WARNING); } /** * Creates a JavaLogStopWatch with the tag specified, no message and started * at the instant of creation, using the specified Logger to log stop watch * messages at the normalPriority level specified, or at the * exceptionPriority level if an exception is passed to one of the stop or * lap methods. * * @param tag * The tag name for this timing call. Tags are used to group * timing logs, thus each block of code being timed should have a * unique tag. Note that tags can take a hierarchical format * using dot notation. * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. * @param normalPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that does NOT take an exception is called. * @param exceptionPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that DOES take an exception is called. */ public JavaLogStopWatch(String tag, boolean isRootMethod, Logger logger, Level normalPriority, Level exceptionPriority) { this(tag, null, isRootMethod, logger, normalPriority, exceptionPriority); } /** * Creates a JavaLogStopWatch with the tag and message specified and started * at the instant of creation. The Logger with the name * "org.perf4j.TimingLogger" is used to log stop watch messages at the INFO * level, or at the WARNING level if an exception is passed to one of the * stop or lap methods. * * @param tag * The tag name for this timing call. Tags are used to group * timing logs, thus each block of code being timed should have a * unique tag. Note that tags can take a hierarchical format * using dot notation. * @param message * Additional text to be printed with the logging statement of * this StopWatch. */ public JavaLogStopWatch(String tag, String message, boolean isRootMethod) { this(tag, message, isRootMethod, Logger.getLogger(DEFAULT_LOGGER_NAME), Level.INFO, Level.WARNING); } /** * Creates a JavaLogStopWatch with the tag and message specified and started * at the instant of creation, using the specified Logger to log stop watch * messages at INFO level, or at WARNING level if an exception is passed to * one of the stop or lap methods. * * @param tag * The tag name for this timing call. Tags are used to group * timing logs, thus each block of code being timed should have a * unique tag. Note that tags can take a hierarchical format * using dot notation. * @param message * Additional text to be printed with the logging statement of * this StopWatch. * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. */ public JavaLogStopWatch(String tag, String message, boolean isRootMethod, Logger logger) { this(tag, message, isRootMethod, logger, Level.INFO, Level.WARNING); } /** * Creates a JavaLogStopWatch with the tag and message specified and started * at the instant of creation, using the specified Logger to log stop watch * messages at the normalPriority level specified, or at WARNING level if an * exception is passed to one of the stop or lap methods. * * @param tag * The tag name for this timing call. Tags are used to group * timing logs, thus each block of code being timed should have a * unique tag. Note that tags can take a hierarchical format * using dot notation. * @param message * Additional text to be printed with the logging statement of * this StopWatch. * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. * @param normalPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that does NOT take an exception is called. */ public JavaLogStopWatch(String tag, String message, boolean isRootMethod, Logger logger, Level normalPriority) { this(tag, message, isRootMethod, logger, normalPriority, Level.WARNING); } /** * Creates a JavaLogStopWatch with the tag and message specified and started * at the instant of creation, using the specified Logger to log stop watch * messages at the normalPriority level specified, or at the * exceptionPriority level if an exception is passed to one of the stop or * lap methods. * * @param tag * The tag name for this timing call. Tags are used to group * timing logs, thus each block of code being timed should have a * unique tag. Note that tags can take a hierarchical format * using dot notation. * @param message * Additional text to be printed with the logging statement of * this StopWatch. * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. * @param normalPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that does NOT take an exception is called. * @param exceptionPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that DOES take an exception is called. */ public JavaLogStopWatch(String tag, String message, boolean isRootMethod, Logger logger, Level normalPriority, Level exceptionPriority) { this(System.currentTimeMillis(), -1L, tag, message, isRootMethod, logger, normalPriority, exceptionPriority); } /** * This constructor is mainly used for creation of StopWatch instances from * logs and for testing. Users should normally not call this constructor in * client code. * * @param startTime * The start time in milliseconds * @param elapsedTime * The elapsed time in milliseconds * @param tag * The tag used to group timing logs of the same code block * @param message * Additional message text * @param logger * The Logger to use when persisting StopWatches in one of the * stop or lap methods. * @param normalPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that does NOT take an exception is called. * @param exceptionPriority * The level at which this StopWatch is logged if one of the stop * or lap methods that DOES take an exception is called. */ public JavaLogStopWatch(long startTime, long elapsedTime, String tag, String message, boolean isRootMethod, Logger logger, Level normalPriority, Level exceptionPriority) { super(startTime, elapsedTime, tag, message, isRootMethod, JavaLogPerftrace.getInstance()); this.logger = logger; this.normalPriority = normalPriority; this.exceptionPriority = exceptionPriority; } // --- Bean Methods --- /** * Gets the java.util.logging Logger that is used to persist logging * statements when one of the stop or lap methods is called. * * @return The Logger used for StopWatch persistence. */ public Logger getLogger() { return logger; } /** * Sets the java.util.logging Logger used to persist StopWatch instances. * * @param logger * The Logger this instance should use for persistence. May not * be null. * @return this instance, for use with method chaining if desired */ public JavaLogStopWatch setLogger(Logger logger) { this.logger = logger; return this; } /** * Gets the Level at which log statements will be made when one of the stop * or lap methods that does NOT take an exception is called. * * @return The Level used when logging "normal" stop or lap calls. */ public Level getNormalPriority() { return normalPriority; } /** * Sets the Level at which log statements will be made when one of the stop * or lap methods that does NOT take an exception is called. * * @param normalPriority * The Level used when logging "normal" stop or lap calls. May * not be null. * @return this instance, for use with method chaining if desired */ public JavaLogStopWatch setNormalPriority(Level normalPriority) { this.normalPriority = normalPriority; return this; } /** * Gets the Level at which log statements will be made when one of the stop * or lap methods that DOES take an exception is called. * * @return The Level used when logging "exception" stop or lap calls. */ public Level getExceptionPriority() { return exceptionPriority; } /** * Sets the Level at which log statements will be made when one of the stop * or lap methods that DOES take an exception is called. This should usually * be at a level equal to or higher than the normal priority. * * @param exceptionPriority * The Level used when logging "exceptional" stop or lap calls. * May not be null. * @return this instance, for use with method chaining if desired */ public JavaLogStopWatch setExceptionPriority(Level exceptionPriority) { this.exceptionPriority = exceptionPriority; return this; } // Just overridden to make use of covariant return types public JavaLogStopWatch setTimeThreshold(long timeThreshold) { super.setTimeThreshold(timeThreshold); return this; } // Just overridden to make use of covariant return types public JavaLogStopWatch setTag(String tag) { super.setTag(tag); return this; } // Just overridden to make use of covariant return types public JavaLogStopWatch setMessage(String message) { super.setMessage(message); return this; } // Just overridden to make use of covariant return types public JavaLogStopWatch setNormalAndSlowSuffixesEnabled( boolean normalAndSlowSuffixesEnabled) { super.setNormalAndSlowSuffixesEnabled(normalAndSlowSuffixesEnabled); return this; } // Just overridden to make use of covariant return types public JavaLogStopWatch setNormalSuffix(String normalSuffix) { super.setNormalSuffix(normalSuffix); return this; } // Just overridden to make use of covariant return types public JavaLogStopWatch setSlowSuffix(String slowSuffix) { super.setSlowSuffix(slowSuffix); return this; } // --- Helper Methods --- /** * This method returns true if the logger it uses is enabled at the * normalPriority level of this StopWatch. * * @return true if this StopWatch will output log messages when one of the * stop or lap messages that does NOT take an exception is called. */ public boolean isLogging() { return logger.isLoggable(normalPriority); } /** * The log message is overridden to use the java.util.logging Logger to * persist the stop watch. * * @param stopWatchAsString * The stringified view of the stop watch for logging. * @param exception * An exception, if any, that was passed to the stop or lap * method. If this is null then logging will occur at * normalPriority, if non-null it will occur at * exceptionPriority. */ protected void log(String stopWatchAsString, Throwable exception) { logger.log((exception == null) ? normalPriority : exceptionPriority, stopWatchAsString, exception); } // --- Static Utility Methods --- /** * This utility method provides the standard mapping between log4j level * names (which Perf4J uses as the standard set of possible levels) to the * closest corresponding java.util.logging Level. * * @param levelName * The name of the logging level, should be one of TRACE, DEBUG, * INFO, WARN, ERROR or FATAL. * @return The java.util.logging Level that is the closest match to the * log4j Level name. */ public static Level mapLevelName(String levelName) { levelName = levelName.toUpperCase(); if ("TRACE".equals(levelName)) { return Level.FINEST; } if ("DEBUG".equals(levelName)) { return Level.FINE; } if ("INFO".equals(levelName)) { return Level.INFO; } if ("WARN".equals(levelName)) { return Level.WARNING; } if ("ERROR".equals(levelName)) { return Level.SEVERE; } if ("FATAL".equals(levelName)) { return Level.SEVERE; } return Level.INFO; } // --- Object Methods --- public JavaLogStopWatch clone() { return (JavaLogStopWatch) super.clone(); } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeUTF(logger.getName()); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); this.logger = Logger.getLogger(stream.readUTF()); } }