简体   繁体   English

如何在登录文件之前使用Log4j2 xml重写追加程序修改LogEvent

[英]How to use Log4j2 xml Rewrite appender for modifying LogEvent before it logs in file

I want to use Rewrite appender in my log4j2.xml file so that before logging I can modify logs. 我想在log4j2.xml文件中使用重写追加程序,以便在记录之前可以修改日志。 I have not get much helps from google. 我没有从Google获得太多帮助。 As per log4j2 documents Rewrite is an interface has rewrite method and MapRewritePolicy is implementation class, when I run this I am able to see my web3.log file generating but not seeing any modification in log content. 根据log4j2文档,Rewrite是具有重写方法的接口,而MapRewritePolicy是实现类,当我运行它时,我可以看到我的web3.log文件正在生成,但是看不到日志内容的任何修改。 I seen MapRewritePolicy source code and created local implementation class as MapRewritePolicyImpl.java in my project and put some System.out to see code flow is coming into this class from log4j2.xml file. 我在项目中看到了MapRewritePolicy源代码,并以MapRewritePolicyImpl.java的形式创建了本地实现类,并放置了一些System.out来查看代码流从log4j2.xml文件进入此类。 I have modified my log4j2.xml to use MapRewritePolicyImpl.java but code flow is not going into my MapRewritePolicyImpl.java class. 我已经修改了log4j2.xml以使用MapRewritePolicyImpl.java,但是代码流没有进入MapRewritePolicyImpl.java类。

<Rewrite name="rewrite" >
            <Appender-Ref ref="web3" />
             <MapRewritePolicyImpl">
                <KeyValuePair key="creditCard" value="new12345"/>
            </MapRewritePolicyImpl> 
        </Rewrite>



    <Configuration monitorInterval="5" status="debug" strict="true">
        <Appenders>
            <RollingFile name="web3" fileName="../logs/web3.log" 
                filePattern="${sys:catalina.home}/logs/$${date:yyyy-MM-dd}/web3-%d{yyyy-MM-dd}-%i.log.gz">
                <PatternLayout
                    pattern="%d{dd/MM/yyyy HH:mm:ss,SSS} [%X{cartID}] [%X{sessionId}] [%p] [%t] [%c] (%F:%L)  - %m%n" />
                <Policies>
                    <TimeBasedTriggeringPolicy interval="1"
                        modulate="true" />
                    <SizeBasedTriggeringPolicy size="10 MB" />

                </Policies>
            </RollingFile>
            <Rewrite name="rewrite" >
                <Appender-Ref ref="web3" />
                 <MapRewritePolicy">
                    <KeyValuePair key="creditCard" value="new12345"/>
                </MapRewritePolicy> 
            </Rewrite>
    </Appenders>
    <Loggers>
        <Logger name="com.virginamerica" level="info" additivity="false">
            <!-- <Appender-Ref ref="web3" /> -->
            <Appender-Ref ref="rewrite"/>
        </Logger>
    </Loggers>
</Configuration>

Solution 1: Using RewriteAppender 解决方案1:使用RewriteAppender

Your example seems almost correct. 您的示例似乎几乎是正确的。 As mentioned by @Remko Popma the Rewrite implementation you selected is not fit for your usecase. 如@Remko Popma所述,您选择的Rewrite实现不适合您的用例。

If you use your own Rewriter implementation you can get it to work. 如果您使用自己的Rewriter实现,则可以使其生效。

I found a very good example here: RewriteAppender Example 我在这里找到了一个很好的示例: RewriteAppender示例

The example contains the log4j2.xml and the implementation of the RewriteAppender. 该示例包含log4j2.xml和RewriteAppender的实现。 In the RewriteAppender (here called MarkerInjectorRewritePolicy ) you can modify the event to fit your needs. 在RewriteAppender(这里称为MarkerInjectorRewritePolicy )中,您可以修改事件以适合您的需求。 In the example the author injects some marker-data, you would not need that part. 在示例中,作者注入了一些标记数据,您将不需要该部分。

.

Solution 2: Using LogEventFactory 解决方案2:使用LogEventFactory

Solution 1 has some drawbacks. 解决方案1具有一些缺点。 Imagine you have a 100 loggers and 50 Appenders. 假设您有100个记录器和50个Appender。 Trying to implement solution 1 now you end up with another 50 RewriteAppender declarations plus adjustments to all loggers to use the redirect logger instead of the actual target Appender. 现在,尝试实施解决方案1时,您最终会得到另外50个RewriteAppender声明以及对所有记录器的调整,以使用重定向记录器代替实际的目标Appender。 This can be very tedious and error-prone. 这可能非常繁琐且容易出错。

A much easier solution is this: 一个更简单的解决方案是:

// Do this somewhere before using the logger
System.setProperty(Constants.LOG4J_LOG_EVENT_FACTORY, MyLogEventFactory.class.getName());

Or set it by using the start parameter: 或使用start参数进行设置:

-DLog4jLogEventFactory=my.package.MyLogEventFactory

EDIT: BETTER: A more robust way to set this is by using a log4j2.component.properties : 编辑:更好:设置此功能的更可靠的方法是使用log4j2.component.properties

  • Create a text file called log4j2.component.properties and put it in your classpath. 创建一个名为log4j2.component.properties的文本文件,并将其放在您的类路径中。
  • Put this code in it: Log4jLogEventFactory = my.package.MyLogEventFactory 将以下代码放入其中: Log4jLogEventFactory = my.package.MyLogEventFactory

This file is loaded automatically by log4j and used to configure multiple core settings. 该文件由log4j自动加载,并用于配置多个核心设置。 Using this file you do not have to pass start-parameters every time plus you don't run into the potential problem of class initialization ordering problems (like when using System.setProperty() ). 使用此文件,您不必每次都传递起始参数,也不必遇到潜在的类初始化排序问题(例如,使用System.setProperty() )。

The LogEventFactory implementation is pretty simple: LogEventFactory实现非常简单:

public class MyLogEventFactory implements LogEventFactory {

    @Override
    public LogEvent createEvent(String loggerName, Marker marker, String fqcn, Level level, Message message,
            List<Property> properties, Throwable t) {
        { // In my case i wanted "log.error(new Exception(msg))"
          // to pass the exception properly to the event,
          // as if "log.error(msg, new Exception(msg))" was called.
            if (t == null && message instanceof ObjectMessage) {
                ObjectMessage msg = (ObjectMessage) message;
                t = msg.getThrowable();
            }
        }
        // XXX do your adjustments here
        return new Log4jLogEvent(loggerName, marker, fqcn, level, message, properties, t);
    }

}

The LogEventFactory is used to create the LogEvents . LogEventFactory用于创建LogEvents So instead of intercepting and manipulating them later, we simply go to the source and do our work here. 因此,我们不再去侦听和操纵它们,而是直接前往源代码并在此处进行工作。

With this we get ALL events! 有了这个我们得到所有事件!

Good luck! 祝好运! Have fun! 玩得开心!

MapRewritePolicy will evaluate LogEvents that contain a MapMessage and will add or update elements of the Map. MapRewritePolicy将评估包含MapMessage的LogEvent,并添加或更新Map的元素。 This only works if your application calls logger.info(new MapMessage(keyValueMap)) . 仅当您的应用程序调用logger.info(new MapMessage(keyValueMap))此方法才有效。 I suspect that this is not what your application is currently doing. 我怀疑这不是您的应用程序当前正在执行的操作。

Usually, your messages will be either a SimpleMessage (if you called logger.info("Just a string without parameters") ) or a ParameterizedMessage (if you called logger.info("Hi {}!", name) ). 通常,您的消息将是SimpleMessage(如果您调用logger.info("Just a string without parameters") )或ParameterizedMessage(如果您将其称为logger.info("Hi {}!", name) )。 RewriteAppender will not be able to do anything with either SimpleMessage or ParameterizedMessages, so nothing is replaced... RewriteAppender将无法对SimpleMessage或ParameterizedMessages进行任何操作,因此什么也不会被替换...

You may want to take a look at the documentation for PatternLayout : this has the capability to replace regular expressions in string messages with some replacement value, if you use the replace{pattern}{regex}{substitution} pattern. 您可能需要看一下PatternLayout的文档:如果您使用replace{pattern}{regex}{substitution}模式,它可以用一些替换值替换字符串消息中的replace{pattern}{regex}{substitution}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM