在不使用 logback.xml 文件的情况下,使用 spring 引导中的 MDC 或任何过滤器屏蔽日志消息中的密码
Mask the passwords in log messages using MDC or Any Filters in spring boot without using logback.xml file
我必须在 spring 引导中不使用 logback.xml 文件来屏蔽日志消息中的密码。
示例日志:
LOGGER.info("user password : {}", 密码);
预期输出:
2019-11-26 18:27:15,951 [http-nio-8080-exec-2] 信息 com.test.controller.TestController - 用户密码:************
我可以使用 logback.xml 文件实现相同的效果。如下所示。
但是没有 logback 文件需要在 spring 引导中使用 application.properties 配置文件。
注意:不要使用 log4j xml 文件。我们应该使用 slf4j 或 MDC 或任何过滤器和 application.properties
<configuration>
<property name="DEV_HOME" value="c:/logs" />
<appender name="CONSOLE"
class="ch.qos.logback.core.ConsoleAppender">
<encoder
class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.test.config.MaskingPatternLayout">
<patternsProperty>(SSN)</patternsProperty>
<pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
</layout>
</encoder>
</appender>
<logger name="com.test" level="debug" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<root level="error">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
是否可以在不使用 logback.xml 文件和 log4j.xml 文件的情况下实现这一点?
我们能否在应用程序属性文件中提及模式布局 java class 而不是在 logback.xml 文件中提及?
“在上面的例子中,我在 logback 中提到了 java 文件”
添加了 MaskingPatternLayout 以供参考:
package com.test.config;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.stereotype.Component;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
@Component
public class MaskingPatternTest extends PatternLayout {
private String patternsProperty;
private Optional<Pattern> pattern;
public String getPatternsProperty() {
return patternsProperty;
}
public void setPatternsProperty(String patternsProperty) {
this.patternsProperty = patternsProperty;
if (this.patternsProperty != null) {
this.pattern = Optional.of(Pattern.compile(patternsProperty, Pattern.MULTILINE));
} else {
this.pattern = Optional.empty();
}
}
@Override
public String doLayout(ILoggingEvent event) {
final StringBuilder message = new StringBuilder(super.doLayout(event));
if (pattern.isPresent()) {
Matcher matcher = pattern.get().matcher(message);
while (matcher.find()) {
int group = 1;
while (group <= matcher.groupCount()) {
if (matcher.group(group) != null) {
for (int i = matcher.start(group); i < matcher.end(group); i++) {
message.setCharAt(i, '*');
}
}
group++;
}
}
}
return message.toString();
}
}
请帮忙解决这个问题。
一旦您想使用高级日志记录功能(设置日志级别除外),就必须使用日志库特定的配置,例如 logback.xml
用于 Logback,log4j.xml
用于 log4j等等。
但是,Logback 确实有一个 API 您可以调用。例如,您可以使用 beans 设置 ConsoleAppender
:
@Bean
public LoggerContext loggerContext() {
return (LoggerContext) LoggerFactory.getILoggerFactory();
}
@Bean
public MaskPatternLayout maskPatternLayout(LoggerContext context) {
MaskPatternLayout layout = new MaskPatternLayout();
layout.setPatternsProperty("(SSN)");
layout.setPattern("%d [%thread] %-5level %logger{35} - %msg%n");
layout.setContext(context);
layout.start();
return layout;
}
@Bean
public LayoutWrappingEncoder<ILoggingEvent> maskEncoder(MaskPatternLayout layout) {
LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder<>();
encoder.setLayout(layout);
return encoder;
}
@Bean
public ConsoleAppender<ILoggingEvent> maskConsoleAppender(LoggerContext context, LayoutWrappingEncoder<ILoggingEvent> maskEncoder) {
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
appender.setContext(context);
appender.setEncoder(maskEncoder);
appender.start();
return appender;
}
现在您可以创建自己的 LoggerFactory
:
@Component
public class MaskLoggerFactory {
private final Appender<ILoggingEvent> appender;
public MaskLoggerFactory(Appender<ILoggingEvent> appender) {
this.appender = appender;
}
public org.slf4j.Logger getLogger(String name) {
Logger logger = (Logger) LoggerFactory.getLogger(name);
logger.addAppender(appender);
logger.setLevel(Level.ALL);
logger.setAdditive(false);
return logger;
}
public org.slf4j.Logger getLogger(Class<?> cls) {
return getLogger(cls.getName());
}
}
然后你可以自动连接 MaskLoggerFactory
以获得正确的 Logger
。但是,这并不能使事情更易于使用,如果您唯一的理由是避免创建单独的 XML 文件,我鼓励您继续使用该 XML 文件。
我必须在 spring 引导中不使用 logback.xml 文件来屏蔽日志消息中的密码。
示例日志: LOGGER.info("user password : {}", 密码);
预期输出: 2019-11-26 18:27:15,951 [http-nio-8080-exec-2] 信息 com.test.controller.TestController - 用户密码:************
我可以使用 logback.xml 文件实现相同的效果。如下所示。 但是没有 logback 文件需要在 spring 引导中使用 application.properties 配置文件。
注意:不要使用 log4j xml 文件。我们应该使用 slf4j 或 MDC 或任何过滤器和 application.properties
<configuration>
<property name="DEV_HOME" value="c:/logs" />
<appender name="CONSOLE"
class="ch.qos.logback.core.ConsoleAppender">
<encoder
class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.test.config.MaskingPatternLayout">
<patternsProperty>(SSN)</patternsProperty>
<pattern>%d [%thread] %-5level %logger{35} - %msg%n</pattern>
</layout>
</encoder>
</appender>
<logger name="com.test" level="debug" additivity="false">
<appender-ref ref="CONSOLE" />
</logger>
<root level="error">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
是否可以在不使用 logback.xml 文件和 log4j.xml 文件的情况下实现这一点?
我们能否在应用程序属性文件中提及模式布局 java class 而不是在 logback.xml 文件中提及? “在上面的例子中,我在 logback 中提到了 java 文件”
添加了 MaskingPatternLayout 以供参考:
package com.test.config;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.stereotype.Component;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
@Component
public class MaskingPatternTest extends PatternLayout {
private String patternsProperty;
private Optional<Pattern> pattern;
public String getPatternsProperty() {
return patternsProperty;
}
public void setPatternsProperty(String patternsProperty) {
this.patternsProperty = patternsProperty;
if (this.patternsProperty != null) {
this.pattern = Optional.of(Pattern.compile(patternsProperty, Pattern.MULTILINE));
} else {
this.pattern = Optional.empty();
}
}
@Override
public String doLayout(ILoggingEvent event) {
final StringBuilder message = new StringBuilder(super.doLayout(event));
if (pattern.isPresent()) {
Matcher matcher = pattern.get().matcher(message);
while (matcher.find()) {
int group = 1;
while (group <= matcher.groupCount()) {
if (matcher.group(group) != null) {
for (int i = matcher.start(group); i < matcher.end(group); i++) {
message.setCharAt(i, '*');
}
}
group++;
}
}
}
return message.toString();
}
}
请帮忙解决这个问题。
一旦您想使用高级日志记录功能(设置日志级别除外),就必须使用日志库特定的配置,例如 logback.xml
用于 Logback,log4j.xml
用于 log4j等等。
但是,Logback 确实有一个 API 您可以调用。例如,您可以使用 beans 设置 ConsoleAppender
:
@Bean
public LoggerContext loggerContext() {
return (LoggerContext) LoggerFactory.getILoggerFactory();
}
@Bean
public MaskPatternLayout maskPatternLayout(LoggerContext context) {
MaskPatternLayout layout = new MaskPatternLayout();
layout.setPatternsProperty("(SSN)");
layout.setPattern("%d [%thread] %-5level %logger{35} - %msg%n");
layout.setContext(context);
layout.start();
return layout;
}
@Bean
public LayoutWrappingEncoder<ILoggingEvent> maskEncoder(MaskPatternLayout layout) {
LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder<>();
encoder.setLayout(layout);
return encoder;
}
@Bean
public ConsoleAppender<ILoggingEvent> maskConsoleAppender(LoggerContext context, LayoutWrappingEncoder<ILoggingEvent> maskEncoder) {
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
appender.setContext(context);
appender.setEncoder(maskEncoder);
appender.start();
return appender;
}
现在您可以创建自己的 LoggerFactory
:
@Component
public class MaskLoggerFactory {
private final Appender<ILoggingEvent> appender;
public MaskLoggerFactory(Appender<ILoggingEvent> appender) {
this.appender = appender;
}
public org.slf4j.Logger getLogger(String name) {
Logger logger = (Logger) LoggerFactory.getLogger(name);
logger.addAppender(appender);
logger.setLevel(Level.ALL);
logger.setAdditive(false);
return logger;
}
public org.slf4j.Logger getLogger(Class<?> cls) {
return getLogger(cls.getName());
}
}
然后你可以自动连接 MaskLoggerFactory
以获得正确的 Logger
。但是,这并不能使事情更易于使用,如果您唯一的理由是避免创建单独的 XML 文件,我鼓励您继续使用该 XML 文件。