/* * $Id$ * * Copyright 2006, The jCoderZ.org Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * Neither the name of the jCoderZ.org Project nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jcoderz.commons.logging; import java.io.PrintWriter; import java.text.Format; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Set; import org.jcoderz.commons.util.Assert; /** * This printer prints the log information as lines of text and uses the display * options for selecting the fields to display. * The format is similar to the log file format. * */ public class BasicPrinter extends LogPrinter { private static final String SOURCE_TAG = "_LOGGED_AT_"; private static final String SOLUTION_TAG = "_SOLUTION_"; private static final String SYMBOL_TAG = "_SYMBOL_"; private static final String FIRST_MSG_ITEM = "{0}"; private MessageFormat mStackTraceFormat = null; private MessageFormat mTraceLineFormat = null; private MessageFormat mLogMessageFormat = null; private MessageFormat mParameterLineFormat = null; private MessageFormat mNestedLineFormat = null; private Object[] mStackTraceData = null; private Object[] mTraceLineData = null; private Object[] mLogMessageData = null; private Object[] mParameterLineData = null; private Object[] mNestedLineData = null; private final StringBuffer mBuffer = new StringBuffer(); /** {@inheritDoc} */ public void setDisplayOptions (DisplayOptions options) { super.setDisplayOptions(options); setStackTraceFormat(); setTraceLineFormat(); setLogMessageFormat(); setParameterLineFormat(); setNestedLineFormat(); } /** {@inheritDoc} */ public void print ( final PrintWriter printer, final LogItem entry) { LogItem currentEntry = entry; Assert.notNull(printer, "Printer"); Assert.notNull(entry, "entry"); Assert.notNull(entry.getType(), "entry.getType()"); final List trackingIds = new ArrayList(); while (currentEntry != null) { printEntry(printer, currentEntry, trackingIds); currentEntry = currentEntry.getNestedItem(); if (currentEntry != null) { printNesting(printer, currentEntry, trackingIds); } } currentEntry = entry; trackingIds.clear(); while (currentEntry != null) { if (displayStackTrace(currentEntry)) { printStackTrace(printer, currentEntry, trackingIds); } currentEntry = currentEntry.getNestedItem(); } } /** * @param printer * @param currentEntry * @param trackingIds */ private void printEntry ( final PrintWriter printer, final LogItem entry, final List trackingIds) { if (! entry.isExceptionItem()) { addTrackingNumber(trackingIds, entry.getTrackingNumber()); final LogLineFormat.LogLineType type = LogLineFormat.getLogLineType(entry.getType().charAt(0)); if ((type == LogLineFormat.TRACE_MESSAGE) || (type == LogLineFormat.EXCEPTION_MESSAGE)) { printTraceLine(printer, entry, trackingIds); } else if ((type == LogLineFormat.LOG_MESSAGE) || (type == LogLineFormat.ERROR_MESSAGE)) { printMessageLine(printer, entry, trackingIds); printParameters(printer, entry, trackingIds); } } } private void setStackTraceFormat () { final Format[] formats = StackTraceFormat.getFormatList( getDisplayOptions(), false); mStackTraceData = new Object[formats.length]; final StringBuffer pattern = new StringBuffer(FIRST_MSG_ITEM); for (int i = 1; i < formats.length; ++i) { pattern.append(" {").append(i).append('}'); } mStackTraceFormat = new MessageFormat(pattern.toString()); mStackTraceFormat.setFormats(formats); } private void setTraceLineFormat () { final Format[] formats = TraceLineFormat.getFormatList( getDisplayOptions(), false); mTraceLineData = new Object[formats.length]; final StringBuffer pattern = new StringBuffer(FIRST_MSG_ITEM); for (int i = 1; i < formats.length; ++i) { pattern.append(" {").append(i).append('}'); } mTraceLineFormat = new MessageFormat(pattern.toString()); mTraceLineFormat.setFormats(formats); } private void setLogMessageFormat () { final Format[] formats = MessageLineFormat.getFormatList( getDisplayOptions(), false); mLogMessageData = new Object[formats.length]; final StringBuffer pattern = new StringBuffer(FIRST_MSG_ITEM); for (int i = 1; i < formats.length; ++i) { pattern.append(" {").append(i).append('}'); } mLogMessageFormat = new MessageFormat(pattern.toString()); mLogMessageFormat.setFormats(formats); } private void setParameterLineFormat () { final Format[] formats = ParameterLineFormat.getFormatList( getDisplayOptions(), false); mParameterLineData = new Object[formats.length]; final StringBuffer pattern = new StringBuffer(FIRST_MSG_ITEM); int i; for (i = 1; i < formats.length - 1; ++i) { pattern.append(" {").append(i).append('}'); } pattern.append(": \t{").append(i).append('}'); mParameterLineFormat = new MessageFormat(pattern.toString()); mParameterLineFormat.setFormats(formats); } private void setNestedLineFormat () { final Format[] formats = NestedLineFormat.getFormatList( getDisplayOptions(), false); mNestedLineData = new Object[formats.length]; final StringBuffer pattern = new StringBuffer(); int i = 0; for (i = 0; i < formats.length - 1; ++i) { pattern.append('{').append(i).append("} "); } pattern.append("Caused by: {").append(i).append('}'); mNestedLineFormat = new MessageFormat(pattern.toString()); mNestedLineFormat.setFormats(formats); } private void printTraceLine ( final PrintWriter writer, final LogItem entry, final List trackingIds) { int i = 0; i = setTimeStamp(i, mTraceLineData, entry); i = setNodeId(i, mTraceLineData, entry); i = setInstanceId(i, mTraceLineData, entry); i = setThreadId(i, mTraceLineData, entry); i = setLoggerLevel(i, mTraceLineData, entry); i = setSymbolId(i, mTraceLineData, entry); i = setBusinessImpact(i, mTraceLineData, entry); i = setThreadName(i, mTraceLineData, entry); i = setCategory(i, mTraceLineData, entry); i = setTrackingNumber(i, mTraceLineData, trackingIds); i = setSource(i, mTraceLineData, entry); i = setMessage(i, mTraceLineData, entry); mBuffer.setLength(0); mTraceLineFormat.format(mTraceLineData, mBuffer, null); writer.println(mBuffer); } private void printMessageLine ( final PrintWriter writer, final LogItem entry, final List trackingIds) { int i = 0; i = setTimeStamp(i, mLogMessageData, entry); i = setNodeId(i, mLogMessageData, entry); i = setInstanceId(i, mLogMessageData, entry); i = setThreadId(i, mLogMessageData, entry); i = setLoggerLevel(i, mLogMessageData, entry); i = setSymbolId(i, mLogMessageData, entry); i = setBusinessImpact(i, mLogMessageData, entry); i = setThreadName(i, mTraceLineData, entry); i = setCategory(i, mLogMessageData, entry); i = setTrackingNumber(i, mLogMessageData, trackingIds); i = setMessage(i, mLogMessageData, entry); mBuffer.setLength(0); mLogMessageFormat.format(mLogMessageData, mBuffer, null); writer.println(mBuffer); } private void printParameterLine ( final PrintWriter writer, final LogItem entry, final List trackingIds, final String parameterName, final List parameterValues) { int i = 0; i = setThreadId(i, mParameterLineData, entry); i = setTrackingNumber(i, mParameterLineData, trackingIds); mParameterLineData[i++] = parameterName; mParameterLineData[i++] = parameterValues; mBuffer.setLength(0); mParameterLineFormat.format(mParameterLineData, mBuffer, null); writer.println(mBuffer); } private void printStackTraceLine ( final PrintWriter writer, final LogItem entry, final List trackingIds, final StackTraceInfo stacktraceLine) { int i = 0; i = setThreadId(i, mStackTraceData, entry); i = setTrackingNumber(i, mStackTraceData, trackingIds); mStackTraceData[i++] = stacktraceLine.toString(); mBuffer.setLength(0); mStackTraceFormat.format(mStackTraceData, mBuffer, null); writer.println(mBuffer); } private void printNesting ( final PrintWriter writer, final LogItem entry, final List trackingIds) { int i = 0; i = setThreadId(i, mNestedLineData, entry); i = setTrackingNumber(i, mNestedLineData, trackingIds); i = setMessage(i, mNestedLineData, entry); mBuffer.setLength(0); mNestedLineFormat.format(mNestedLineData, mBuffer, null); writer.println(mBuffer); } private void printParameters ( final PrintWriter writer, final LogItem entry, final List trackingIds) { final StringBuffer source = getPrintableSource( entry.getSourceClass(), entry.getSourceMethod()); if (source != null) { printParameterLine( writer, entry, trackingIds, SOURCE_TAG, Arrays.asList( new String[]{source.toString()})); } if (getDisplayOptions().displaySymbol()) { printParameterLine( writer, entry, trackingIds, SYMBOL_TAG, Arrays.asList( new String[]{entry.getSymbol()})); } if (getDisplayOptions().displaySolution()) { printParameterLine( writer, entry, trackingIds, SOLUTION_TAG, Arrays.asList( new String[]{entry.getSolution()})); } if (getDisplayOptions().displayParameters()) { final Set names = entry.getParameterNames(); for (final Iterator nameIter = names.iterator(); nameIter.hasNext(); ) { final String name = (String) nameIter.next(); printParameterLine(writer, entry, trackingIds, name, entry.getParameterValues(name)); } } } private void printStackTrace ( final PrintWriter writer, final LogItem entry, final List trackingIds) { for (final Iterator iter = entry.getStackTraceLines().iterator(); iter.hasNext(); ) { final StackTraceInfo info = (StackTraceInfo) iter.next(); if (! info.isMoreLine()) { printStackTraceLine(writer, entry, trackingIds, info); } else { printMoreStackTrace(writer, entry, trackingIds, info); } } } private void printMoreStackTrace ( final PrintWriter writer, final LogItem entry, final List trackingIds, final StackTraceInfo info) { final LogItem stackTraceEntry = getEntryForMoreStackTrace(entry, info); if (stackTraceEntry == null) { throw new IllegalStateException("Did not find correct stack trace to " + "display for " + entry); } else if (entry == stackTraceEntry) { printStackTraceLine(writer, entry, trackingIds, info); } else { printStackTrace(writer, stackTraceEntry, trackingIds); } } private int setTimeStamp ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displayTimestamp()) { data[rc++] = entry.getTimestamp(); } return rc; } private int setNodeId ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displayNodeId()) { data[rc++] = entry.getNodeId(); } return rc; } private int setInstanceId ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displayInstanceId()) { data[rc++] = entry.getInstanceId(); } return rc; } private int setThreadId ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displayThreadId()) { data[rc++] = String.valueOf(entry.getThreadId()); } return rc; } private int setLoggerLevel ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displayLoggerLevel()) { data[rc++] = entry.getLoggerLevel().toString(); } return rc; } private int setSymbolId ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displaySymbolId()) { data[rc++] = entry.getSymbolId(); } return rc; } private int setBusinessImpact ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displayBusinessImpact()) { data[rc++] = entry.getBusinessImpact().toString(); } return rc; } private int setCategory ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displayCategory()) { data[rc++] = entry.getCategory().toString(); } return rc; } private int setThreadName ( final int i, final Object[] data, final LogItem entry) { int rc = i; if (getDisplayOptions().displayThreadName()) { data[rc++] = entry.getThreadName(); } return rc; } private int setTrackingNumber ( final int i, final Object[] data, final List trackingNumbers) { int rc = i; if (getDisplayOptions().displayTrackingNumber()) { data[rc++] = trackingNumbers; } return rc; } private int setSource ( final int i, final Object[] data, final LogItem entry) { int rc = i; final StringBuffer source = getPrintableSource(entry.getSourceClass(), entry.getSourceMethod()); if (source != null) { data[rc++] = source.toString(); } return rc; } /** * Gets source class and method appended within one string buffer according * to the display options currently set. * * @param sourceClass The name of the source class. * @param sourceMethod The name of the source method. * * @return null if none of source class or method is to display; * StringBuffer containing the displayable parts of source class name * and source method name, else */ private StringBuffer getPrintableSource ( final String sourceClass, final String sourceMethod) { StringBuffer rc = null; final StringBuffer source = new StringBuffer(); if (getDisplayOptions().displaySourceClass()) { rc = source.append(sourceClass); } if (getDisplayOptions().displaySourceMethod()) { if (getDisplayOptions().displaySourceClass()) { rc = source.append('.'); } source.append(sourceMethod); if (sourceMethod.indexOf('(') < 0) { rc = source.append("()"); } } return rc; } private int setMessage ( final int i, final Object[] data, final LogItem entry) { int rc = i; data[rc++] = entry.getMessage(); return rc; } /** * Adds the new tracking number as new tracking id to the sequence of * tracking ids, if it is not already included as last element. * * @param trackingIds The list storing the sequence of tracking ids. * @param newId The number to add to the sequence. */ private void addTrackingNumber ( final List trackingIds, final String newId) { if (! trackingIds.isEmpty()) { if (! trackingIds.get(trackingIds.size() - 1).equals(newId)) { trackingIds.add(newId); } } else { trackingIds.add(newId); } } }