From 0e3a3df6f495ed0539ef9535b9d95071d20e2fb1 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 15 Nov 2016 13:57:16 -0800 Subject: [PATCH] Return log levels in `/loggers` endpoint payload Update `LoggersEndpoint` to additionally return the log levels actually supported by the system. Fixes gh-7396 --- spring-boot-actuator/pom.xml | 5 ++++ .../actuate/endpoint/LoggersEndpoint.java | 27 ++++++++++++++----- .../EndpointAutoConfigurationTests.java | 4 ++- .../endpoint/LoggersEndpointTests.java | 18 ++++++++++--- .../endpoint/mvc/LoggersMvcEndpointTests.java | 12 ++++++--- .../boot/logging/AbstractLoggingSystem.java | 10 ++++++- .../boot/logging/LoggingSystem.java | 11 ++++++++ .../boot/logging/java/JavaLoggingSystem.java | 6 +++++ .../logging/log4j2/Log4J2LoggingSystem.java | 6 +++++ .../logging/logback/LogbackLoggingSystem.java | 6 +++++ .../logging/java/JavaLoggingSystemTests.java | 8 ++++++ .../log4j2/Log4J2LoggingSystemTests.java | 7 +++++ .../logback/LogbackLoggingSystemTests.java | 8 ++++++ 13 files changed, 114 insertions(+), 14 deletions(-) diff --git a/spring-boot-actuator/pom.xml b/spring-boot-actuator/pom.xml index 7434a07c05..984b8cbf5d 100644 --- a/spring-boot-actuator/pom.xml +++ b/spring-boot-actuator/pom.xml @@ -338,6 +338,11 @@ hsqldb test + + org.skyscreamer + jsonassert + test + org.springframework spring-test diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LoggersEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LoggersEndpoint.java index 334d578295..fbb999a608 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LoggersEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LoggersEndpoint.java @@ -20,6 +20,9 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import java.util.NavigableSet; +import java.util.Set; +import java.util.TreeSet; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.logging.LogLevel; @@ -35,8 +38,7 @@ import org.springframework.util.Assert; * @since 1.5.0 */ @ConfigurationProperties(prefix = "endpoints.loggers") -public class LoggersEndpoint - extends AbstractEndpoint> { +public class LoggersEndpoint extends AbstractEndpoint> { private final LoggingSystem loggingSystem; @@ -51,18 +53,31 @@ public class LoggersEndpoint } @Override - public Map invoke() { + public Map invoke() { Collection configurations = this.loggingSystem .getLoggerConfigurations(); if (configurations == null) { return Collections.emptyMap(); } - Map result = new LinkedHashMap( + Map result = new LinkedHashMap(); + result.put("levels", getLevels()); + result.put("loggers", getLoggers(configurations)); + return result; + } + + private NavigableSet getLevels() { + Set levels = this.loggingSystem.getSupportedLogLevels(); + return new TreeSet(levels).descendingSet(); + } + + private Map getLoggers( + Collection configurations) { + Map loggers = new LinkedHashMap( configurations.size()); for (LoggerConfiguration configuration : configurations) { - result.put(configuration.getName(), new LoggerLevels(configuration)); + loggers.put(configuration.getName(), new LoggerLevels(configuration)); } - return result; + return loggers; } public LoggerLevels invoke(String name) { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java index e41fc55a8c..444e014314 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java @@ -130,7 +130,9 @@ public class EndpointAutoConfigurationTests { public void loggersEndpointHasLoggers() throws Exception { load(CustomLoggingConfig.class, EndpointAutoConfiguration.class); LoggersEndpoint endpoint = this.context.getBean(LoggersEndpoint.class); - Map loggers = endpoint.invoke(); + Map result = endpoint.invoke(); + Map loggers = (Map) result + .get("loggers"); assertThat(loggers.size()).isGreaterThan(0); } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/LoggersEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/LoggersEndpointTests.java index 21e27f7b8c..4d0aade680 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/LoggersEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/LoggersEndpointTests.java @@ -17,6 +17,9 @@ package org.springframework.boot.actuate.endpoint; import java.util.Collections; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; import org.junit.Test; @@ -45,12 +48,21 @@ public class LoggersEndpointTests extends AbstractEndpointTests } @Test + @SuppressWarnings("unchecked") public void invokeShouldReturnConfigurations() throws Exception { given(getLoggingSystem().getLoggerConfigurations()).willReturn(Collections .singletonList(new LoggerConfiguration("ROOT", null, LogLevel.DEBUG))); - LoggerLevels levels = getEndpointBean().invoke().get("ROOT"); - assertThat(levels.getConfiguredLevel()).isNull(); - assertThat(levels.getEffectiveLevel()).isEqualTo("DEBUG"); + given(getLoggingSystem().getSupportedLogLevels()) + .willReturn(EnumSet.allOf(LogLevel.class)); + Map result = getEndpointBean().invoke(); + Map loggers = (Map) result + .get("loggers"); + Set levels = (Set) result.get("levels"); + LoggerLevels rootLevels = loggers.get("ROOT"); + assertThat(rootLevels.getConfiguredLevel()).isNull(); + assertThat(rootLevels.getEffectiveLevel()).isEqualTo("DEBUG"); + assertThat(levels).containsExactly(LogLevel.OFF, LogLevel.FATAL, LogLevel.ERROR, + LogLevel.WARN, LogLevel.INFO, LogLevel.DEBUG, LogLevel.TRACE); } public void invokeWhenNameSpecifiedShouldReturnLevels() throws Exception { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpointTests.java index ab769ee67f..dbf81ed441 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/LoggersMvcEndpointTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.endpoint.mvc; import java.util.Collections; +import java.util.EnumSet; import org.junit.After; import org.junit.Before; @@ -80,18 +81,23 @@ public class LoggersMvcEndpointTests { .alwaysDo(MockMvcResultHandlers.print()).build(); } + @Before @After - public void reset() { + public void resetMocks() { Mockito.reset(this.loggingSystem); + given(this.loggingSystem.getSupportedLogLevels()) + .willReturn(EnumSet.allOf(LogLevel.class)); } @Test public void getLoggerShouldReturnAllLoggerConfigurations() throws Exception { given(this.loggingSystem.getLoggerConfigurations()).willReturn(Collections .singletonList(new LoggerConfiguration("ROOT", null, LogLevel.DEBUG))); + String expected = "{\"levels\":[\"OFF\",\"FATAL\",\"ERROR\",\"WARN\",\"INFO\",\"DEBUG\",\"TRACE\"]," + + "\"loggers\":{\"ROOT\":{\"configuredLevel\":null,\"effectiveLevel\":\"DEBUG\"}}}"; + System.out.println(expected); this.mvc.perform(get("/loggers")).andExpect(status().isOk()) - .andExpect(content().string(equalTo("{\"ROOT\":{\"configuredLevel\":" - + "null,\"effectiveLevel\":\"DEBUG\"}}"))); + .andExpect(content().json(expected)); } @Test diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java index d3521e2ced..711e180e64 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java @@ -17,7 +17,9 @@ package org.springframework.boot.logging; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; import org.springframework.core.env.Environment; import org.springframework.core.io.ClassPathResource; @@ -193,7 +195,9 @@ public abstract class AbstractLoggingSystem extends LoggingSystem { public void map(LogLevel system, T nativeLevel) { this.systemToNative.put(system, nativeLevel); - this.nativeToSystem.put(nativeLevel, system); + if (!this.nativeToSystem.containsKey(nativeLevel)) { + this.nativeToSystem.put(nativeLevel, system); + } } public LogLevel convertNativeToSystem(T level) { @@ -204,6 +208,10 @@ public abstract class AbstractLoggingSystem extends LoggingSystem { return this.systemToNative.get(level); } + public Set getSupported() { + return new LinkedHashSet(this.nativeToSystem.values()); + } + } } diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java index a2e1758037..a8a53462b5 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java @@ -17,9 +17,11 @@ package org.springframework.boot.logging; import java.util.Collections; +import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -94,6 +96,15 @@ public abstract class LoggingSystem { return null; } + /** + * Returns a set of the {@link LogLevel LogLevels} that are actually supported by the + * logging system. + * @return the supported levels + */ + public Set getSupportedLogLevels() { + return EnumSet.allOf(LogLevel.class); + } + /** * Sets the logging level for a given logger. * @param loggerName the name of the logger to set diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java index d23a99d337..da05c83f7f 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.Set; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; @@ -113,6 +114,11 @@ public class JavaLoggingSystem extends AbstractLoggingSystem { } } + @Override + public Set getSupportedLogLevels() { + return LEVELS.getSupported(); + } + @Override public void setLogLevel(String loggerName, LogLevel level) { Assert.notNull(level, "Level must not be null"); diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java index bfca2884d1..3ccc3c62fe 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java @@ -22,6 +22,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; @@ -197,6 +198,11 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem { getLoggerContext().reconfigure(); } + @Override + public Set getSupportedLogLevels() { + return LEVELS.getSupported(); + } + @Override public void setLogLevel(String loggerName, LogLevel logLevel) { Level level = LEVELS.convertSystemToNative(logLevel); diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java index f58ba8f57e..c71971466e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java @@ -22,6 +22,7 @@ import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; @@ -238,6 +239,11 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { return new LoggerConfiguration(logger.getName(), level, effectiveLevel); } + @Override + public Set getSupportedLogLevels() { + return LEVELS.getSupported(); + } + @Override public void setLogLevel(String loggerName, LogLevel level) { ch.qos.logback.classic.Logger logger = getLogger(loggerName); diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java index 12eb04eb9c..bc8a53b83f 100644 --- a/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.logging.java; import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.logging.Level; @@ -148,6 +149,13 @@ public class JavaLoggingSystemTests extends AbstractLoggingSystemTests { null); } + @Test + public void getSupportedLevels() { + assertThat(this.loggingSystem.getSupportedLogLevels()) + .isEqualTo(EnumSet.of(LogLevel.TRACE, LogLevel.DEBUG, LogLevel.INFO, + LogLevel.WARN, LogLevel.ERROR, LogLevel.OFF)); + } + @Test public void setLevel() throws Exception { this.loggingSystem.beforeInitialize(); diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java index 1e06c7c891..b2abdb969f 100644 --- a/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.FileReader; import java.util.ArrayList; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; @@ -122,6 +123,12 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { this.loggingSystem.initialize(null, "classpath:log4j2-nonexistent.xml", null); } + @Test + public void getSupportedLevels() { + assertThat(this.loggingSystem.getSupportedLogLevels()) + .isEqualTo(EnumSet.allOf(LogLevel.class)); + } + @Test public void setLevel() throws Exception { this.loggingSystem.beforeInitialize(); diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java index 072b9b8210..b7f2e117b0 100644 --- a/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.logging.logback; import java.io.File; import java.io.FileReader; +import java.util.EnumSet; import java.util.List; import java.util.logging.Handler; import java.util.logging.LogManager; @@ -162,6 +163,13 @@ public class LogbackLoggingSystemTests extends AbstractLoggingSystemTests { "classpath:logback-nonexistent.xml", null); } + @Test + public void getSupportedLevels() { + assertThat(this.loggingSystem.getSupportedLogLevels()) + .isEqualTo(EnumSet.of(LogLevel.TRACE, LogLevel.DEBUG, LogLevel.INFO, + LogLevel.WARN, LogLevel.ERROR, LogLevel.OFF)); + } + @Test public void setLevel() throws Exception { this.loggingSystem.beforeInitialize();