Skip to content

Commit db7166b

Browse files
authored
Merge pull request #123 from avaje/feature/plugin
Add ConfigurationPlugin and avaje-dynamic-logback
2 parents 29924af + 2d3a406 commit db7166b

File tree

10 files changed

+150
-2
lines changed

10 files changed

+150
-2
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.avaje.config;
2+
3+
import java.util.function.Consumer;
4+
5+
/**
6+
* Plugin that is initiated after the configuration has been loaded.
7+
*/
8+
public interface ConfigurationPlugin {
9+
10+
/**
11+
* Apply the plugin. Typically, a plugin might read configuration and do something
12+
* and listen for configuration changes via {@link Configuration#onChange(Consumer, String...)}.
13+
*
14+
* @param configuration The configuration that has been loaded including all {@link ConfigurationSource}.
15+
*/
16+
void apply(Configuration configuration);
17+
}

avaje-config/src/main/java/io/avaje/config/CoreComponents.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,22 @@ final class CoreComponents {
99
private final ConfigurationLog log;
1010
private final Parsers parsers;
1111
private final List<ConfigurationSource> sources;
12+
private final List<ConfigurationPlugin> plugins;
1213

13-
CoreComponents(ModificationEventRunner runner, ConfigurationLog log, Parsers parsers, List<ConfigurationSource> sources) {
14+
CoreComponents(ModificationEventRunner runner, ConfigurationLog log, Parsers parsers, List<ConfigurationSource> sources, List<ConfigurationPlugin> plugins) {
1415
this.runner = runner;
1516
this.log = log;
1617
this.parsers = parsers;
1718
this.sources = sources;
19+
this.plugins = plugins;
1820
}
1921

2022
CoreComponents() {
2123
this.runner = new CoreConfiguration.ForegroundEventRunner();
2224
this.log = new DefaultConfigurationLog();
2325
this.parsers = new Parsers();
2426
this.sources = Collections.emptyList();
27+
this.plugins = Collections.emptyList();
2528
}
2629

2730
Parsers parsers() {
@@ -39,4 +42,8 @@ ModificationEventRunner runner() {
3942
List<ConfigurationSource> sources() {
4043
return sources;
4144
}
45+
46+
List<ConfigurationPlugin> plugins() {
47+
return plugins;
48+
}
4249
}

avaje-config/src/main/java/io/avaje/config/CoreConfiguration.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ final class CoreConfiguration implements Configuration {
3737
private final CoreSetValue setValue;
3838
private final ModificationEventRunner eventRunner;
3939
private final List<ConfigurationSource> sources;
40+
private final List<ConfigurationPlugin> plugins;
4041

4142
private boolean loadedSystemProperties;
4243
private FileWatch watcher;
@@ -48,6 +49,7 @@ final class CoreConfiguration implements Configuration {
4849
this.eventRunner = components.runner();
4950
this.log = components.log();
5051
this.sources = components.sources();
52+
this.plugins = components.plugins();
5153
this.properties = new ModifyAwareProperties(entries);
5254
this.listValue = new CoreListValue(this);
5355
this.setValue = new CoreSetValue(this);
@@ -59,6 +61,7 @@ final class CoreConfiguration implements Configuration {
5961
this.eventRunner = parent.eventRunner;
6062
this.log = parent.log;
6163
this.sources = parent.sources;
64+
this.plugins = parent.plugins;
6265
this.properties = new ModifyAwareProperties(entries);
6366
this.listValue = new CoreListValue(this);
6467
this.setValue = new CoreSetValue(this);
@@ -89,11 +92,18 @@ CoreConfiguration postLoad(@Nullable InitialLoader loader) {
8992
initSystemProperties();
9093
if (loader != null) {
9194
logMessage(loader);
95+
applyPlugins();
9296
}
9397
log.postInitialisation();
9498
return this;
9599
}
96100

101+
private void applyPlugins() {
102+
for (ConfigurationPlugin plugin : plugins) {
103+
plugin.apply(this);
104+
}
105+
}
106+
97107
ConfigurationLog log() {
98108
return log;
99109
}

avaje-config/src/main/java/io/avaje/config/CoreConfigurationBuilder.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,11 @@ public Configuration build() {
7777
final var sources = ServiceLoader.load(ConfigurationSource.class).stream()
7878
.map(ServiceLoader.Provider::get)
7979
.collect(Collectors.toList());
80+
final var plugins = ServiceLoader.load(ConfigurationPlugin.class).stream()
81+
.map(ServiceLoader.Provider::get)
82+
.collect(Collectors.toList());
8083

81-
var components = new CoreComponents(runner, log, parsers, sources);
84+
var components = new CoreComponents(runner, log, parsers, sources, plugins);
8285
if (includeResourceLoading) {
8386
log.preInitialisation();
8487
initialLoader = new InitialLoader(components, initResourceLoader());

avaje-config/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
uses io.avaje.config.ConfigParser;
1010
uses io.avaje.config.ConfigurationLog;
11+
uses io.avaje.config.ConfigurationPlugin;
1112
uses io.avaje.config.ModificationEventRunner;
1213
uses io.avaje.config.ConfigurationSource;
1314
uses io.avaje.config.ResourceLoader;

avaje-dynamic-logback/pom.xml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>org.avaje</groupId>
8+
<artifactId>java11-oss</artifactId>
9+
<version>4.0</version>
10+
<relativePath/>
11+
</parent>
12+
13+
<groupId>io.avaje</groupId>
14+
<artifactId>avaje-dynamic-logback</artifactId>
15+
<version>0.1</version>
16+
17+
<properties>
18+
<surefire.useModulePath>false</surefire.useModulePath>
19+
</properties>
20+
21+
<dependencies>
22+
23+
<dependency>
24+
<groupId>io.avaje</groupId>
25+
<artifactId>avaje-config</artifactId>
26+
<version>3.12-RC1</version>
27+
</dependency>
28+
29+
<dependency>
30+
<groupId>ch.qos.logback</groupId>
31+
<artifactId>logback-classic</artifactId>
32+
<version>1.5.0</version>
33+
<scope>provided</scope>
34+
</dependency>
35+
36+
</dependencies>
37+
38+
</project>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package io.avaje.config.dynamiclogback;
2+
3+
import ch.qos.logback.classic.Level;
4+
import ch.qos.logback.classic.Logger;
5+
import ch.qos.logback.classic.LoggerContext;
6+
import io.avaje.applog.AppLog;
7+
import io.avaje.config.Configuration;
8+
import io.avaje.config.ConfigurationPlugin;
9+
import io.avaje.config.ModificationEvent;
10+
import org.slf4j.LoggerFactory;
11+
12+
import static java.lang.System.Logger.Level.DEBUG;
13+
14+
/**
15+
* Plugin to dynamically adjust the log levels via configuration changes.
16+
*/
17+
public final class LogbackPlugin implements ConfigurationPlugin {
18+
19+
private static final System.Logger log = AppLog.getLogger(LogbackPlugin.class);
20+
21+
@Override
22+
public void apply(Configuration configuration) {
23+
final var loggerContext = loggerContext();
24+
final var config = configuration.forPath("log.level");
25+
for (String key : config.keys()) {
26+
String rawLevel = configuration.get(key);
27+
setLogLevel(key, loggerContext, rawLevel);
28+
}
29+
configuration.onChange(this::onChangeAny);
30+
}
31+
32+
private static void setLogLevel(String key, LoggerContext loggerContext, String rawLevel) {
33+
String logKey = key.substring(10);
34+
Logger logger = loggerContext.getLogger(logKey);
35+
if (logger != null) {
36+
log.log(DEBUG, "logger change for {0} to {1}", logKey, rawLevel);
37+
logger.setLevel(Level.toLevel(rawLevel));
38+
}
39+
}
40+
41+
private void onChangeAny(ModificationEvent modificationEvent) {
42+
final var loggerContext = loggerContext();
43+
final var config = modificationEvent.configuration();
44+
modificationEvent.modifiedKeys().stream()
45+
.filter(key -> key.startsWith("log.level."))
46+
.forEach(key -> {
47+
String rawLevel = config.get(key);
48+
setLogLevel(key, loggerContext, rawLevel);
49+
});
50+
}
51+
52+
private LoggerContext loggerContext() {
53+
return (LoggerContext) LoggerFactory.getILoggerFactory();
54+
}
55+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import io.avaje.config.ConfigurationPlugin;
2+
import io.avaje.config.dynamiclogback.LogbackPlugin;
3+
4+
module io.avaje.config.dynamic.logback {
5+
6+
requires io.avaje.config;
7+
requires transitive io.avaje.lang;
8+
requires transitive io.avaje.applog;
9+
10+
requires static org.slf4j;
11+
requires static ch.qos.logback.core;
12+
requires static ch.qos.logback.classic;
13+
14+
provides ConfigurationPlugin with LogbackPlugin;
15+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.avaje.config.dynamiclogback.LogbackPlugin

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<modules>
1717
<module>avaje-config</module>
1818
<module>avaje-aws-appconfig</module>
19+
<module>avaje-dynamic-logback</module>
1920
</modules>
2021

2122
</project>

0 commit comments

Comments
 (0)