/**
* This file is part of the source code and related artifacts for eGym Application.
*
* Copyright © 2013 eGym GmbH
*/
package de.egym.logqueue.formatter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import de.egym.logqueue.EgymLogLevel;
import de.egym.logqueue.EgymLogRecord;
/**
* Utilities used to format log messages.
*/
public class EgymLogFormatterUtil {
private static final DateTimeFormatter FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
private static final Map<EgymLogLevel, String> logLevelLabels = createLogLevelLabels();
private EgymLogFormatterUtil() {
throw new AssertionError("Do not instantiate");
}
/**
* Formats the given {@link de.egym.logqueue.EgymLogRecord} in a nice, structured, human readable format. Uses the specified
* indentation string to indent the log message. All lines except the first one are indented by twice the indentation string.
*
* @param logRecord
* the record to format. Must not be null.
* @param indentation
* The indentation to use. Must not be null.
* @return the formatted log message.
*/
public static String formatLogRecord(final EgymLogRecord logRecord, final String indentation) {
if (logRecord == null) {
throw new IllegalArgumentException("logRecord must not be null");
}
if (indentation == null) {
throw new IllegalArgumentException("indentation must not be null");
}
final StringBuilder str = new StringBuilder();
str.append(indentation);
str.append(formatTimestamp(logRecord.getTimestamp()));
str.append(" ");
str.append(formatLogLevel(logRecord.getLogLevel()));
if (logRecord.getSource() != null) {
str.append(" ");
str.append(logRecord.getSource().getName());
}
str.append(": ");
if (logRecord.getMessage() != null) {
final String[] lines = logRecord.getMessage().split("\n");
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (i > 0) {
str.append('\n');
str.append(indentation);
str.append(indentation);
}
str.append(line);
}
}
if (logRecord.getThrowable() != null) {
final String stackTrace = ExceptionUtils.getFullStackTrace(logRecord.getThrowable());
final String[] lines = stackTrace.split("\n");
for (String line : lines) {
str.append('\n');
str.append(indentation);
str.append(indentation);
str.append(line);
}
}
return str.toString();
}
/**
* Formats the given log level.
*
* @param logLevel
* must not be null.
* @return the formatted log level.
*/
public static String formatLogLevel(EgymLogLevel logLevel) {
if (logLevel == null) {
throw new IllegalArgumentException("logLevel must not be null");
}
final String logLevelLabel = logLevelLabels.get(logLevel);
if (logLevelLabel == null) {
throw new AssertionError("Unknown logLevel: " + logLevel);
}
return logLevelLabel;
}
/**
* @return An unmodifiable map containing a label for each {@link EgymLogLevel} value. All labels have exactly the same length. Shorter
* labels are prefixed with spaces to have the same length as the longest label.
*/
private static Map<EgymLogLevel, String> createLogLevelLabels() {
final Map<EgymLogLevel, String> logLevelLabels = new HashMap<EgymLogLevel, String>();
final int maxLength = calcMaxLogLevelNameLength();
for (EgymLogLevel logLevel : EgymLogLevel.values()) {
final String label = formatLogLevelLabel(logLevel, maxLength);
logLevelLabels.put(logLevel, label);
}
return Collections.unmodifiableMap(logLevelLabels);
}
/**
* @return The length of the longest {@link EgymLogLevel} value name.
*/
private static int calcMaxLogLevelNameLength() {
int maxLength = 0;
for (EgymLogLevel logLevel : EgymLogLevel.values()) {
maxLength = Math.max(logLevel.name().length(), maxLength);
}
return maxLength;
}
/**
* Formats a {@link EgymLogLevel} value's name. Adds a prefix consisting of whitespaces if the value's name is shorter than length.
*
* @param logLevel
* the value to format. Must not be null.
* @param length
* the output length. Must not be smaller than the logLevel name's length.
* @return the formatted log level label.
*/
private static String formatLogLevelLabel(EgymLogLevel logLevel, int length) {
if (logLevel == null) {
throw new IllegalArgumentException("logLevel must not be null");
}
if (length < 0) {
throw new IllegalArgumentException("length must not be negative but is: " + length);
}
final String logLevelName = logLevel.name();
final int requiredPadding = length - logLevelName.length();
if (requiredPadding < 0) {
throw new IllegalArgumentException("logLevelName.length(" + logLevelName.length() + ") exceeds length(" + length + ")");
}
StringBuilder str = new StringBuilder();
// Add padding.
for (int i = 0; i < requiredPadding; i++) {
str.append(' ');
}
str.append(logLevelName);
return str.toString();
}
/**
* Formats the given timestamp.
*
* @param timestamp
* must not be null.
* @return the string representation of the timestamp.
*/
public static String formatTimestamp(DateTime timestamp) {
if (timestamp == null) {
throw new IllegalArgumentException("timestamp must not be null");
}
return FORMAT.print(timestamp);
}
}