Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
按对象类型列出的java(log4j)日志过滤器_Java_Logging_Filter_Log4j - Fatal编程技术网

按对象类型列出的java(log4j)日志过滤器

按对象类型列出的java(log4j)日志过滤器,java,logging,filter,log4j,Java,Logging,Filter,Log4j,我有一个log4j当前实现的日志语句: log.info("Failed to create message for {}", CustomerData); 这将在CustomerData中记录一些敏感数据 是否有方法阻止对CustomerData的任何实例进行日志记录?可能在log4j配置中,或者通过自定义过滤器 如果log4j无法实现,那么其他日志框架如何?防止这种情况的最简单方法是编写/覆盖您的CustomerData.toString()方法 除此之外,您可以扩展slf4j,但不要问我

我有一个log4j当前实现的日志语句:

log.info("Failed to create message for {}", CustomerData);
这将在
CustomerData
中记录一些敏感数据

是否有方法阻止对
CustomerData
的任何实例进行日志记录?可能在log4j配置中,或者通过自定义过滤器


如果log4j无法实现,那么其他日志框架如何?

防止这种情况的最简单方法是编写/覆盖您的
CustomerData.toString()
方法

除此之外,您可以扩展slf4j,但不要问我如何做

在Log4j/SLF4j/任何日志框架中都没有提供(可能永远不会提供)

为了满足您的特定需求,最简单的方法是拥有自己的记录器装饰器

它可以是SLF4J或Log4j2的自定义日志记录实现。或者只是针对
记录器的某种工厂(例如,类似于SLF4j中的LoggerFactory,或者针对Log4j2的
Logger.getLogger()

它可以在内部创建自定义记录器实现,将其委托给真正的记录器,并且您可以在日志impl中执行额外的检查

e、 g.(psuedo代码)


但是正如您所看到的,有很多缺点,比如性能下降


如果您正在使用Logback(我相信您也可以对Log4j2执行类似的操作),那么您可以实现自己的Appender或编码器等

登录Logback时,它会在内部创建一个日志事件,其中包含日志消息和参数。因此,您不必在appender(或编码器等)中实际格式化日志消息,只需进行参数检查,如果异常看起来不正确,则抛出异常

此方法的注意事项: -仅当启用日志级别时,才会到达Appender。因此,若在配置中将日志级别设置为警告,那个么您将无法捕获由
logger.info(“message{}”,senstive)完成的日志消息
-它更多地与您正在使用的日志实现的内部实现有关,这意味着很难切换到其他实现(我相信这在现实生活中是罕见的)

优点是,如果您还没有自己的日志API,那么可以使用SLF4J/Log4j2 API来保存代码更改


编辑:

刚刚在Log4j2中检查,它允许您替换MessageFactory(用于基于message+params构造消息字符串)

信息工厂 MessageFactory用于生成消息对象。 应用程序可能会取代标准的ParameterizedMessageFactory(或 ReusableMessageFactory(在无垃圾模式下)通过设置 将系统属性log4j2.messageFactory设置为自定义 MessageFactory类

Logger.entry()和Logger.exit()方法的流消息具有 独立的工厂。申请可取代 通过设置系统属性的值来设置DefaultFlowMessageFactory log4j2.flowMessageFactory设置为自定义flowMessageFactory的名称 班级


因此,与上述方法类似,您可以创建自己的
MessageFactory
,进行额外的参数检查Log4j2提供了许多方法来实现这一点:

  • 过滤器
  • 重写日志事件

过滤器 Log4j2允许您在特定记录器、特定附加器或全局上进行配置(因此过滤器适用于所有日志事件)。过滤器提供的功能是强制接受日志事件、强制拒绝日志事件或保持“中立”。在您的情况下,您可能希望拒绝包含敏感数据的日志事件

您可以创建(有关如何安装自定义过滤器的信息,请参阅),也可以使用一些内置过滤器。对于您的目的,内置或a都应该足够了

正则表达式过滤器示例 假设这是一个包含敏感数据的类:

public class Customer {
    public String name;
    public String password;

    @Override
    public String toString() {
        return "Customer[name=" + name + ", password=" + password + "]";
    }
}
您的应用程序日志如下所示:

public class CustomerLoggingApp {
    public static void main(String[] args) {
        Logger log = LogManager.getLogger();

        Customer customer = new Customer();
        customer.name = "Jesse Zhuang";
        customer.password = "secret123";

        log.info("This is sensitive and should not be logged: {}", customer);
        log.info("But this message should be logged.");
    }
}
您可以配置一个正则表达式过滤器,用于查看格式化(或未格式化)消息,并拒绝任何包含单词“
Customer
”后跟“
,password=
”的日志消息:


重写日志事件 另一个有趣的选择是重写日志事件,这样消息就不会被完全过滤掉,而只是屏蔽敏感数据。例如,在日志中将密码字符串替换为“***”

为此,您需要创建一个。从手册中:

RewriteAppender允许在运行日志事件之前对其进行操作 由另一个附加程序处理。这可用于遮罩敏感区域 密码等信息或将信息注入每个 事件

重写策略示例:

package com.jesse.zhuang;

import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ObjectMessage;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.message.ReusableMessage;

@Plugin(name = "MaskSensitiveDataPolicy", category = Core.CATEGORY_NAME, 
        elementType = "rewritePolicy", printObject = true)
public class MaskSensitiveDataPolicy implements RewritePolicy {

    private String[] sensitiveClasses;

    @PluginFactory
    public static MaskSensitiveDataPolicy createPolicy(
            @PluginElement("sensitive") final String[] sensitiveClasses) {
        return new MaskSensitiveDataPolicy(sensitiveClasses);
    }

    private MaskSensitiveDataPolicy(String[] sensitiveClasses) {
        super();
        this.sensitiveClasses = sensitiveClasses;
    }

    @Override
    public LogEvent rewrite(LogEvent event) {
        Message rewritten = rewriteIfSensitive(event.getMessage());
        if (rewritten != event.getMessage()) {
            return new Log4jLogEvent.Builder(event).setMessage(rewritten).build();
        }
        return event;
    }

    private Message rewriteIfSensitive(Message message) {
        // Make sure to switch off garbage-free logging
        // by setting system property `log4j2.enable.threadlocals` to `false`.
        // Otherwise you may get ReusableObjectMessage, ReusableParameterizedMessage
        // or MutableLogEvent messages here which may not be rewritable...
        if (message instanceof ObjectMessage) {
            return rewriteObjectMessage((ObjectMessage) message);
        }
        if (message instanceof ParameterizedMessage) {
            return rewriteParameterizedMessage((ParameterizedMessage) message);
        }
        return message;
    }

    private Message rewriteObjectMessage(ObjectMessage message) {
        if (isSensitive(message.getParameter())) {
            return new ObjectMessage(maskSensitive(message.getParameter()));
        }
        return message;
    }

    private Message rewriteParameterizedMessage(ParameterizedMessage message) {
        Object[] params = message.getParameters();
        boolean changed = rewriteSensitiveParameters(params);
        return changed ? new ParameterizedMessage(message.getFormat(), params) : message;
    }

    private boolean rewriteSensitiveParameters(Object[] params) {
        boolean changed = false;
        for (int i = 0; i < params.length; i++) {
            if (isSensitive(params[i])) {
                params[i] = maskSensitive(params[i]);
                changed = true;
            }
        }
        return changed;
    }

    private boolean isSensitive(Object parameter) {
        return parameter instanceof Customer;
    }

    private Object maskSensitive(Object parameter) {
        Customer result = new Customer();
        result.name = ((Customer) parameter).name;
        result.password = "***";
        return result;
    }
}
这将使上述示例程序产生以下输出。请注意,密码被屏蔽,但敏感对象的其他属性被保留:

2018-01-09 22:18:30,561 INFO CustomerLoggingApp This is sensitive and should not be logged: Customer[name=Jesse Zhuang, password=***]
2018-01-09 22:18:30,569 INFO CustomerLoggingApp But this message should be logged.

不清楚您要问什么。
CustomerData.toString()
方法是什么样子的?@stdunbar CustomerData.toString将被记录。例如,“客户姓名:Jon Smith,客户性别:男性,客户年龄:25岁,客户余额:$100”。正如您所见,这包含敏感数据,我想知道是否有任何方法可以设置一个过滤器来阻止记录
CustomerData
@romac类型的任何对象,您对此有何澄清或具体疑问?我认为这是一个简单而直接的问题。我想问的是排除或阻止某一类型/类别的任何对象的可能性
CustomerData
,以及如果可能的话如何做到这一点。@JesseZhuang我认为这个问题有点混乱。当您键入log.info(“abcdefgh{},someStringHere)时,它将记录字符串“abcdefgh”+不管someStringHere的值是什么。因此,在您的情况下,无论CustomerData.toString()的结果是什么,都将在记录之前连接到上一个字符串的末尾。如果你
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <RegexFilter regex=".*Customer.*, password=.*" onMatch="DENY" onMismatch="NEUTRAL"/>
      <PatternLayout>
        <pattern>%d %level %c %m%n</pattern>
      </PatternLayout>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="debug">
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
  <ScriptFilter onMatch="DENY" onMisMatch="NEUTRAL">
    <Script name="DropSensitiveObjects" language="groovy"><![CDATA[
                parameters.any { p ->
                    // DENY log messages with Customer parameters
                    p.class.name == "Customer"
                }
              ]]>
    </Script>
  </ScriptFilter>
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout>
        <pattern>%d %level %c %m%n</pattern>
      </PatternLayout>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="debug">
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>
package com.jesse.zhuang;

import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ObjectMessage;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.message.ReusableMessage;

@Plugin(name = "MaskSensitiveDataPolicy", category = Core.CATEGORY_NAME, 
        elementType = "rewritePolicy", printObject = true)
public class MaskSensitiveDataPolicy implements RewritePolicy {

    private String[] sensitiveClasses;

    @PluginFactory
    public static MaskSensitiveDataPolicy createPolicy(
            @PluginElement("sensitive") final String[] sensitiveClasses) {
        return new MaskSensitiveDataPolicy(sensitiveClasses);
    }

    private MaskSensitiveDataPolicy(String[] sensitiveClasses) {
        super();
        this.sensitiveClasses = sensitiveClasses;
    }

    @Override
    public LogEvent rewrite(LogEvent event) {
        Message rewritten = rewriteIfSensitive(event.getMessage());
        if (rewritten != event.getMessage()) {
            return new Log4jLogEvent.Builder(event).setMessage(rewritten).build();
        }
        return event;
    }

    private Message rewriteIfSensitive(Message message) {
        // Make sure to switch off garbage-free logging
        // by setting system property `log4j2.enable.threadlocals` to `false`.
        // Otherwise you may get ReusableObjectMessage, ReusableParameterizedMessage
        // or MutableLogEvent messages here which may not be rewritable...
        if (message instanceof ObjectMessage) {
            return rewriteObjectMessage((ObjectMessage) message);
        }
        if (message instanceof ParameterizedMessage) {
            return rewriteParameterizedMessage((ParameterizedMessage) message);
        }
        return message;
    }

    private Message rewriteObjectMessage(ObjectMessage message) {
        if (isSensitive(message.getParameter())) {
            return new ObjectMessage(maskSensitive(message.getParameter()));
        }
        return message;
    }

    private Message rewriteParameterizedMessage(ParameterizedMessage message) {
        Object[] params = message.getParameters();
        boolean changed = rewriteSensitiveParameters(params);
        return changed ? new ParameterizedMessage(message.getFormat(), params) : message;
    }

    private boolean rewriteSensitiveParameters(Object[] params) {
        boolean changed = false;
        for (int i = 0; i < params.length; i++) {
            if (isSensitive(params[i])) {
                params[i] = maskSensitive(params[i]);
                changed = true;
            }
        }
        return changed;
    }

    private boolean isSensitive(Object parameter) {
        return parameter instanceof Customer;
    }

    private Object maskSensitive(Object parameter) {
        Customer result = new Customer();
        result.name = ((Customer) parameter).name;
        result.password = "***";
        return result;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" packages="com.jesse.zhuang">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout>
        <pattern>%d %level %c %m%n</pattern>
      </PatternLayout>
    </Console>

    <Rewrite name="obfuscateSensitiveData">
      <AppenderRef ref="Console"/>
      <MaskSensitiveDataPolicy />
    </Rewrite>

  </Appenders>
  <Loggers>
    <Root level="debug">
      <AppenderRef ref="obfuscateSensitiveData"/>
    </Root>
  </Loggers>
</Configuration>
2018-01-09 22:18:30,561 INFO CustomerLoggingApp This is sensitive and should not be logged: Customer[name=Jesse Zhuang, password=***]
2018-01-09 22:18:30,569 INFO CustomerLoggingApp But this message should be logged.