From 493777d3c950ca0e9278dbededf9a48f41cffefc Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 21 Jun 2023 21:56:20 -0700 Subject: [PATCH] Include the application name on each log line when it is available Update Logback and Log4J2 so that they include the application name on each log line. If `spring.application.name` had not been set, or if `logging.include-application-name` is `false` then the name is not logged. Closes gh-35593 --- .../spring-boot-docs/build.gradle | 2 +- .../src/docs/asciidoc/features/logging.adoc | 2 ++ .../boot/logging/LoggingSystemProperties.java | 12 +++++++++++ .../boot/logging/LoggingSystemProperty.java | 5 +++++ .../logback/DefaultLogbackConfiguration.java | 4 ++-- ...itional-spring-configuration-metadata.json | 7 +++++++ .../boot/logging/log4j2/log4j2-file.xml | 4 ++-- .../boot/logging/log4j2/log4j2.xml | 4 ++-- .../boot/logging/logback/defaults.xml | 4 ++-- .../logging/LoggingSystemPropertiesTests.java | 19 +++++++++++++++++ .../log4j2/Log4J2LoggingSystemTests.java | 21 +++++++++++++++++++ .../logback/LogbackLoggingSystemTests.java | 17 +++++++++++++++ .../src/main/resources/application.properties | 1 + .../src/main/resources/log4j2.xml | 2 +- .../src/main/resources/application.properties | 1 + 15 files changed, 95 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/build.gradle b/spring-boot-project/spring-boot-docs/build.gradle index 3d0d6ddcd8a..baaf0f82328 100644 --- a/spring-boot-project/spring-boot-docs/build.gradle +++ b/spring-boot-project/spring-boot-docs/build.gradle @@ -293,7 +293,7 @@ task runSpringApplicationExample(type: org.springframework.boot.build.docs.Appli task runLoggingFormatExample(type: org.springframework.boot.build.docs.ApplicationRunner) { classpath = configurations.springApplicationExample + sourceSets.main.output mainClass = "org.springframework.boot.docs.features.springapplication.MyApplication" - args = ["--spring.main.banner-mode=off", "--server.port=0"] + args = ["--spring.main.banner-mode=off", "--server.port=0", "--spring.application.name=myapp"] output = file("$buildDir/example-output/logging-format.txt") expectedLogging = "Started MyApplication in " normalizeTomcatPort() diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/logging.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/logging.adoc index b1d81e5ef07..102998a9d8c 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/logging.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/logging.adoc @@ -31,6 +31,7 @@ The following items are output: * Log Level: `ERROR`, `WARN`, `INFO`, `DEBUG`, or `TRACE`. * Process ID. * A `---` separator to distinguish the start of actual log messages. +* Application name: Enclosed in square brackets (logged by default only if configprop:spring.application.name[] is set) * Thread name: Enclosed in square brackets (may be truncated for console output). * Correlation ID: If tracing is enabled (not shown in the sample above) * Logger name: This is usually the source class name (often abbreviated). @@ -39,6 +40,7 @@ The following items are output: NOTE: Logback does not have a `FATAL` level. It is mapped to `ERROR`. +TIP: If you have a configprop:spring.application.name[] property but don't want it logged you can set configprop:logging.include-application-name[] to `false`. [[features.logging.console-output]] diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java index 8b1b20f57f1..17b2e1a3aec 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java @@ -27,6 +27,7 @@ import org.springframework.core.env.Environment; import org.springframework.core.env.PropertyResolver; import org.springframework.core.env.PropertySourcesPropertyResolver; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * Utility to set system properties that can later be used by log configuration files. @@ -227,6 +228,7 @@ public class LoggingSystemProperties { protected void apply(LogFile logFile, PropertyResolver resolver) { String defaultCharsetName = getDefaultCharset().name(); + setApplicationNameSystemProperty(resolver); setSystemProperty(LoggingSystemProperty.PID, new ApplicationPid().toString()); setSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET, resolver, defaultCharsetName); setSystemProperty(LoggingSystemProperty.FILE_CHARSET, resolver, defaultCharsetName); @@ -243,6 +245,16 @@ public class LoggingSystemProperties { } } + private void setApplicationNameSystemProperty(PropertyResolver resolver) { + if (resolver.getProperty("logging.include-application-name", Boolean.class, Boolean.TRUE)) { + String applicationName = resolver.getProperty("spring.application.name"); + if (StringUtils.hasText(applicationName)) { + setSystemProperty(LoggingSystemProperty.APPLICATION_NAME.getEnvironmentVariableName(), + "[%s] ".formatted(applicationName)); + } + } + } + private void setSystemProperty(LoggingSystemProperty property, PropertyResolver resolver) { setSystemProperty(property, resolver, null); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperty.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperty.java index b835feeb547..489ebec89fe 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperty.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperty.java @@ -25,6 +25,11 @@ package org.springframework.boot.logging; */ public enum LoggingSystemProperty { + /** + * Logging system property for the application name that should be logged. + */ + APPLICATION_NAME("LOGGED_APPLICATION_NAME"), + /** * Logging system property for the process ID. */ diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java index c86cd372e5f..0298aa6325f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java @@ -75,7 +75,7 @@ class DefaultLogbackConfiguration { config.getContext() .putProperty("CONSOLE_LOG_PATTERN", resolve(config, "${CONSOLE_LOG_PATTERN:-" + "%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) " - + "%clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} " + + "%clr(${PID:- }){magenta} %clr(---){faint} %clr(${LOGGED_APPLICATION_NAME:-}[%15.15t]){faint} " + "%clr(${LOG_CORRELATION_PATTERN:-}){faint}%clr(%-40.40logger{39}){cyan} " + "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}")); String defaultCharset = Charset.defaultCharset().name(); @@ -84,7 +84,7 @@ class DefaultLogbackConfiguration { config.getContext().putProperty("CONSOLE_LOG_THRESHOLD", resolve(config, "${CONSOLE_LOG_THRESHOLD:-TRACE}")); config.getContext() .putProperty("FILE_LOG_PATTERN", resolve(config, "${FILE_LOG_PATTERN:-" - + "%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] " + + "%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- ${LOGGED_APPLICATION_NAME:-}[%t] " + "${LOG_CORRELATION_PATTERN:-}" + "%-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}")); config.getContext() diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 17c21808424..a22819a934c 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -103,6 +103,13 @@ "description": "Log groups to quickly change multiple loggers at the same time. For instance, `logging.group.db=org.hibernate,org.springframework.jdbc`.", "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener" }, + { + "name": "logging.include-application-name", + "type": "java.lang.String>", + "description": "Whether to include the application name in the logs.", + "sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener", + "defaultValue": true + }, { "name": "logging.level", "type": "java.util.Map", diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml index ee6812d92a6..fb3edde9dfe 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml @@ -4,8 +4,8 @@ %xwEx %5p yyyy-MM-dd'T'HH:mm:ss.SSSXXX - %clr{%d{${sys:LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${sys:LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{${sys:LOG_CORRELATION_PATTERN:-}}{faint}%clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} - %d{${sys:LOG_DATEFORMAT_PATTERN}} ${sys:LOG_LEVEL_PATTERN} %pid --- [%t] ${sys:LOG_CORRELATION_PATTERN:-}%-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} + %clr{%d{${sys:LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${sys:LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{${sys:LOGGED_APPLICATION_NAME:-}[%15.15t]}{faint} %clr{${sys:LOG_CORRELATION_PATTERN:-}}{faint}%clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} + %d{${sys:LOG_DATEFORMAT_PATTERN}} ${sys:LOG_LEVEL_PATTERN} %pid --- ${sys:LOGGED_APPLICATION_NAME}[%t] ${sys:LOG_CORRELATION_PATTERN:-}%-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml index de8588498e1..600f2fa207e 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml @@ -4,8 +4,8 @@ %xwEx %5p yyyy-MM-dd'T'HH:mm:ss.SSSXXX - %clr{%d{${sys:LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${sys:LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{${sys:LOG_CORRELATION_PATTERN:-}}{faint}%clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} - %d{${sys:LOG_DATEFORMAT_PATTERN}} ${sys:LOG_LEVEL_PATTERN} %pid --- [%t] ${sys:LOG_CORRELATION_PATTERN:-}%-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} + %clr{%d{${sys:LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${sys:LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{${sys:LOGGED_APPLICATION_NAME}[%15.15t]}{faint} %clr{${sys:LOG_CORRELATION_PATTERN:-}}{faint}%clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} + %d{${sys:LOG_DATEFORMAT_PATTERN}} ${sys:LOG_LEVEL_PATTERN} %pid --- ${sys:LOGGED_APPLICATION_NAME}[%t] ${sys:LOG_CORRELATION_PATTERN:-}%-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} diff --git a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml index d10022ca070..9c02f84e409 100644 --- a/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml +++ b/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml @@ -10,10 +10,10 @@ Default logback configuration provided for import - + - + diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java index 0f5a3a44ceb..2c5a1aaf285 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java @@ -136,6 +136,25 @@ class LoggingSystemPropertiesTests { .isEqualTo("default correlation pattern"); } + @Test + void loggedApplicationNameWhenHasApplicationName() { + new LoggingSystemProperties(new MockEnvironment().withProperty("spring.application.name", "test")).apply(null); + assertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_NAME)).isEqualTo("[test] "); + } + + @Test + void loggedApplicationNameWhenHasNoApplicationName() { + new LoggingSystemProperties(new MockEnvironment()).apply(null); + assertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_NAME)).isNull(); + } + + @Test + void loggedApplicationNameWhenApplicationNameLoggingDisabled() { + new LoggingSystemProperties(new MockEnvironment().withProperty("spring.application.name", "test") + .withProperty("logging.include-application-name", "false")).apply(null); + assertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_NAME)).isNull(); + } + private Environment environment(String key, Object value) { StandardEnvironment environment = new StandardEnvironment(); environment.getPropertySources().addLast(new MapPropertySource("test", Collections.singletonMap(key, value))); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java index ceb5b64650a..fdd2add6889 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java @@ -564,6 +564,27 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { .contains(" [0123456789012345-01234567890123456789012345678901] "); } + @Test + void applicationNameLoggingWhenHasApplicationName(CapturedOutput output) { + this.environment.setProperty("spring.application.name", "myapp"); + this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.beforeInitialize(); + this.loggingSystem.initialize(this.initializationContext, null, null); + this.logger.info("Hello world"); + assertThat(getLineWithText(output, "Hello world")).contains("[myapp] "); + } + + @Test + void applicationNameLoggingWhenDisabled(CapturedOutput output) { + this.environment.setProperty("spring.application.name", "myapp"); + this.environment.setProperty("logging.include-application-name", "false"); + this.loggingSystem.setStandardConfigLocations(false); + this.loggingSystem.beforeInitialize(); + this.loggingSystem.initialize(this.initializationContext, null, null); + this.logger.info("Hello world"); + assertThat(getLineWithText(output, "Hello world")).doesNotContain("myapp"); + } + private String getRelativeClasspathLocation(String fileName) { String defaultPath = ClassUtils.getPackageName(getClass()); defaultPath = defaultPath.replace('.', '/'); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java index 8673dbd701c..685923ead60 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java @@ -754,6 +754,23 @@ class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { .contains(" [01234567890123456789012345678901-0123456789012345] "); } + @Test + void applicationNameLoggingWhenHasApplicationName(CapturedOutput output) { + this.environment.setProperty("spring.application.name", "myapp"); + initialize(this.initializationContext, null, null); + this.logger.info("Hello world"); + assertThat(getLineWithText(output, "Hello world")).contains("[myapp] "); + } + + @Test + void applicationNameLoggingWhenDisabled(CapturedOutput output) { + this.environment.setProperty("spring.application.name", "myapp"); + this.environment.setProperty("logging.include-application-name", "false"); + initialize(this.initializationContext, null, null); + this.logger.info("Hello world"); + assertThat(getLineWithText(output, "Hello world")).doesNotContain("myapp"); + } + private void initialize(LoggingInitializationContext context, String configLocation, LogFile logFile) { this.loggingSystem.getSystemProperties((ConfigurableEnvironment) context.getEnvironment()).apply(logFile); this.loggingSystem.beforeInitialize(); diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/application.properties b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/application.properties index 2583f7fcefd..d622bb1f7ca 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/application.properties +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/application.properties @@ -1,3 +1,4 @@ +spring.application.name=sample spring.security.user.name=user spring.security.user.password=password management.endpoint.shutdown.enabled=true diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml index 5320cd61c74..1c84d286b09 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml @@ -2,7 +2,7 @@ ???? - %clr{%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%xwEx + %clr{%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{${sys:LOGGED_APPLICATION_NAME:-}[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%xwEx diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator/src/main/resources/application.properties b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator/src/main/resources/application.properties index 81cc777bfc8..2c35d22ff03 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator/src/main/resources/application.properties +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator/src/main/resources/application.properties @@ -1,3 +1,4 @@ +spring.application.name=sample service.name=Phil spring.security.user.name=user