Return log levels in /loggers endpoint payload

Update `LoggersEndpoint` to additionally return the log levels actually
supported by the system.

Fixes gh-7396
This commit is contained in:
Madhura Bhave 2016-11-15 13:57:16 -08:00 committed by Phillip Webb
parent 764f13453a
commit 0e3a3df6f4
13 changed files with 114 additions and 14 deletions

View File

@ -338,6 +338,11 @@
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>

View File

@ -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<Map<String, LoggersEndpoint.LoggerLevels>> {
public class LoggersEndpoint extends AbstractEndpoint<Map<String, Object>> {
private final LoggingSystem loggingSystem;
@ -51,18 +53,31 @@ public class LoggersEndpoint
}
@Override
public Map<String, LoggerLevels> invoke() {
public Map<String, Object> invoke() {
Collection<LoggerConfiguration> configurations = this.loggingSystem
.getLoggerConfigurations();
if (configurations == null) {
return Collections.emptyMap();
}
Map<String, LoggerLevels> result = new LinkedHashMap<String, LoggerLevels>(
Map<String, Object> result = new LinkedHashMap<String, Object>();
result.put("levels", getLevels());
result.put("loggers", getLoggers(configurations));
return result;
}
private NavigableSet<LogLevel> getLevels() {
Set<LogLevel> levels = this.loggingSystem.getSupportedLogLevels();
return new TreeSet<LogLevel>(levels).descendingSet();
}
private Map<String, LoggerLevels> getLoggers(
Collection<LoggerConfiguration> configurations) {
Map<String, LoggerLevels> loggers = new LinkedHashMap<String, LoggerLevels>(
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) {

View File

@ -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<String, LoggerLevels> loggers = endpoint.invoke();
Map<String, Object> result = endpoint.invoke();
Map<String, LoggerLevels> loggers = (Map<String, LoggerLevels>) result
.get("loggers");
assertThat(loggers.size()).isGreaterThan(0);
}

View File

@ -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<LoggersEndpoint>
}
@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<String, Object> result = getEndpointBean().invoke();
Map<String, LoggerLevels> loggers = (Map<String, LoggerLevels>) result
.get("loggers");
Set<LogLevel> levels = (Set<LogLevel>) 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 {

View File

@ -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

View File

@ -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<LogLevel> getSupported() {
return new LinkedHashSet<LogLevel>(this.nativeToSystem.values());
}
}
}

View File

@ -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<LogLevel> getSupportedLogLevels() {
return EnumSet.allOf(LogLevel.class);
}
/**
* Sets the logging level for a given logger.
* @param loggerName the name of the logger to set

View File

@ -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<LogLevel> getSupportedLogLevels() {
return LEVELS.getSupported();
}
@Override
public void setLogLevel(String loggerName, LogLevel level) {
Assert.notNull(level, "Level must not be null");

View File

@ -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<LogLevel> getSupportedLogLevels() {
return LEVELS.getSupported();
}
@Override
public void setLogLevel(String loggerName, LogLevel logLevel) {
Level level = LEVELS.convertSystemToNative(logLevel);

View File

@ -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<LogLevel> getSupportedLogLevels() {
return LEVELS.getSupported();
}
@Override
public void setLogLevel(String loggerName, LogLevel level) {
ch.qos.logback.classic.Logger logger = getLogger(loggerName);

View File

@ -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();

View File

@ -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();

View File

@ -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();