package com.twitter.common.logging; import java.util.logging.Formatter; import java.util.logging.Level; import java.util.logging.LogRecord; import com.google.common.base.Throwables; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import org.apache.commons.lang.StringUtils; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; /** * Log formatter to match the format generated by glog: * * I0218 17:36:47.460234 (source) (message) * * @author William Farner */ public class LogFormatter extends Formatter { private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("MMdd HH:mm:ss.SSS").withZone(DateTimeZone.UTC); /** * Build a level 'label' by taking the first character of the level name and making uppercase. */ private static final LoadingCache<Level, String> LEVEL_LABELS = CacheBuilder.newBuilder().build( new CacheLoader<Level, String>() { public String load(Level level) { return String.valueOf(level.getName().charAt(0)).toUpperCase(); } } ); private static final int BASE_MESSAGE_LENGTH = 1 // Level char. + 4 // Month + day + 1 // space + 12 // Timestamp + 1 // space + 6 // THREAD + 4 // Room for thread ID. + 1; // space @Override public String format(final LogRecord record) { int messageLength = BASE_MESSAGE_LENGTH + 2 // Colon and space + record.getMessage().length(); if (record.getSourceClassName() != null) { messageLength += record.getSourceClassName().length(); if (record.getSourceMethodName() != null) { messageLength += 1; // Period between class and method. messageLength += record.getSourceMethodName().length(); } } StringBuilder sb = new StringBuilder(messageLength) .append(LEVEL_LABELS.getUnchecked(record.getLevel())) .append(DATE_TIME_FORMATTER.print(record.getMillis())) .append(" THREAD") .append(record.getThreadID()); if (record.getSourceClassName() != null) { sb.append(' ').append(record.getSourceClassName()); if (record.getSourceMethodName() != null) { sb.append('.').append(record.getSourceMethodName()); } } sb.append(": ").append(formatMessage(record)); if (record.getThrown() != null) { sb.append('\n').append(Throwables.getStackTraceAsString(record.getThrown())); } return sb.append('\n').toString(); } private static String zeroPad(int value, int width) { return StringUtils.leftPad(String.valueOf(value), width, '0'); } }