package net.sf.openrocket.logging; import java.io.PrintWriter; import java.util.concurrent.atomic.AtomicInteger; /** * Container object for a log line. A log line consists of the following elements: * <ul> * <li>a LogLevel * <li>a TraceException * <li>a message * <li>a cause Throwable * <li>an incremental log line counter (provided by LogLine) * <li>a millisecond timestamp (provided by LogLine) * </ul> * Any one of the provided input values may be null. * * @author Sampo Niskanen <sampo.niskanen@iki.fi> */ public class LogLine implements Comparable<LogLine> { private static final AtomicInteger logCount = new AtomicInteger(1); private static final long startTime = System.currentTimeMillis(); private final LogLevel level; private final int count; private final long timestamp; private final TraceException trace; private final String message; private final Throwable cause; private volatile String formattedMessage = null; /** * Construct a LogLine at the current moment. The next log line count number is selected * and the current run time set to the timestamp. * * @param level the logging level * @param trace the trace exception for the log line, <code>null</code> permitted * @param message the log message * @param cause the causing throwable, <code>null</code> permitted */ public LogLine(LogLevel level, TraceException trace, String message, Throwable cause) { this(level, logCount.getAndIncrement(), System.currentTimeMillis() - startTime, trace, message, cause); } /** * Construct a LogLine with all parameters. This should only be used in special conditions, * for example to insert a log line at a specific point within normal logs. * * @param level the logging level * @param count the log line count number * @param timestamp the log line timestamp * @param trace the trace exception for the log line, <code>null</code> permitted * @param message the log message * @param cause the causing throwable, <code>null</code> permitted */ public LogLine(LogLevel level, int count, long timestamp, TraceException trace, String message, Throwable cause) { this.level = level; this.count = count; this.timestamp = timestamp; this.trace = trace; this.message = message; this.cause = cause; } /** * @return the level */ public LogLevel getLevel() { return level; } /** * @return the count */ public int getLogCount() { return count; } /** * @return the timestamp */ public long getTimestamp() { return timestamp; } public String getLocation() { if (trace != null) { return trace.getLocation(); } else { return "(-)"; } } /** * @return the message */ public String getMessage() { return message; } /** * @return the error */ public Throwable getCause() { return cause; } /** * Return a formatted string of the log line. The line contains the log * line count, the time stamp, the log level, the trace position, the log * message and, if provided, the stack trace of the error throwable. */ @Override public String toString() { if (formattedMessage == null) { String str; str = String.format("%4d %10.3f %-" + LogLevel.LENGTH + "s %s %s", count, timestamp / 1000.0, (level != null) ? level.toString() : "NULL", getLocation(), message); if (cause != null) { StackTraceWriter stw = new StackTraceWriter(); PrintWriter pw = new PrintWriter(stw); cause.printStackTrace(pw); pw.flush(); str = str + "\n" + stw.toString(); } formattedMessage = str; } return formattedMessage; } /** * Compare against another log line based on the log line count number. */ @Override public int compareTo(LogLine o) { return this.count - o.count; } }