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