From c4c50b7c49f0e240a0e5cc65cffd2b609e686dab Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 28 Feb 2018 17:18:32 +0000 Subject: [PATCH] Only auto-configure LogbackMetrics when Logback is actually being used Closes gh-12286 --- .../pom.xml | 10 ++-- .../metrics/MetricsAutoConfiguration.java | 32 +++++++++- ...onfigurationWithLog4j2AndLogbackTests.java | 58 +++++++++++++++++++ 3 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationWithLog4j2AndLogbackTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index 0ef5930a77c..ef0ecf425de 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -37,6 +37,11 @@ spring-context + + ch.qos.logback + logback-classic + true + com.fasterxml.jackson.dataformat jackson-dataformat-xml @@ -379,11 +384,6 @@ spring-boot-test-support test - - ch.qos.logback - logback-classic - test - io.projectreactor reactor-test diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java index bfd9f8aae37..731b172e681 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.metrics; +import ch.qos.logback.classic.LoggerContext; import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; @@ -26,17 +27,25 @@ import io.micrometer.core.instrument.binder.logging.LogbackMetrics; import io.micrometer.core.instrument.binder.system.FileDescriptorMetrics; import io.micrometer.core.instrument.binder.system.ProcessorMetrics; import io.micrometer.core.instrument.binder.system.UptimeMetrics; +import org.slf4j.ILoggerFactory; +import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; +import org.springframework.core.type.AnnotatedTypeMetadata; /** * {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics. @@ -103,7 +112,9 @@ public class MetricsAutoConfiguration { static class MeterBindersConfiguration { @Bean - @ConditionalOnClass(name = "ch.qos.logback.classic.Logger") + @ConditionalOnClass(name = { "ch.qos.logback.classic.LoggerContext", + "org.slf4j.LoggerFactory" }) + @Conditional(LogbackLoggingCondition.class) @ConditionalOnMissingBean(LogbackMetrics.class) @ConditionalOnProperty(value = "management.metrics.binders.logback.enabled", matchIfMissing = true) public LogbackMetrics logbackMetrics() { @@ -133,4 +144,23 @@ public class MetricsAutoConfiguration { } + static class LogbackLoggingCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory(); + ConditionMessage.Builder message = ConditionMessage + .forCondition("LogbackLoggingCondition"); + if (loggerFactory instanceof LoggerContext) { + return ConditionOutcome.match( + message.because("ILoggerFactory is a Logback LoggerContext")); + } + return ConditionOutcome + .noMatch(message.because("ILoggerFactory is an instance of " + + loggerFactory.getClass().getCanonicalName())); + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationWithLog4j2AndLogbackTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationWithLog4j2AndLogbackTests.java new file mode 100644 index 00000000000..a56fe1cbe29 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationWithLog4j2AndLogbackTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2018 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 + * + * http://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.actuate.autoconfigure.metrics; + +import io.micrometer.core.instrument.binder.logging.LogbackMetrics; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; +import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.testsupport.runner.classpath.ClassPathOverrides; +import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link MetricsAutoConfiguration} when both Log4j2 and Logback are on the + * classpath. + * + * @author Andy Wilkinson + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathOverrides({ "org.apache.logging.log4j:log4j-core:2.9.0", + "org.apache.logging.log4j:log4j-slf4j-impl:2.9.0" }) +public class MetricsAutoConfigurationWithLog4j2AndLogbackTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class)); + + @Test + public void doesNotConfigureLogbackMetrics() { + this.contextRunner.run((context) -> { + System.out.println( + new ConditionEvaluationReportMessage(ConditionEvaluationReport + .get((ConfigurableListableBeanFactory) context + .getAutowireCapableBeanFactory()))); + assertThat(context).doesNotHaveBean(LogbackMetrics.class); + }); + } + +}