Skip to content

Commit 4568e90

Browse files
committed
Add option to configure logging filters
This commit introduces `logging.filters.console` and `logging.filters.file` properties which allow configuration of logging filters for default console and file appenders.
1 parent 5ef9364 commit 4568e90

File tree

4 files changed

+104
-0
lines changed

4 files changed

+104
-0
lines changed

spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ content into your application. Rather, pick only the properties that you need.
4343
logging.file= # Log file name. For instance, `myapp.log`
4444
logging.file.max-history= # Maximum of archive log files to keep. Only supported with the default logback setup.
4545
logging.file.max-size= # Maximum log file size. Only supported with the default logback setup.
46+
logging.filters.console= # Comma-separated list of filter classes to apply to console appender. Only supported with the default logback setup.
47+
logging.filters.file= # Comma-separated list of filter classes to apply to file appender. Only supported with the default logback setup.
4648
logging.level.*= # Log levels severity mapping. For instance, `logging.level.org.springframework=DEBUG`
4749
logging.path= # Location of the log file. For instance, `/var/log`
4850
logging.pattern.console= # Appender pattern for output to the console. Supported only with the default Logback setup.

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import ch.qos.logback.core.Appender;
2626
import ch.qos.logback.core.ConsoleAppender;
2727
import ch.qos.logback.core.CoreConstants;
28+
import ch.qos.logback.core.OutputStreamAppender;
29+
import ch.qos.logback.core.filter.Filter;
2830
import ch.qos.logback.core.rolling.RollingFileAppender;
2931
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
3032
import ch.qos.logback.core.util.FileSize;
@@ -120,6 +122,11 @@ private Appender<ILoggingEvent> consoleAppender(LogbackConfigurator config) {
120122
encoder.setCharset(StandardCharsets.UTF_8);
121123
config.start(encoder);
122124
appender.setEncoder(encoder);
125+
String[] filterClasses = this.patterns.getProperty("logging.filters.console",
126+
String[].class);
127+
if (filterClasses != null) {
128+
configureFilters(config, appender, filterClasses);
129+
}
123130
config.appender("CONSOLE", appender);
124131
return appender;
125132
}
@@ -135,6 +142,11 @@ private Appender<ILoggingEvent> fileAppender(LogbackConfigurator config,
135142
config.start(encoder);
136143
appender.setFile(logFile);
137144
setRollingPolicy(appender, config, logFile);
145+
String[] filterClasses = this.patterns.getProperty("logging.filters.file",
146+
String[].class);
147+
if (filterClasses != null) {
148+
configureFilters(config, appender, filterClasses);
149+
}
138150
config.appender("FILE", appender);
139151
return appender;
140152
}
@@ -166,4 +178,20 @@ private void setMaxFileSize(
166178
}
167179
}
168180

181+
@SuppressWarnings("unchecked")
182+
private void configureFilters(LogbackConfigurator config,
183+
OutputStreamAppender appender, String[] filterClasses) {
184+
for (String filterClass : filterClasses) {
185+
try {
186+
Filter filter = (Filter) Class.forName(filterClass).newInstance();
187+
config.start(filter);
188+
appender.addFilter(filter);
189+
}
190+
catch (Exception e) {
191+
throw new IllegalStateException(
192+
"Unable to configure " + filterClass + " logging filter");
193+
}
194+
}
195+
}
196+
169197
}

spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@
8585
"sourceType": "org.springframework.boot.context.logging.LoggingApplicationListener",
8686
"defaultValue": 0
8787
},
88+
{
89+
"name": "logging.filter.console",
90+
"type": "java.lang.String[]",
91+
"description": "Comma-separated list of filter classes to apply to console appender. Only supported with the default logback setup.",
92+
"sourceType": "org.springframework.boot.logging.LoggingApplicationListener"
93+
},
94+
{
95+
"name": "logging.filter.file",
96+
"type": "java.lang.String[]",
97+
"description": "Comma-separated list of filter classes to apply to file appender. Only supported with the default logback setup.",
98+
"sourceType": "org.springframework.boot.logging.LoggingApplicationListener"
99+
},
88100
{
89101
"name": "logging.level",
90102
"type": "java.util.Map<java.lang.String,java.lang.String>",

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@
2626
import ch.qos.logback.classic.Level;
2727
import ch.qos.logback.classic.Logger;
2828
import ch.qos.logback.classic.LoggerContext;
29+
import ch.qos.logback.classic.spi.ILoggingEvent;
2930
import ch.qos.logback.classic.spi.LoggerContextListener;
3031
import ch.qos.logback.core.ConsoleAppender;
3132
import ch.qos.logback.core.CoreConstants;
33+
import ch.qos.logback.core.filter.Filter;
3234
import ch.qos.logback.core.rolling.RollingFileAppender;
3335
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;
36+
import ch.qos.logback.core.spi.FilterReply;
3437
import org.apache.commons.logging.Log;
3538
import org.apache.commons.logging.impl.SLF4JLogFactory;
3639
import org.hamcrest.Matcher;
@@ -487,6 +490,45 @@ public void testDateformatPatternProperty() {
487490
.containsPattern("\\d{4}-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:\\d{2}");
488491
}
489492

493+
@Test
494+
public void consoleFiltersProperty() throws Exception {
495+
MockEnvironment environment = new MockEnvironment();
496+
environment.setProperty("logging.filters.console", HelloFilter.class.getName() +
497+
"," + HiFilter.class.getName());
498+
LoggingInitializationContext loggingInitializationContext =
499+
new LoggingInitializationContext(environment);
500+
this.loggingSystem.initialize(loggingInitializationContext, null, null);
501+
this.logger.info("Hello world");
502+
this.logger.info("Hi world");
503+
this.logger.info("Bye world");
504+
String output = this.output.toString().trim();
505+
assertThat(output).doesNotContain("Hello world");
506+
assertThat(output).doesNotContain("Hi world");
507+
assertThat(output).contains("Bye world");
508+
}
509+
510+
@Test
511+
public void fileFiltersProperty() throws Exception {
512+
MockEnvironment environment = new MockEnvironment();
513+
environment.setProperty("logging.filters.file", HelloFilter.class.getName() +
514+
"," + HiFilter.class.getName());
515+
LoggingInitializationContext loggingInitializationContext =
516+
new LoggingInitializationContext(environment);
517+
this.loggingSystem.initialize(loggingInitializationContext, null,
518+
getLogFile(null, tmpDir()));
519+
this.logger.info("Hello world");
520+
this.logger.info("Hi world");
521+
this.logger.info("Bye world");
522+
String output = this.output.toString().trim();
523+
File file = new File(tmpDir() + "/spring.log");
524+
assertThat(output).contains("Hello world");
525+
assertThat(output).contains("Hi world");
526+
assertThat(output).contains("Bye world");
527+
assertThat(getLineWithText(file, "Hello world")).isNull();
528+
assertThat(getLineWithText(file, "Hi world")).isNull();
529+
assertThat(getLineWithText(file, "Bye world")).isNotEmpty();
530+
}
531+
490532
private static Logger getRootLogger() {
491533
ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
492534
LoggerContext context = (LoggerContext) factory;
@@ -520,4 +562,24 @@ private String getLineWithText(String output, String outputSearch) {
520562
return null;
521563
}
522564

565+
static class HelloFilter extends Filter<ILoggingEvent> {
566+
567+
@Override
568+
public FilterReply decide(ILoggingEvent event) {
569+
return event.getMessage().contains("Hello")
570+
? FilterReply.DENY : FilterReply.NEUTRAL;
571+
}
572+
573+
}
574+
575+
static class HiFilter extends Filter<ILoggingEvent> {
576+
577+
@Override
578+
public FilterReply decide(ILoggingEvent event) {
579+
return event.getMessage().contains("Hi")
580+
? FilterReply.DENY : FilterReply.NEUTRAL;
581+
}
582+
583+
}
584+
523585
}

0 commit comments

Comments
 (0)