Make PID and application version available in the environment
Adds the following new properties: - spring.application.pid - spring.application.version Refactors the ResourceBanner and the structured logging support to use the new properties. Closes gh-41604
This commit is contained in:
@@ -160,11 +160,11 @@ class SpringBootContextLoaderTests {
|
||||
.stream()
|
||||
.map(PropertySource::getName)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
String last = names.remove(names.size() - 1);
|
||||
String configResource = names.remove(names.size() - 2);
|
||||
assertThat(names).containsExactly("configurationProperties", "Inlined Test Properties", "commandLineArgs",
|
||||
"servletConfigInitParams", "servletContextInitParams", "systemProperties", "systemEnvironment",
|
||||
"random");
|
||||
assertThat(last).startsWith("Config resource");
|
||||
"random", "applicationInfo");
|
||||
assertThat(configResource).startsWith("Config resource");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link PropertySource} which provides information about the application, like the
|
||||
* process ID (PID) or the version.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class ApplicationInfoPropertySource extends MapPropertySource {
|
||||
|
||||
static final String NAME = "applicationInfo";
|
||||
|
||||
ApplicationInfoPropertySource(Class<?> mainClass) {
|
||||
super(NAME, getProperties(readVersion(mainClass)));
|
||||
}
|
||||
|
||||
ApplicationInfoPropertySource(String applicationVersion) {
|
||||
super(NAME, getProperties(applicationVersion));
|
||||
}
|
||||
|
||||
private static Map<String, Object> getProperties(String applicationVersion) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if (StringUtils.hasText(applicationVersion)) {
|
||||
result.put("spring.application.version", applicationVersion);
|
||||
}
|
||||
ApplicationPid applicationPid = new ApplicationPid();
|
||||
if (applicationPid.isAvailable()) {
|
||||
result.put("spring.application.pid", applicationPid.toLong());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String readVersion(Class<?> applicationClass) {
|
||||
Package sourcePackage = (applicationClass != null) ? applicationClass.getPackage() : null;
|
||||
return (sourcePackage != null) ? sourcePackage.getImplementationVersion() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the {@link ApplicationInfoPropertySource} to the end of the environment's
|
||||
* property sources.
|
||||
* @param environment the environment
|
||||
*/
|
||||
static void moveToEnd(ConfigurableEnvironment environment) {
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
PropertySource<?> propertySource = propertySources.remove(NAME);
|
||||
if (propertySource != null) {
|
||||
propertySources.addLast(propertySource);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,6 +47,7 @@ import org.springframework.util.StreamUtils;
|
||||
* @author Vedran Pavic
|
||||
* @author Toshiaki Maki
|
||||
* @author Krzysztof Krason
|
||||
* @author Moritz Halbritter
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class ResourceBanner implements Banner {
|
||||
@@ -91,7 +92,7 @@ public class ResourceBanner implements Banner {
|
||||
}
|
||||
sources.addLast(getTitleSource(sourceClass));
|
||||
sources.addLast(getAnsiSource());
|
||||
sources.addLast(getVersionSource(sourceClass));
|
||||
sources.addLast(getVersionSource(sourceClass, environment));
|
||||
List<PropertyResolver> resolvers = new ArrayList<>();
|
||||
resolvers.add(new PropertySourcesPropertyResolver(sources));
|
||||
return resolvers;
|
||||
@@ -119,12 +120,15 @@ public class ResourceBanner implements Banner {
|
||||
return new AnsiPropertySource("ansi", true);
|
||||
}
|
||||
|
||||
private MapPropertySource getVersionSource(Class<?> sourceClass) {
|
||||
return new MapPropertySource("version", getVersionsMap(sourceClass));
|
||||
private MapPropertySource getVersionSource(Class<?> sourceClass, Environment environment) {
|
||||
return new MapPropertySource("version", getVersionsMap(sourceClass, environment));
|
||||
}
|
||||
|
||||
private Map<String, Object> getVersionsMap(Class<?> sourceClass) {
|
||||
private Map<String, Object> getVersionsMap(Class<?> sourceClass, Environment environment) {
|
||||
String appVersion = getApplicationVersion(sourceClass);
|
||||
if (appVersion == null) {
|
||||
appVersion = getApplicationVersion(environment);
|
||||
}
|
||||
String bootVersion = getBootVersion();
|
||||
Map<String, Object> versions = new HashMap<>();
|
||||
versions.put("application.version", getVersionString(appVersion, false));
|
||||
@@ -134,9 +138,19 @@ public class ResourceBanner implements Banner {
|
||||
return versions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the application version.
|
||||
* @param sourceClass the source class
|
||||
* @return the application version or {@code null} if unknown
|
||||
* @deprecated since 3.4.0 for removal in 3.6.0
|
||||
*/
|
||||
@Deprecated(since = "3.4.0", forRemoval = true)
|
||||
protected String getApplicationVersion(Class<?> sourceClass) {
|
||||
Package sourcePackage = (sourceClass != null) ? sourceClass.getPackage() : null;
|
||||
return (sourcePackage != null) ? sourcePackage.getImplementationVersion() : null;
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getApplicationVersion(Environment environment) {
|
||||
return environment.getProperty("spring.application.version");
|
||||
}
|
||||
|
||||
protected String getBootVersion() {
|
||||
|
||||
@@ -368,6 +368,7 @@ public class SpringApplication {
|
||||
configureEnvironment(environment, applicationArguments.getSourceArgs());
|
||||
ConfigurationPropertySources.attach(environment);
|
||||
listeners.environmentPrepared(bootstrapContext, environment);
|
||||
ApplicationInfoPropertySource.moveToEnd(environment);
|
||||
DefaultPropertiesPropertySource.moveToEnd(environment);
|
||||
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
|
||||
"Environment prefix cannot be set via properties.");
|
||||
@@ -539,6 +540,7 @@ public class SpringApplication {
|
||||
sources.addFirst(new SimpleCommandLinePropertySource(args));
|
||||
}
|
||||
}
|
||||
environment.getPropertySources().addLast(new ApplicationInfoPropertySource(this.mainApplicationClass));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.logging.log4j2;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.impl.ThrowableProxy;
|
||||
@@ -28,7 +30,7 @@ import org.springframework.boot.logging.structured.CommonStructuredLogFormat;
|
||||
import org.springframework.boot.logging.structured.ElasticCommonSchemaService;
|
||||
import org.springframework.boot.logging.structured.JsonWriterStructuredLogFormatter;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatter;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -40,17 +42,17 @@ import org.springframework.util.ObjectUtils;
|
||||
*/
|
||||
class ElasticCommonSchemaStructuredLogFormatter extends JsonWriterStructuredLogFormatter<LogEvent> {
|
||||
|
||||
ElasticCommonSchemaStructuredLogFormatter(ApplicationPid pid, ElasticCommonSchemaService service) {
|
||||
super((members) -> jsonMembers(pid, service, members));
|
||||
ElasticCommonSchemaStructuredLogFormatter(Environment environment) {
|
||||
super((members) -> jsonMembers(environment, members));
|
||||
}
|
||||
|
||||
private static void jsonMembers(ApplicationPid pid, ElasticCommonSchemaService service,
|
||||
JsonWriter.Members<LogEvent> members) {
|
||||
private static void jsonMembers(Environment environment, JsonWriter.Members<LogEvent> members) {
|
||||
members.add("@timestamp", LogEvent::getInstant).as(ElasticCommonSchemaStructuredLogFormatter::asTimestamp);
|
||||
members.add("log.level", LogEvent::getLevel).as(Level::name);
|
||||
members.add("process.pid", pid).when(ApplicationPid::isAvailable).as(ApplicationPid::toLong);
|
||||
members.add("process.pid", environment.getProperty("spring.application.pid", Long.class))
|
||||
.when(Objects::nonNull);
|
||||
members.add("process.thread.name", LogEvent::getThreadName);
|
||||
service.jsonMembers(members);
|
||||
ElasticCommonSchemaService.get(environment).jsonMembers(members);
|
||||
members.add("log.logger", LogEvent::getLoggerName);
|
||||
members.add("message", LogEvent::getMessage).as(Message::getFormattedMessage);
|
||||
members.from(LogEvent::getContextData)
|
||||
|
||||
@@ -30,11 +30,9 @@ import org.apache.logging.log4j.core.config.plugins.PluginLoggerContext;
|
||||
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
|
||||
|
||||
import org.springframework.boot.logging.structured.CommonStructuredLogFormat;
|
||||
import org.springframework.boot.logging.structured.ElasticCommonSchemaService;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatter;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatterFactory;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatterFactory.CommonFormatters;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -106,8 +104,7 @@ final class StructuredLogLayout extends AbstractStringLayout {
|
||||
private void addCommonFormatters(CommonFormatters<LogEvent> commonFormatters) {
|
||||
commonFormatters.add(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA,
|
||||
(instantiator) -> new ElasticCommonSchemaStructuredLogFormatter(
|
||||
instantiator.getArg(ApplicationPid.class),
|
||||
instantiator.getArg(ElasticCommonSchemaService.class)));
|
||||
instantiator.getArg(Environment.class)));
|
||||
commonFormatters.add(CommonStructuredLogFormat.LOGSTASH,
|
||||
(instantiator) -> new LogstashStructuredLogFormatter());
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.logging.logback;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.classic.spi.IThrowableProxy;
|
||||
@@ -27,7 +29,7 @@ import org.springframework.boot.logging.structured.CommonStructuredLogFormat;
|
||||
import org.springframework.boot.logging.structured.ElasticCommonSchemaService;
|
||||
import org.springframework.boot.logging.structured.JsonWriterStructuredLogFormatter;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatter;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Logback {@link StructuredLogFormatter} for
|
||||
@@ -41,18 +43,19 @@ class ElasticCommonSchemaStructuredLogFormatter extends JsonWriterStructuredLogF
|
||||
private static final PairExtractor<KeyValuePair> keyValuePairExtractor = PairExtractor.of((pair) -> pair.key,
|
||||
(pair) -> pair.value);
|
||||
|
||||
ElasticCommonSchemaStructuredLogFormatter(ApplicationPid pid, ElasticCommonSchemaService service,
|
||||
ElasticCommonSchemaStructuredLogFormatter(Environment environment,
|
||||
ThrowableProxyConverter throwableProxyConverter) {
|
||||
super((members) -> jsonMembers(pid, service, throwableProxyConverter, members));
|
||||
super((members) -> jsonMembers(environment, throwableProxyConverter, members));
|
||||
}
|
||||
|
||||
private static void jsonMembers(ApplicationPid pid, ElasticCommonSchemaService service,
|
||||
ThrowableProxyConverter throwableProxyConverter, JsonWriter.Members<ILoggingEvent> members) {
|
||||
private static void jsonMembers(Environment environment, ThrowableProxyConverter throwableProxyConverter,
|
||||
JsonWriter.Members<ILoggingEvent> members) {
|
||||
members.add("@timestamp", ILoggingEvent::getInstant);
|
||||
members.add("log.level", ILoggingEvent::getLevel);
|
||||
members.add("process.pid", pid).when(ApplicationPid::isAvailable).as(ApplicationPid::toLong);
|
||||
members.add("process.pid", environment.getProperty("spring.application.pid", Long.class))
|
||||
.when(Objects::nonNull);
|
||||
members.add("process.thread.name", ILoggingEvent::getThreadName);
|
||||
service.jsonMembers(members);
|
||||
ElasticCommonSchemaService.get(environment).jsonMembers(members);
|
||||
members.add("log.logger", ILoggingEvent::getLoggerName);
|
||||
members.add("message", ILoggingEvent::getFormattedMessage);
|
||||
members.addMapEntries(ILoggingEvent::getMDCPropertyMap);
|
||||
|
||||
@@ -25,11 +25,9 @@ import ch.qos.logback.core.encoder.Encoder;
|
||||
import ch.qos.logback.core.encoder.EncoderBase;
|
||||
|
||||
import org.springframework.boot.logging.structured.CommonStructuredLogFormat;
|
||||
import org.springframework.boot.logging.structured.ElasticCommonSchemaService;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatter;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatterFactory;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatterFactory.CommonFormatters;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.boot.util.Instantiator.AvailableParameters;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -82,9 +80,7 @@ public class StructuredLogEncoder extends EncoderBase<ILoggingEvent> {
|
||||
|
||||
private void addCommonFormatters(CommonFormatters<ILoggingEvent> commonFormatters) {
|
||||
commonFormatters.add(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA,
|
||||
(instantiator) -> new ElasticCommonSchemaStructuredLogFormatter(
|
||||
instantiator.getArg(ApplicationPid.class),
|
||||
instantiator.getArg(ElasticCommonSchemaService.class),
|
||||
(instantiator) -> new ElasticCommonSchemaStructuredLogFormatter(instantiator.getArg(Environment.class),
|
||||
instantiator.getArg(ThrowableProxyConverter.class)));
|
||||
commonFormatters.add(CommonStructuredLogFormat.LOGSTASH, (instantiator) -> new LogstashStructuredLogFormatter(
|
||||
instantiator.getArg(ThrowableProxyConverter.class)));
|
||||
|
||||
@@ -38,7 +38,8 @@ public record ElasticCommonSchemaService(String name, String version, String env
|
||||
|
||||
private ElasticCommonSchemaService withDefaults(Environment environment) {
|
||||
String name = withFallbackProperty(environment, this.name, "spring.application.name");
|
||||
return new ElasticCommonSchemaService(name, this.version, this.environment, this.nodeName);
|
||||
String version = withFallbackProperty(environment, this.version, "spring.application.version");
|
||||
return new ElasticCommonSchemaService(name, version, this.environment, this.nodeName);
|
||||
}
|
||||
|
||||
private String withFallbackProperty(Environment environment, String value, String property) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.nio.charset.Charset;
|
||||
|
||||
import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
|
||||
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
@@ -29,8 +28,6 @@ import org.springframework.core.env.Environment;
|
||||
* Implementing classes can declare the following parameter types in the constructor:
|
||||
* <ul>
|
||||
* <li>{@link Environment}</li>
|
||||
* <li>{@link ApplicationPid}</li>
|
||||
* <li>{@link ElasticCommonSchemaService}</li>
|
||||
* </ul>
|
||||
* When using Logback, implementing classes can also use the following parameter types in
|
||||
* the constructor:
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.boot.util.Instantiator;
|
||||
import org.springframework.boot.util.Instantiator.AvailableParameters;
|
||||
import org.springframework.boot.util.Instantiator.FailureHandler;
|
||||
@@ -68,9 +67,6 @@ public class StructuredLogFormatterFactory<E> {
|
||||
this.logEventType = logEventType;
|
||||
this.instantiator = new Instantiator<>(StructuredLogFormatter.class, (allAvailableParameters) -> {
|
||||
allAvailableParameters.add(Environment.class, environment);
|
||||
allAvailableParameters.add(ApplicationPid.class, (type) -> new ApplicationPid());
|
||||
allAvailableParameters.add(ElasticCommonSchemaService.class,
|
||||
(type) -> ElasticCommonSchemaService.get(environment));
|
||||
if (availableParameters != null) {
|
||||
availableParameters.accept(allAvailableParameters);
|
||||
}
|
||||
|
||||
@@ -285,6 +285,11 @@
|
||||
"sourceType": "org.springframework.boot.context.ContextIdApplicationContextInitializer",
|
||||
"description": "Application name."
|
||||
},
|
||||
{
|
||||
"name": "spring.application.version",
|
||||
"type": "java.lang.String",
|
||||
"description": "Application version (defaults to 'Implementation-Version' from the manifest)."
|
||||
},
|
||||
{
|
||||
"name": "spring.banner.charset",
|
||||
"type": "java.nio.charset.Charset",
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2012-2024 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ApplicationInfoPropertySource}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class ApplicationInfoPropertySourceTests {
|
||||
|
||||
@Test
|
||||
void shouldAddVersion() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.getPropertySources().addLast(new ApplicationInfoPropertySource("1.2.3"));
|
||||
assertThat(environment.getProperty("spring.application.version")).isEqualTo("1.2.3");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotAddVersionIfVersionIsNotAvailable() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.getPropertySources().addLast(new ApplicationInfoPropertySource((String) null));
|
||||
assertThat(environment.containsProperty("spring.application.version")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddPid() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.getPropertySources().addLast(new ApplicationInfoPropertySource("1.2.3"));
|
||||
assertThat(environment.getProperty("spring.application.pid", Long.class))
|
||||
.isEqualTo(new ApplicationPid().toLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMoveToEnd() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.getPropertySources().addFirst(new MapPropertySource("first", Collections.emptyMap()));
|
||||
environment.getPropertySources().addAfter("first", new MapPropertySource("second", Collections.emptyMap()));
|
||||
environment.getPropertySources().addFirst(new ApplicationInfoPropertySource("1.2.3"));
|
||||
List<String> propertySources = environment.getPropertySources().stream().map(PropertySource::getName).toList();
|
||||
assertThat(propertySources).containsExactly("applicationInfo", "first", "second", "mockProperties");
|
||||
ApplicationInfoPropertySource.moveToEnd(environment);
|
||||
List<String> propertySourcesAfterMove = environment.getPropertySources()
|
||||
.stream()
|
||||
.map(PropertySource::getName)
|
||||
.toList();
|
||||
assertThat(propertySourcesAfterMove).containsExactly("first", "second", "mockProperties", "applicationInfo");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
@@ -28,7 +28,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.ansi.AnsiOutput;
|
||||
import org.springframework.boot.ansi.AnsiOutput.Enabled;
|
||||
import org.springframework.core.env.AbstractPropertyResolver;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.PropertyResolver;
|
||||
@@ -143,18 +142,20 @@ class ResourceBannerTests {
|
||||
@Test
|
||||
void renderWithMutation() {
|
||||
Resource resource = new ByteArrayResource("banner ${foo}".getBytes());
|
||||
String banner = printBanner(new MutatingResourceBanner(resource, "1", "2", null));
|
||||
String banner = printBanner(new MutatingResourceBanner(resource, "1", null), "2");
|
||||
assertThat(banner).startsWith("banner bar");
|
||||
|
||||
}
|
||||
|
||||
private String printBanner(Resource resource, String bootVersion, String applicationVersion,
|
||||
String applicationTitle) {
|
||||
return printBanner(new MockResourceBanner(resource, bootVersion, applicationVersion, applicationTitle));
|
||||
return printBanner(new MockResourceBanner(resource, bootVersion, applicationTitle), applicationVersion);
|
||||
}
|
||||
|
||||
private String printBanner(ResourceBanner banner) {
|
||||
ConfigurableEnvironment environment = new MockEnvironment();
|
||||
private String printBanner(ResourceBanner banner, String applicationVersion) {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
if (applicationVersion != null) {
|
||||
environment.setProperty("spring.application.version", applicationVersion);
|
||||
}
|
||||
Map<String, Object> source = Collections.singletonMap("a", "1");
|
||||
environment.getPropertySources().addLast(new MapPropertySource("map", source));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
@@ -166,14 +167,11 @@ class ResourceBannerTests {
|
||||
|
||||
private final String bootVersion;
|
||||
|
||||
private final String applicationVersion;
|
||||
|
||||
private final String applicationTitle;
|
||||
|
||||
MockResourceBanner(Resource resource, String bootVersion, String applicationVersion, String applicationTitle) {
|
||||
MockResourceBanner(Resource resource, String bootVersion, String applicationTitle) {
|
||||
super(resource);
|
||||
this.bootVersion = bootVersion;
|
||||
this.applicationVersion = applicationVersion;
|
||||
this.applicationTitle = applicationTitle;
|
||||
}
|
||||
|
||||
@@ -182,11 +180,6 @@ class ResourceBannerTests {
|
||||
return this.bootVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getApplicationVersion(Class<?> sourceClass) {
|
||||
return this.applicationVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getApplicationTitle(Class<?> sourceClass) {
|
||||
return this.applicationTitle;
|
||||
@@ -196,9 +189,8 @@ class ResourceBannerTests {
|
||||
|
||||
static class MutatingResourceBanner extends MockResourceBanner {
|
||||
|
||||
MutatingResourceBanner(Resource resource, String bootVersion, String applicationVersion,
|
||||
String applicationTitle) {
|
||||
super(resource, bootVersion, applicationVersion, applicationTitle);
|
||||
MutatingResourceBanner(Resource resource, String bootVersion, String applicationTitle) {
|
||||
super(resource, bootVersion, applicationTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,9 +23,7 @@ import org.apache.logging.log4j.core.impl.MutableLogEvent;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.logging.structured.ElasticCommonSchemaService;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.boot.system.MockApplicationPid;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -40,9 +38,13 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
ApplicationPid pid = MockApplicationPid.of(1L);
|
||||
ElasticCommonSchemaService service = new ElasticCommonSchemaService("name", "1.0.0", "test", "node-1");
|
||||
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(pid, service);
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("logging.structured.ecs.service.name", "name");
|
||||
environment.setProperty("logging.structured.ecs.service.version", "1.0.0");
|
||||
environment.setProperty("logging.structured.ecs.service.environment", "test");
|
||||
environment.setProperty("logging.structured.ecs.service.node-name", "node-1");
|
||||
environment.setProperty("spring.application.pid", "1");
|
||||
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(environment);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.logging.log4j2.StructuredLogLayout.Builder;
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatter;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
@@ -83,11 +83,12 @@ class StructuredLoggingLayoutTests extends AbstractStructuredLoggingTests {
|
||||
|
||||
@Test
|
||||
void shouldInjectCustomFormatConstructorParameters() {
|
||||
this.environment.setProperty("spring.application.pid", "42");
|
||||
StructuredLogLayout layout = newBuilder()
|
||||
.setFormat(CustomLog4j2StructuredLoggingFormatterWithInjection.class.getName())
|
||||
.build();
|
||||
String format = layout.toSerializable(createEvent());
|
||||
assertThat(format).isEqualTo("custom-format-with-injection pid=" + new ApplicationPid());
|
||||
assertThat(format).isEqualTo("custom-format-with-injection pid=42");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -129,15 +130,15 @@ class StructuredLoggingLayoutTests extends AbstractStructuredLoggingTests {
|
||||
|
||||
static final class CustomLog4j2StructuredLoggingFormatterWithInjection implements StructuredLogFormatter<LogEvent> {
|
||||
|
||||
private final ApplicationPid pid;
|
||||
private final Environment environment;
|
||||
|
||||
CustomLog4j2StructuredLoggingFormatterWithInjection(ApplicationPid pid) {
|
||||
this.pid = pid;
|
||||
CustomLog4j2StructuredLoggingFormatterWithInjection(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(LogEvent event) {
|
||||
return "custom-format-with-injection pid=" + this.pid;
|
||||
return "custom-format-with-injection pid=" + this.environment.getProperty("spring.application.pid");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,9 +24,7 @@ import ch.qos.logback.classic.spi.ThrowableProxy;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.logging.structured.ElasticCommonSchemaService;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.boot.system.MockApplicationPid;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -43,9 +41,13 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
super.setUp();
|
||||
ApplicationPid pid = MockApplicationPid.of(1L);
|
||||
ElasticCommonSchemaService service = new ElasticCommonSchemaService("name", "1.0.0", "test", "node-1");
|
||||
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(pid, service, getThrowableProxyConverter());
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("logging.structured.ecs.service.name", "name");
|
||||
environment.setProperty("logging.structured.ecs.service.version", "1.0.0");
|
||||
environment.setProperty("logging.structured.ecs.service.environment", "test");
|
||||
environment.setProperty("logging.structured.ecs.service.node-name", "node-1");
|
||||
environment.setProperty("spring.application.pid", "1");
|
||||
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(environment, getThrowableProxyConverter());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatter;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
@@ -103,13 +102,13 @@ class StructuredLoggingEncoderTests extends AbstractStructuredLoggingTests {
|
||||
|
||||
@Test
|
||||
void shouldInjectCustomFormatConstructorParameters() {
|
||||
this.environment.setProperty("spring.application.pid", "42");
|
||||
this.encoder.setFormat(CustomLogbackStructuredLoggingFormatterWithInjection.class.getName());
|
||||
this.encoder.start();
|
||||
LoggingEvent event = createEvent();
|
||||
event.setMDCPropertyMap(Collections.emptyMap());
|
||||
String format = encode(event);
|
||||
assertThat(format)
|
||||
.isEqualTo("custom-format-with-injection pid=" + new ApplicationPid() + " hasThrowableProxyConverter=true");
|
||||
assertThat(format).isEqualTo("custom-format-with-injection pid=42 hasThrowableProxyConverter=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -154,21 +153,21 @@ class StructuredLoggingEncoderTests extends AbstractStructuredLoggingTests {
|
||||
static final class CustomLogbackStructuredLoggingFormatterWithInjection
|
||||
implements StructuredLogFormatter<ILoggingEvent> {
|
||||
|
||||
private final ApplicationPid pid;
|
||||
private final Environment environment;
|
||||
|
||||
private final ThrowableProxyConverter throwableProxyConverter;
|
||||
|
||||
CustomLogbackStructuredLoggingFormatterWithInjection(ApplicationPid pid,
|
||||
CustomLogbackStructuredLoggingFormatterWithInjection(Environment environment,
|
||||
ThrowableProxyConverter throwableProxyConverter) {
|
||||
this.pid = pid;
|
||||
this.environment = environment;
|
||||
this.throwableProxyConverter = throwableProxyConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(ILoggingEvent event) {
|
||||
boolean hasThrowableProxyConverter = this.throwableProxyConverter != null;
|
||||
return "custom-format-with-injection pid=" + this.pid + " hasThrowableProxyConverter="
|
||||
+ hasThrowableProxyConverter;
|
||||
return "custom-format-with-injection pid=" + this.environment.getProperty("spring.application.pid")
|
||||
+ " hasThrowableProxyConverter=" + hasThrowableProxyConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Tests for {@link ElasticCommonSchemaService}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class ElasticCommonSchemaServiceTests {
|
||||
|
||||
@@ -49,6 +50,14 @@ class ElasticCommonSchemaServiceTests {
|
||||
assertThat(service).isEqualTo(new ElasticCommonSchemaService("spring", null, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWhenNoServiceVersionUsesApplicationVersion() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("spring.application.version", "1.2.3");
|
||||
ElasticCommonSchemaService service = ElasticCommonSchemaService.get(environment);
|
||||
assertThat(service).isEqualTo(new ElasticCommonSchemaService(null, "1.2.3", null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWhenNoPropertiesToBind() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 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.
|
||||
|
||||
@@ -20,21 +20,21 @@ import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.impl.ThrowableProxy;
|
||||
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatter;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
public class CustomStructuredLogFormatter implements StructuredLogFormatter<LogEvent> {
|
||||
|
||||
private final ApplicationPid pid;
|
||||
private final Long pid;
|
||||
|
||||
public CustomStructuredLogFormatter(ApplicationPid pid) {
|
||||
this.pid = pid;
|
||||
public CustomStructuredLogFormatter(Environment environment) {
|
||||
this.pid = environment.getProperty("spring.application.pid", Long.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(LogEvent event) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("epoch=").append(event.getInstant().getEpochMillisecond());
|
||||
if (this.pid.isAvailable()) {
|
||||
if (this.pid != null) {
|
||||
result.append(" pid=").append(this.pid);
|
||||
}
|
||||
result.append(" msg=\"").append(event.getMessage().getFormattedMessage()).append('"');
|
||||
|
||||
@@ -21,16 +21,16 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.classic.spi.IThrowableProxy;
|
||||
|
||||
import org.springframework.boot.logging.structured.StructuredLogFormatter;
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
public class CustomStructuredLogFormatter implements StructuredLogFormatter<ILoggingEvent> {
|
||||
|
||||
private final ApplicationPid pid;
|
||||
private final Long pid;
|
||||
|
||||
private final ThrowableProxyConverter throwableProxyConverter;
|
||||
|
||||
public CustomStructuredLogFormatter(ApplicationPid pid, ThrowableProxyConverter throwableProxyConverter) {
|
||||
this.pid = pid;
|
||||
public CustomStructuredLogFormatter(Environment environment, ThrowableProxyConverter throwableProxyConverter) {
|
||||
this.pid = environment.getProperty("spring.application.pid", Long.class);
|
||||
this.throwableProxyConverter = throwableProxyConverter;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class CustomStructuredLogFormatter implements StructuredLogFormatter<ILog
|
||||
public String format(ILoggingEvent event) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("epoch=").append(event.getInstant().toEpochMilli());
|
||||
if (this.pid.isAvailable()) {
|
||||
if (this.pid != null) {
|
||||
result.append(" pid=").append(this.pid);
|
||||
}
|
||||
result.append(" msg=\"").append(event.getFormattedMessage()).append('"');
|
||||
|
||||
Reference in New Issue
Block a user