Support log pattern properties with logback

Update AbstractLoggingSystem to pass LoggingInitializationContext to
loadDefaults() method to enable access to the environment.
DefaultLogbackConfiguration now uses this to find log pattern overrides.

Fixes gh-3367
Closes gh-3405
This commit is contained in:
Rob Baily
2015-07-02 09:53:09 -04:00
committed by Phillip Webb
parent 1fab23c514
commit 177ea459f1
8 changed files with 96 additions and 14 deletions

View File

@@ -57,6 +57,8 @@ content into your application; rather pick only the properties that you need.
logging.file=myapp.log
logging.config= # location of config file (default classpath:logback.xml for logback)
logging.level.*= # levels for loggers, e.g. "logging.level.org.springframework=DEBUG" (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF)
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)
# IDENTITY ({sc-spring-boot}/context/ContextIdApplicationContextInitializer.{sc-ext}[ContextIdApplicationContextInitializer])
spring.application.name=

View File

@@ -71,7 +71,7 @@ public abstract class AbstractLoggingSystem extends LoggingSystem {
loadConfiguration(initializationContext, config, logFile);
return;
}
loadDefaults(logFile);
loadDefaults(initializationContext, logFile);
}
/**
@@ -129,9 +129,11 @@ public abstract class AbstractLoggingSystem extends LoggingSystem {
/**
* Load sensible defaults for the logging system.
* @param initializationContext the logging initialization context
* @param logFile the file to load or {@code null} if no log file is to be written
*/
protected abstract void loadDefaults(LogFile logFile);
protected abstract void loadDefaults(
LoggingInitializationContext initializationContext, LogFile logFile);
/**
* Load a specific configuration.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -72,7 +72,8 @@ public class JavaLoggingSystem extends AbstractLoggingSystem {
}
@Override
protected void loadDefaults(LogFile logFile) {
protected void loadDefaults(LoggingInitializationContext initializationContext,
LogFile logFile) {
if (logFile != null) {
loadConfiguration(getPackagedConfigFile("logging-file.properties"), logFile);
}

View File

@@ -70,7 +70,8 @@ public class Log4JLoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void loadDefaults(LogFile logFile) {
protected void loadDefaults(LoggingInitializationContext initializationContext,
LogFile logFile) {
if (logFile != null) {
loadConfiguration(getPackagedConfigFile("log4j-file.properties"), logFile);
}

View File

@@ -136,7 +136,8 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void loadDefaults(LogFile logFile) {
protected void loadDefaults(LoggingInitializationContext initializationContext,
LogFile logFile) {
if (logFile != null) {
loadConfiguration(getPackagedConfigFile("log4j2-file.xml"), logFile);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,12 @@ package org.springframework.boot.logging.logback;
import java.nio.charset.Charset;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
@@ -50,12 +55,23 @@ class DefaultLogbackConfiguration {
private static final Charset UTF8 = Charset.forName("UTF-8");
private final PropertyResolver patterns;
private final LogFile logFile;
public DefaultLogbackConfiguration(LogFile logFile) {
public DefaultLogbackConfiguration(
LoggingInitializationContext initializationContext, LogFile logFile) {
this.patterns = getPatternsResolver(initializationContext.getEnvironment());
this.logFile = logFile;
}
private PropertyResolver getPatternsResolver(Environment environment) {
if (environment == null) {
return new PropertySourcesPropertyResolver(null);
}
return new RelaxedPropertyResolver(environment, "logging.pattern.");
}
@SuppressWarnings("unchecked")
public void apply(LogbackConfigurator config) {
synchronized (config.getConfigurationLock()) {
@@ -99,8 +115,8 @@ class DefaultLogbackConfiguration {
private Appender<ILoggingEvent> consoleAppender(LogbackConfigurator config) {
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<ILoggingEvent>();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setPattern(OptionHelper.substVars(CONSOLE_LOG_PATTERN,
config.getContext()));
String logPattern = this.patterns.getProperty("console", CONSOLE_LOG_PATTERN);
encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext()));
encoder.setCharset(UTF8);
config.start(encoder);
appender.setEncoder(encoder);
@@ -112,7 +128,8 @@ class DefaultLogbackConfiguration {
String logFile) {
RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<ILoggingEvent>();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setPattern(OptionHelper.substVars(FILE_LOG_PATTERN, config.getContext()));
String logPattern = this.patterns.getProperty("file", FILE_LOG_PATTERN);
encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext()));
appender.setEncoder(encoder);
config.start(encoder);

View File

@@ -103,12 +103,14 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
}
@Override
protected void loadDefaults(LogFile logFile) {
protected void loadDefaults(LoggingInitializationContext initializationContext,
LogFile logFile) {
LoggerContext context = getLoggerContext();
context.stop();
context.reset();
LogbackConfigurator configurator = new LogbackConfigurator(context);
new DefaultLogbackConfiguration(logFile).apply(configurator);
new DefaultLogbackConfiguration(initializationContext, logFile)
.apply(configurator);
}
@Override
@@ -210,4 +212,5 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem {
}
return "unknown location";
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.boot.logging.logback;
import java.io.File;
import java.io.FileReader;
import java.util.logging.Handler;
import java.util.logging.LogManager;
@@ -30,10 +31,12 @@ import org.slf4j.ILoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.logging.AbstractLoggingSystemTests;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.test.OutputCapture;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import ch.qos.logback.classic.Logger;
@@ -87,6 +90,8 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
String output = this.output.toString().trim();
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertTrue("Wrong output pattern:\n" + output,
getLineWithText(output, "Hello world").contains("INFO"));
assertFalse(new File(tmpDir() + "/spring.log").exists());
}
@@ -98,9 +103,14 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
getLogFile(null, tmpDir()));
this.logger.info("Hello world");
String output = this.output.toString().trim();
File file = new File(tmpDir() + "/spring.log");
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
assertFalse("Output not hidden:\n" + output, output.contains("Hidden"));
assertTrue(new File(tmpDir() + "/spring.log").exists());
assertTrue("Wrong console output pattern:\n" + output,
getLineWithText(output, "Hello world").contains("INFO"));
assertTrue(file.exists());
assertTrue("Wrong file output pattern:\n" + output,
getLineWithText(file, "Hello world").contains("INFO"));
}
@Test
@@ -197,4 +207,49 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests {
return false;
}
@Test
public void testConsolePatternProperty() {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("logging.pattern.console", "%logger %msg");
LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(
environment);
this.loggingSystem.initialize(loggingInitializationContext, null, null);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertFalse("Wrong output pattern:\n" + output,
getLineWithText(output, "Hello world").contains("INFO"));
}
@Test
public void testFilePatternProperty() throws Exception {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("logging.pattern.file", "%logger %msg");
LoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(
environment);
File file = new File(tmpDir(), "logback-test.log");
LogFile logFile = getLogFile(file.getPath(), null);
this.loggingSystem.initialize(loggingInitializationContext, null, logFile);
this.logger.info("Hello world");
String output = this.output.toString().trim();
assertTrue("Wrong console output pattern:\n" + output,
getLineWithText(output, "Hello world").contains("INFO"));
assertFalse("Wrong file output pattern:\n" + output,
getLineWithText(file, "Hello world").contains("INFO"));
}
private String getLineWithText(File file, String outputSearch) throws Exception {
return getLineWithText(FileCopyUtils.copyToString(new FileReader(file)),
outputSearch);
}
private String getLineWithText(String output, String outputSearch) {
String[] lines = output.split("\\r?\\n");
for (String line : lines) {
if (line.contains(outputSearch)) {
return line;
}
}
return null;
}
}