Add support for LOG_LEVEL_PATTERN replacing the default level pattern

For logback we also support logging.pattern.level as a synonym.

Fixes gh-4062
pull/4069/head
Dave Syer 9 years ago
parent eeaa1df1dd
commit cad2666522

@ -63,6 +63,7 @@ content into your application; rather pick only the properties that you need.
logging.path=/var/log logging.path=/var/log
logging.pattern.console= # appender pattern for output to the console (only supported with the default logback setup) logging.pattern.console= # appender pattern for output to the console (only supported with the default logback setup)
logging.pattern.file= # appender pattern for output to the file (only supported with the default logback setup) logging.pattern.file= # appender pattern for output to the file (only supported with the default logback setup)
logging.pattern.level= # appender pattern for the log level (default %5p, only supported with the default logback setup)
# IDENTITY ({sc-spring-boot}/context/ContextIdApplicationContextInitializer.{sc-ext}[ContextIdApplicationContextInitializer]) # IDENTITY ({sc-spring-boot}/context/ContextIdApplicationContextInitializer.{sc-ext}[ContextIdApplicationContextInitializer])
spring.application.name= spring.application.name=

@ -1085,6 +1085,18 @@ To help with the customization some other properties are transferred from the Sp
|`LOG_PATH` |`LOG_PATH`
|Used in default log configuration if defined. |Used in default log configuration if defined.
|`logging.pattern.console`
|`CONSOLE_LOG_PATTERN`
|The log pattern to use on the console (stdout). (Not supported with JDK logger.)
|`logging.pattern.file`
|`FILE_LOG_PATTERN`
|The log pattern to use in a file (if LOG_FILE enabled). (Not supported with JDK logger.)
|`logging.pattern.level`
|`LOG_LEVEL_PATTERN`
|The format to use to render the log level (default `%5p`). (The `logging.pattern.level` form is only supported by Logback.)
|`PID` |`PID`
|`PID` |`PID`
|The current process ID (discovered if possible and when not already defined as an OS |The current process ID (discovered if possible and when not already defined as an OS
@ -1095,6 +1107,20 @@ To help with the customization some other properties are transferred from the Sp
All the logging systems supported can consult System properties when parsing their All the logging systems supported can consult System properties when parsing their
configuration files. See the default configurations in `spring-boot.jar` for examples. configuration files. See the default configurations in `spring-boot.jar` for examples.
[TIP]
====
You can add MDC and other ad-hoc content to log lines by overriding
only the `LOG_LEVEL_PATTERN` (or `logging.pattern.level` with
Logback). For example, if you use `logging.pattern.level=user:%X{user}
%5p` then the default log format will contain an MDC entry for "user"
if it exists, e.g.
----
2015-09-30 12:30:04.031 user:juergen INFO 22174 --- [ nio-8080-exec-0] demo.Controller Handling authenticated request
----
====
[[boot-features-logback-extensions]] [[boot-features-logback-extensions]]

@ -46,12 +46,12 @@ import ch.qos.logback.core.util.OptionHelper;
class DefaultLogbackConfiguration { class DefaultLogbackConfiguration {
private static final String CONSOLE_LOG_PATTERN = "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} " private static final String CONSOLE_LOG_PATTERN = "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} "
+ "%clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} " + "%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} "
+ "%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} " + "%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} "
+ "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx}"; + "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx}";
private static final String FILE_LOG_PATTERN = "%d{yyyy-MM-dd HH:mm:ss.SSS} %5p " private static final String FILE_LOG_PATTERN = "%d{yyyy-MM-dd HH:mm:ss.SSS} "
+ "${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx}"; + "${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx}";
private static final Charset UTF8 = Charset.forName("UTF-8"); private static final Charset UTF8 = Charset.forName("UTF-8");

@ -57,6 +57,7 @@ import ch.qos.logback.core.status.Status;
public class LogbackLoggingSystem extends Slf4JLoggingSystem { public class LogbackLoggingSystem extends Slf4JLoggingSystem {
private static final Map<LogLevel, Level> LEVELS; private static final Map<LogLevel, Level> LEVELS;
static { static {
Map<LogLevel, Level> levels = new HashMap<LogLevel, Level>(); Map<LogLevel, Level> levels = new HashMap<LogLevel, Level>();
levels.put(LogLevel.TRACE, Level.TRACE); levels.put(LogLevel.TRACE, Level.TRACE);
@ -85,8 +86,8 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
@Override @Override
protected String[] getStandardConfigLocations() { protected String[] getStandardConfigLocations() {
return new String[] { "logback-test.groovy", "logback-test.xml", return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy",
"logback.groovy", "logback.xml" }; "logback.xml" };
} }
@Override @Override
@ -109,6 +110,9 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
LoggerContext context = getLoggerContext(); LoggerContext context = getLoggerContext();
stopAndReset(context); stopAndReset(context);
LogbackConfigurator configurator = new LogbackConfigurator(context); LogbackConfigurator configurator = new LogbackConfigurator(context);
context.putProperty("LOG_LEVEL_PATTERN",
initializationContext.getEnvironment().resolvePlaceholders(
"${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}"));
new DefaultLogbackConfiguration(initializationContext, logFile) new DefaultLogbackConfiguration(initializationContext, logFile)
.apply(configurator); .apply(configurator);
} }
@ -127,8 +131,8 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
ResourceUtils.getURL(location)); ResourceUtils.getURL(location));
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException("Could not initialize Logback logging from " throw new IllegalStateException(
+ location, ex); "Could not initialize Logback logging from " + location, ex);
} }
List<Status> statuses = loggerContext.getStatusManager().getCopyOfStatusList(); List<Status> statuses = loggerContext.getStatusManager().getCopyOfStatusList();
StringBuilder errors = new StringBuilder(); StringBuilder errors = new StringBuilder();
@ -139,8 +143,8 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
} }
} }
if (errors.length() > 0) { if (errors.length() > 0) {
throw new IllegalStateException("Logback configuration error " throw new IllegalStateException(
+ "detected: \n" + errors); "Logback configuration error " + "detected: \n" + errors);
} }
} }
@ -197,14 +201,15 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
private ch.qos.logback.classic.Logger getLogger(String name) { private ch.qos.logback.classic.Logger getLogger(String name) {
LoggerContext factory = getLoggerContext(); LoggerContext factory = getLoggerContext();
return factory.getLogger(StringUtils.isEmpty(name) ? Logger.ROOT_LOGGER_NAME return factory
: name); .getLogger(StringUtils.isEmpty(name) ? Logger.ROOT_LOGGER_NAME : name);
} }
private LoggerContext getLoggerContext() { private LoggerContext getLoggerContext() {
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory(); ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
Assert.isInstanceOf(LoggerContext.class, factory, String.format( Assert.isInstanceOf(LoggerContext.class, factory,
String.format(
"LoggerFactory is not a Logback LoggerContext but Logback is on " "LoggerFactory is not a Logback LoggerContext but Logback is on "
+ "the classpath. Either remove Logback or the competing " + "the classpath. Either remove Logback or the competing "
+ "implementation (%s loaded from %s). If you are using " + "implementation (%s loaded from %s). If you are using "

@ -3,7 +3,8 @@ log4j.rootCategory=INFO, CONSOLE, FILE
PID=???? PID=????
LOG_PATH=${java.io.tmpdir} LOG_PATH=${java.io.tmpdir}
LOG_FILE=${LOG_PATH}/spring.log LOG_FILE=${LOG_PATH}/spring.log
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${PID} %5p [%t] --- %c{1}: %m%n LOG_LEVEL_PATTERN=%5p
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${PID} ${LOG_LEVEL_PATTERN} [%t] --- %c{1}: %m%n
# CONSOLE is set to be a ConsoleAppender using a PatternLayout. # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender

@ -1,7 +1,8 @@
log4j.rootCategory=INFO, CONSOLE log4j.rootCategory=INFO, CONSOLE
PID=???? PID=????
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${PID} %5p [%t] --- %c{1}: %m%n LOG_LEVEL_PATTERN=%5p
LOG_PATTERN=[%d{yyyy-MM-dd HH:mm:ss.SSS}] boot%X{context} - ${PID} ${LOG_LEVEL_PATTERN} [%t] --- %c{1}: %m%n
# CONSOLE is set to be a ConsoleAppender using a PatternLayout. # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender

@ -3,7 +3,8 @@
<Properties> <Properties>
<Property name="PID">????</Property> <Property name="PID">????</Property>
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%rEx</Property> <Property name="LOG_EXCEPTION_CONVERSION_WORD">%rEx</Property>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${sys:PID} --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property> <Property name="LOG_LEVEL_PATTERN">%5p</Property>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN} ${sys:PID} --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
</Properties> </Properties>
<Appenders> <Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true"> <Console name="Console" target="SYSTEM_OUT" follow="true">

@ -3,7 +3,8 @@
<Properties> <Properties>
<Property name="PID">????</Property> <Property name="PID">????</Property>
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%rEx</Property> <Property name="LOG_EXCEPTION_CONVERSION_WORD">%rEx</Property>
<Property name="LOG_PATTERN">%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property> <Property name="LOG_LEVEL_PATTERN">%5p</Property>
<Property name="LOG_PATTERN">%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
</Properties> </Properties>
<Appenders> <Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true"> <Console name="Console" target="SYSTEM_OUT" follow="true">

@ -9,8 +9,8 @@ initialization performed by Boot
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx}"/> <property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx}"/>
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx}"/> <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%rEx}"/>
<appender name="DEBUG_LEVEL_REMAPPER" class="org.springframework.boot.logging.logback.LevelRemappingAppender"> <appender name="DEBUG_LEVEL_REMAPPER" class="org.springframework.boot.logging.logback.LevelRemappingAppender">
<destinationLogger>org.springframework.boot</destinationLogger> <destinationLogger>org.springframework.boot</destinationLogger>

@ -16,6 +16,16 @@
package org.springframework.boot.logging.logback; package org.springframework.boot.logging.logback;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.util.logging.Handler; import java.util.logging.Handler;
@ -44,16 +54,6 @@ import org.springframework.util.StringUtils;
import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.LoggerContext;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/** /**
* Tests for {@link LogbackLoggingSystem}. * Tests for {@link LogbackLoggingSystem}.
* *
@ -237,6 +237,19 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
getLineWithText(output, "Hello world").contains("INFO")); getLineWithText(output, "Hello world").contains("INFO"));
} }
@Test
public void testLevelPatternProperty() {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("logging.pattern.level", "X%clr(%p)X");
LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(
environment);
this.loggingSystem.initialize(loggingInitializationContext, null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong output pattern:\n" + output,
getLineWithText(output, "Hello world").contains("XINFOX"));
}
@Test @Test
public void testFilePatternProperty() throws Exception { public void testFilePatternProperty() throws Exception {
MockEnvironment environment = new MockEnvironment(); MockEnvironment environment = new MockEnvironment();

Loading…
Cancel
Save