001package ch.qos.logback.classic.layout; 002 003import ch.qos.logback.classic.pattern.ThrowableProxyConverter; 004import ch.qos.logback.classic.spi.ILoggingEvent; 005import ch.qos.logback.classic.spi.IThrowableProxy; 006import ch.qos.logback.core.CoreConstants; 007import ch.qos.logback.core.LayoutBase; 008import ch.qos.logback.core.util.CachingDateFormatter; 009import org.slf4j.event.KeyValuePair; 010 011import java.util.List; 012 013/** 014 * A layout with a fixed format. The output is equivalent to that produced by 015 * {@link ch.qos.logback.classic.PatternLayout PatternLayout} with the pattern: 016 * </p> 017 * 018 * <pre> 019 * %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n 020 * </pre> 021 * 022 * <p> 023 * TTLLLayout has the advantage of faster load time whereas 024 * {@link ch.qos.logback.classic.PatternLayout PatternLayout} requires roughly 025 * 40 milliseconds to load its parser classes. Note that the second run of 026 * PatternLayout will be much much faster (approx. 10 micro-seconds). 027 * </p> 028 * 029 * <p> 030 * Fixed format layouts such as TTLLLayout should be considered as an 031 * alternative to PatternLayout only if the extra 40 milliseconds at application 032 * start-up is considered significant. 033 * </p> 034 * 035 * @author Ceki Gülcü 036 * @since 1.1.6 037 */ 038public class TTLLLayout extends LayoutBase<ILoggingEvent> { 039 040 CachingDateFormatter cachingDateFormatter = new CachingDateFormatter("HH:mm:ss.SSS"); 041 ThrowableProxyConverter tpc = new ThrowableProxyConverter(); 042 043 @Override 044 public void start() { 045 tpc.start(); 046 super.start(); 047 } 048 049 @Override 050 public String doLayout(ILoggingEvent event) { 051 if (!isStarted()) { 052 return CoreConstants.EMPTY_STRING; 053 } 054 StringBuilder sb = new StringBuilder(); 055 056 long timestamp = event.getTimeStamp(); 057 058 sb.append(cachingDateFormatter.format(timestamp)); 059 sb.append(" ["); 060 sb.append(event.getThreadName()); 061 sb.append("] "); 062 sb.append(event.getLevel().toString()); 063 sb.append(" "); 064 sb.append(event.getLoggerName()); 065 sb.append(" -"); 066 kvp(event, sb); 067 sb.append("- "); 068 sb.append(event.getFormattedMessage()); 069 sb.append(CoreConstants.LINE_SEPARATOR); 070 IThrowableProxy tp = event.getThrowableProxy(); 071 if (tp != null) { 072 String stackTrace = tpc.convert(event); 073 sb.append(stackTrace); 074 } 075 return sb.toString(); 076 } 077 078 static final char DOUBLE_QUOTE_CHAR = '"'; 079 private void kvp(ILoggingEvent event, StringBuilder sb) { 080 List<KeyValuePair> kvpList = event.getKeyValuePairs(); 081 if (kvpList == null || kvpList.isEmpty()) { 082 return; 083 } 084 085 int len = kvpList.size(); 086 087 for (int i = 0; i < len; i++) { 088 KeyValuePair kvp = kvpList.get(i); 089 if (i != 0) 090 sb.append(' '); 091 sb.append(String.valueOf(kvp.key)); 092 sb.append('='); 093 sb.append(DOUBLE_QUOTE_CHAR); 094 sb.append(String.valueOf(kvp.value)); 095 sb.append(DOUBLE_QUOTE_CHAR); 096 } 097 } 098 099}