如何编写仅处理异常并且仍然​​通过root ConsoleAppender正常记录所有其他日志的附加程序 [英] How do I write an appender that only handles exceptions and still have all other logs logged normally through a root ConsoleAppender

查看:64
本文介绍了如何编写仅处理异常并且仍然​​通过root ConsoleAppender正常记录所有其他日志的附加程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到一种情况,当调用 log.error("message",exception); 时,我希望在将异常发送到外部工具的同时发生一些逻辑,同时仍保持常规将行记录到根附加程序.

I have a situation where when log.error("message", exception); is called, I want some logic to happen around sending the exception to an external tool, while still maintaining the regular logging for the line to the root appender.

例如,下面是一些代码和预期结果:

As an example, here would be some code and the expected outcome:

try {
   ...
} catch (Exception ex) {
   LOG.info("abcd");
   LOG.error("failed to XYZ", ex);
}

粗略结果:

2019-03-05 13:00:20 INFO  Main:75 - abcd
2019-03-05 13:00:20 ERROR  Main:76 - failed to XYZ - 
Exception: exception message
  stacktrace
  stacktrace
  ...

在记录的同时,我还希望通过另一个代码路径发送异常.

While that is logged, I also want the exception sent through another code path.

我该怎么做?我有点被困住了,有人知道这方面有什么好的指南吗?

How can I do this? I'm a bit stuck, does anyone know any good guides for this?

推荐答案

我不认为您真的需要 Appender .改为编写 Filter 会更简单.供参考,您可以在扩展Log4j2页面上找到有关为log4j2创建扩展的信息.手册

I don't think you really want an Appender here. It would be simpler to write a Filter instead. For reference you can find information regarding creating extensions for log4j2 on the Extending Log4j2 page of the manual

在下面的示例中,我创建了一个简单的过滤器,该过滤器在日志事件具有与之关联的 Throwable 时匹配,而在没有 Throwable (即 Throwable 为空,或者该日志是通过不包含 Throwable 参数的方法调用生成的.

In the example below I created a simple filter that matches when the log event has a Throwable associated with it and mismatches when there is no Throwable (i.e. the Throwable is null or the log was generated from a method call that did not include a Throwable parameter).

在示例中,我将所有匹配的日志事件发送到一个简单的文件追加器,以说明实际上它仅捕获具有 Throwable 的事件.您可以修改此过滤器以执行所需的任何操作.您可以将其更改为始终对每个事件都是 NEUTRAL ,但是当发现非null的 Throwable 时,它会触发一些特殊的逻辑来发送该 Throwable 到您的外部工具.基本上,您将过滤器更多地用作拦截器.我将在最后描述这种变化.

In the example I send all matching log events to a simple file appender to illustrate that in fact it does capture only events with a Throwable. You could modify this filter to do whatever you need. You could change it to always be NEUTRAL to every event, but when a non-null Throwable is found it then triggers some special logic to send that Throwable to your external tool. Basically you would be using the filter as more of an interceptor. I will describe that change at the end.

首先,这里有一些基本的 Java 代码,用于生成一些日志记录,包括具有 Throwable 的日志事件.

First, here's some basic Java code to generate some logging including a log event that has a Throwable.

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class SomeClass {

    private static final Logger log = LogManager.getLogger();   

    public static void main(String[] args){

        if(log.isDebugEnabled())
            log.debug("This is some debug!");
        log.info("Here's some info!");
        log.error("Some error happened!");

        try{
            specialLogic();
        }catch(RuntimeException e){
            log.error("Woops, an exception was detected.", e);
        }
    }

    public static void specialLogic(){
        throw new RuntimeException("Hey an exception happened! Oh no!");
    }
}

接下来,这是我称为 ThrowableFilter 的类:

Next, here's the class I call ThrowableFilter:

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.message.Message;

@Plugin(name = "ThrowableFilter", category = "Core", elementType = "filter", printObject = true)
public final class ThrowableFilter extends AbstractFilter {


    private ThrowableFilter(Result onMatch, Result onMismatch) {
        super(onMatch, onMismatch);
    }

    public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
        return onMismatch;
    }

    public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
        return filter(t);
    }

    public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
        return filter(t);
    }

    @Override
    public Result filter(LogEvent event) {
        return filter(event.getThrown());
    }

    private Result filter(Throwable t) {
        return t != null ? onMatch : onMismatch;
    }

    /**
     * Create a ThrowableFilter.
     * @param match The action to take on a match.
     * @param mismatch The action to take on a mismatch.
     * @return The created ThrowableFilter.
     */
    @PluginFactory
    public static ThrowableFilter createFilter(@PluginAttribute(value = "onMatch", defaultString = "NEUTRAL") Result onMatch,
                                               @PluginAttribute(value = "onMismatch", defaultString = "DENY") Result onMismatch) {
        return new ThrowableFilter(onMatch, onMismatch);
    }
}

最后,这是我用来测试它的log4j2.xml配置文件:

Finally, here is the log4j2.xml configuration file I used to test this:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>

        <File name="ExceptionFile" fileName="logs/exception.log" immediateFlush="true"
            append="true">
            <ThrowableFilter onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout
                pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </File>
    </Appenders>

    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console" />
            <AppenderRef ref="ExceptionFile" />
        </Root>
    </Loggers>
</Configuration>

SomeClass 中运行逻辑会产生以下输出:

Running the logic in SomeClass produces the following output:

在控制台上:

23:23:25.931 [main] DEBUG example.SomeClass - This is some debug!
23:23:25.946 [main] INFO  example.SomeClass - Here's some info!
23:23:25.946 [main] ERROR example.SomeClass - Some error happened!
23:23:25.946 [main] ERROR example.SomeClass - Woops, an exception was detected.
java.lang.RuntimeException: Hey an exception happened! Oh no!
    at example.SomeClass.specialLogic(SomeClass.java:25) ~[classes/:?]
    at example.SomeClass.main(SomeClass.java:18) [classes/:?]

在logs/exception.log文件中:

In the logs/exception.log file:

2019-03-06 23:23:25.946 [main] ERROR example.SomeClass - Woops, an exception was detected.
java.lang.RuntimeException: Hey an exception happened! Oh no!
    at example.SomeClass.specialLogic(SomeClass.java:25) ~[classes/:?]
    at example.SomeClass.main(SomeClass.java:18) [classes/:?]

现在要更改过滤器以使其更多地充当拦截器,您可以更改以下方法:

Now to change the filter to act more as an interceptor you could alter the following methods:

//Remove parameters from constructor as they will not be used.
private ThrowableFilter() {
    super();
}
...

public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
    //Changed to always return NEUTRAL result
    return Result.NEUTRAL;
    //old logic: return onMismatch;
}

...

private Result filter(Throwable t) {
    //TODO: trigger the external tool here when t != null, pass t if needed.

    //Changed to always return NEUTRAL result
    return Result.NEUTRAL;
    //old logic: return t != null ? onMatch : onMismatch;
}

/**
 * Create a ThrowableFilter.
 * @return The created ThrowableFilter.
 */
@PluginFactory
public static ThrowableFilter createFilter() {
    return new ThrowableFilter();
}

然后在配置中,将参数删除到过滤器中.现在看起来像这样:

Then in the configuration you would remove the parameters to the filter. It would now look like this:

<ThrowableFilter/>

希望这对您有所帮助.

这篇关于如何编写仅处理异常并且仍然​​通过root ConsoleAppender正常记录所有其他日志的附加程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆