(1). Actuator允许动态调整Log级别
//查看所有的日志信息
curl -X GET http://localhost:8080/actuator/loggers
// 修改某个类或者某个包(help.lixin.actuator.controller)的日志级别
curl -X POST -H "Content-Type: application/json" -d '{"configuredLevel": "INFO"}' http://localhost:8080/actuator/loggers/help.lixin.actuator.controller
(2). 看下(LoggersEndpointAutoConfiguration)源码
@Configuration
public class LoggersEndpointAutoConfiguration {
@Bean
@ConditionalOnBean(LoggingSystem.class)
@Conditional(OnEnabledLoggingSystemCondition.class)
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
public LoggersEndpoint loggersEndpoint(LoggingSystem loggingSystem) {
return new LoggersEndpoint(loggingSystem);
}
static class OnEnabledLoggingSystemCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 判断是否有配置:org.springframework.boot.logging.LoggingSystem =none
// 如果有配置则返回:false
ConditionMessage.Builder message = ConditionMessage
.forCondition("Logging System");
// org.springframework.boot.logging.LoggingSystem
String loggingSystem = System.getProperty(LoggingSystem.SYSTEM_PROPERTY);
// LoggingSystem.NONE = "none"
if (LoggingSystem.NONE.equals(loggingSystem)) {
return ConditionOutcome.noMatch(message.because("system property "
+ LoggingSystem.SYSTEM_PROPERTY + " is set to none"));
}
return ConditionOutcome.match(message.because("enabled"));
}
}
}
(3). LoggersEndpoint源码
// *****************************************************
// 2. http://ip:port/actuator/loggers
// *****************************************************
@Endpoint(id = "loggers")
public class LoggersEndpoint {
private final LoggingSystem loggingSystem;
// 1. 注入:LoggingSystem
public LoggersEndpoint(LoggingSystem loggingSystem) {
Assert.notNull(loggingSystem, "LoggingSystem must not be null");
this.loggingSystem = loggingSystem;
}
// GET http://ip:port/actuator/loggers
@ReadOperation
public Map<String, Object> loggers() {
Collection<LoggerConfiguration> configurations = this.loggingSystem
.getLoggerConfigurations();
if (configurations == null) {
return Collections.emptyMap();
}
Map<String, Object> result = new LinkedHashMap<>();
result.put("levels", getLevels());
result.put("loggers", getLoggers(configurations));
return result;
}
// GET http://ip:port/actuator/loggers/help.lixin
@ReadOperation
public LoggerLevels loggerLevels(@Selector String name) {
Assert.notNull(name, "Name must not be null");
LoggerConfiguration configuration = this.loggingSystem
.getLoggerConfiguration(name);
return (configuration != null) ? new LoggerLevels(configuration) : null;
}
// POST http://ip:port/actuator/loggers/help.lixin {configuredLevel:xxx,effectiveLevel:xxx}
@WriteOperation
public void configureLogLevel(@Selector String name,
@Nullable LogLevel configuredLevel) {
Assert.notNull(name, "Name must not be empty");
this.loggingSystem.setLogLevel(name, configuredLevel);
}
private NavigableSet<LogLevel> getLevels() {
Set<LogLevel> levels = this.loggingSystem.getSupportedLogLevels();
return new TreeSet<>(levels).descendingSet();
}
private Map<String, LoggerLevels> getLoggers(
Collection<LoggerConfiguration> configurations) {
Map<String, LoggerLevels> loggers = new LinkedHashMap<>(configurations.size());
for (LoggerConfiguration configuration : configurations) {
loggers.put(configuration.getName(), new LoggerLevels(configuration));
}
return loggers;
}
}
(4). 总结
Actuator针对日志这一块的操作是不是so easy…