Polish /loggers actuator endpoint

See gh-7086
This commit is contained in:
Phillip Webb
2016-10-21 18:40:54 -07:00
parent 06cb4fcca5
commit a448183681
18 changed files with 345 additions and 313 deletions

View File

@@ -31,10 +31,12 @@ import org.springframework.util.Assert;
* {@link Endpoint} to expose a collection of {@link LoggerConfiguration}s.
*
* @author Ben Hale
* @author Phillip Webb
* @since 1.5.0
*/
@ConfigurationProperties(prefix = "endpoints.loggers")
public class LoggersEndpoint extends AbstractEndpoint<Map<String, Map<String, String>>> {
public class LoggersEndpoint
extends AbstractEndpoint<Map<String, LoggersEndpoint.LoggerLevels>> {
private final LoggingSystem loggingSystem;
@@ -49,44 +51,58 @@ public class LoggersEndpoint extends AbstractEndpoint<Map<String, Map<String, St
}
@Override
public Map<String, Map<String, String>> invoke() {
Collection<LoggerConfiguration> loggerConfigurations = this.loggingSystem
.listLoggerConfigurations();
if (loggerConfigurations == null) {
public Map<String, LoggerLevels> invoke() {
Collection<LoggerConfiguration> configurations = this.loggingSystem
.getLoggerConfigurations();
if (configurations == null) {
return Collections.emptyMap();
}
Map<String, Map<String, String>> result = new LinkedHashMap<String,
Map<String, String>>(loggerConfigurations.size());
for (LoggerConfiguration loggerConfiguration : loggerConfigurations) {
result.put(loggerConfiguration.getName(), result(loggerConfiguration));
Map<String, LoggerLevels> result = new LinkedHashMap<String, LoggerLevels>(
configurations.size());
for (LoggerConfiguration configuration : configurations) {
result.put(configuration.getName(), new LoggerLevels(configuration));
}
return result;
}
public Map<String, String> get(String name) {
public LoggerLevels invoke(String name) {
Assert.notNull(name, "Name must not be null");
return result(this.loggingSystem.getLoggerConfiguration(name));
LoggerConfiguration configuration = this.loggingSystem
.getLoggerConfiguration(name);
return (configuration == null ? null : new LoggerLevels(configuration));
}
public void set(String name, LogLevel level) {
public void setLogLevel(String name, LogLevel level) {
Assert.notNull(name, "Name must not be empty");
this.loggingSystem.setLogLevel(name, level);
}
private static Map<String, String> result(LoggerConfiguration loggerConfiguration) {
if (loggerConfiguration == null) {
return Collections.emptyMap();
/**
* Levels configured for a given logger exposed in a JSON friendly way.
*/
public static class LoggerLevels {
private String configuredLevel;
private String effectiveLevel;
public LoggerLevels(LoggerConfiguration configuration) {
this.configuredLevel = getName(configuration.getConfiguredLevel());
this.effectiveLevel = getName(configuration.getEffectiveLevel());
}
Map<String, String> result = new LinkedHashMap<String, String>(3);
LogLevel configuredLevel = loggerConfiguration.getConfiguredLevel();
result.put("configuredLevel",
configuredLevel != null ? configuredLevel.name() : null);
result.put("effectiveLevel", loggerConfiguration.getEffectiveLevel().name());
return result;
private String getName(LogLevel level) {
return (level == null ? null : level.name());
}
public String getConfiguredLevel() {
return this.configuredLevel;
}
public String getEffectiveLevel() {
return this.effectiveLevel;
}
}
}

View File

@@ -19,8 +19,10 @@ package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
import org.springframework.boot.actuate.endpoint.LoggersEndpoint.LoggerLevels;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.logging.LogLevel;
import org.springframework.http.HttpEntity;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
@@ -54,11 +56,11 @@ public class LoggersMvcEndpoint extends EndpointMvcAdapter {
// disabled
return getDisabledResponse();
}
return this.delegate.get(name);
LoggerLevels levels = this.delegate.invoke(name);
return (levels == null ? ResponseEntity.notFound().build() : levels);
}
@PostMapping(value = "/{name:.*}", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = "/{name:.*}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@HypermediaDisabled
public Object set(@PathVariable String name,
@@ -69,8 +71,8 @@ public class LoggersMvcEndpoint extends EndpointMvcAdapter {
return getDisabledResponse();
}
String level = configuration.get("configuredLevel");
this.delegate.set(name, level == null ? null : LogLevel.valueOf(level));
return ResponseEntity.EMPTY;
this.delegate.setLogLevel(name, level == null ? null : LogLevel.valueOf(level));
return HttpEntity.EMPTY;
}
}

View File

@@ -37,6 +37,7 @@ import org.springframework.boot.actuate.endpoint.HealthEndpoint;
import org.springframework.boot.actuate.endpoint.InfoEndpoint;
import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint;
import org.springframework.boot.actuate.endpoint.LoggersEndpoint;
import org.springframework.boot.actuate.endpoint.LoggersEndpoint.LoggerLevels;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.actuate.endpoint.PublicMetrics;
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
@@ -129,7 +130,7 @@ public class EndpointAutoConfigurationTests {
public void loggersEndpointHasLoggers() throws Exception {
load(CustomLoggingConfig.class, EndpointAutoConfiguration.class);
LoggersEndpoint endpoint = this.context.getBean(LoggersEndpoint.class);
Map<String, Map<String, String>> loggers = endpoint.invoke();
Map<String, LoggerLevels> loggers = endpoint.invoke();
assertThat(loggers.size()).isGreaterThan(0);
}

View File

@@ -17,10 +17,10 @@
package org.springframework.boot.actuate.endpoint;
import java.util.Collections;
import java.util.Map;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.LoggersEndpoint.LoggerLevels;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggerConfiguration;
@@ -45,25 +45,24 @@ public class LoggersEndpointTests extends AbstractEndpointTests<LoggersEndpoint>
}
@Test
public void invoke() throws Exception {
given(getLoggingSystem().listLoggerConfigurations()).willReturn(Collections
.singleton(new LoggerConfiguration("ROOT", null, LogLevel.DEBUG)));
Map<String, String> loggingConfiguration = getEndpointBean().invoke()
.get("ROOT");
assertThat(loggingConfiguration.get("configuredLevel")).isNull();
assertThat(loggingConfiguration.get("effectiveLevel")).isEqualTo("DEBUG");
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");
}
public void get() throws Exception {
public void invokeWhenNameSpecifiedShouldReturnLevels() throws Exception {
given(getLoggingSystem().getLoggerConfiguration("ROOT"))
.willReturn(new LoggerConfiguration("ROOT", null, LogLevel.DEBUG));
Map<String, String> loggingConfiguration = getEndpointBean().get("ROOT");
assertThat(loggingConfiguration.get("configuredLevel")).isNull();
assertThat(loggingConfiguration.get("effectiveLevel")).isEqualTo("DEBUG");
LoggerLevels levels = getEndpointBean().invoke("ROOT");
assertThat(levels.getConfiguredLevel()).isNull();
assertThat(levels.getEffectiveLevel()).isEqualTo("DEBUG");
}
public void set() throws Exception {
getEndpointBean().set("ROOT", LogLevel.DEBUG);
public void setLogLevelShouldSetLevelOnLoggingSystem() throws Exception {
getEndpointBean().setLogLevel("ROOT", LogLevel.DEBUG);
verify(getLoggingSystem()).setLogLevel("ROOT", LogLevel.DEBUG);
}

View File

@@ -18,9 +18,11 @@ package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
@@ -37,9 +39,9 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@@ -57,9 +59,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* Tests for {@link LoggersMvcEndpoint}.
*
* @author Ben Hale
* @author Phillip Webb
*/
@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest
public class LoggersMvcEndpointTests {
@@ -74,50 +76,60 @@ public class LoggersMvcEndpointTests {
@Before
public void setUp() {
this.context.getBean(LoggersEndpoint.class).setEnabled(true);
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
this.mvc = MockMvcBuilders.webAppContextSetup(this.context)
.alwaysDo(MockMvcResultHandlers.print()).build();
}
@After
public void reset() {
Mockito.reset(this.loggingSystem);
}
@Test
public void list() throws Exception {
given(this.loggingSystem.listLoggerConfigurations()).willReturn(Collections
.singleton(new LoggerConfiguration("ROOT", null, LogLevel.DEBUG)));
public void getLoggerShouldReturnAllLoggerConfigurations() throws Exception {
given(this.loggingSystem.getLoggerConfigurations()).willReturn(Collections
.singletonList(new LoggerConfiguration("ROOT", null, LogLevel.DEBUG)));
this.mvc.perform(get("/loggers")).andExpect(status().isOk())
.andExpect(content().string(equalTo("{\"ROOT\":{\"configuredLevel\":"
+ "null,\"effectiveLevel\":\"DEBUG\"}}")));
}
@Test
public void listDisabled() throws Exception {
public void getLoggersWhenDisabledShouldReturnNotFound() throws Exception {
this.context.getBean(LoggersEndpoint.class).setEnabled(false);
this.mvc.perform(get("/loggers")).andExpect(status().isNotFound());
}
@Test
public void getLogger() throws Exception {
public void getLoggerShouldReturnLogLevels() throws Exception {
given(this.loggingSystem.getLoggerConfiguration("ROOT"))
.willReturn(new LoggerConfiguration("ROOT", null, LogLevel.DEBUG));
this.mvc.perform(get("/loggers/ROOT")).andExpect(status().isOk())
.andExpect(content().string(equalTo("{\"configuredLevel\":null,"
+ "\"effectiveLevel\":\"DEBUG\"}")));
.andExpect(content().string(equalTo(
"{\"configuredLevel\":null," + "\"effectiveLevel\":\"DEBUG\"}")));
}
@Test
public void getLoggerDisabled() throws Exception {
public void getLoggesWhenDisabledShouldReturnNotFound() throws Exception {
this.context.getBean(LoggersEndpoint.class).setEnabled(false);
this.mvc.perform(get("/loggers/ROOT")).andExpect(status().isNotFound());
}
@Test
public void setLogger() throws Exception {
public void getLoggersWhenLoggerNotFoundShouldReturnNotFound() throws Exception {
this.mvc.perform(get("/loggers/com.does.not.exist"))
.andExpect(status().isNotFound());
}
@Test
public void setLoggerShouldSetLogLevel() throws Exception {
this.mvc.perform(post("/loggers/ROOT").contentType(MediaType.APPLICATION_JSON)
.content("{\"configuredLevel\":\"DEBUG\"}")).andExpect(status().isOk());
.content("{\"configuredLevel\":\"DEBUG\"}")).andExpect(status().isOk());
verify(this.loggingSystem).setLogLevel("ROOT", LogLevel.DEBUG);
}
@Test
public void setLoggerDisabled() throws Exception {
public void setLoggerWhenDisabledShouldReturnNotFound() throws Exception {
this.context.getBean(LoggersEndpoint.class).setEnabled(false);
this.mvc.perform(post("/loggers/ROOT").contentType(MediaType.APPLICATION_JSON)
.content("{\"configuredLevel\":\"DEBUG\"}"))
@@ -125,11 +137,11 @@ public class LoggersMvcEndpointTests {
verifyZeroInteractions(this.loggingSystem);
}
@Configuration
@Import({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class })
@Configuration
public static class TestConfiguration {
@Bean