Как написать приложение, которое обрабатывает только исключения и при этом все остальные журналы регистрируются в обычном режиме через root ConsoleAppender - PullRequest
0 голосов
/ 06 марта 2019

У меня есть ситуация, когда вызывается log.error("message", exception);, я хочу, чтобы произошла некоторая логика при отправке исключения внешнему инструменту, сохраняя при этом регулярное ведение журнала для линии корневого приложения.

В качестве примера приведем код и ожидаемый результат:

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
  ...

Пока это регистрируется, я также хочу, чтобы исключение было отправлено через другой путь кода.

Как я могу это сделать? Я немного застрял, кто-нибудь знает хорошие руководства для этого?

1 Ответ

1 голос
/ 07 марта 2019

Я не думаю, что вы действительно хотите Appender здесь.Было бы проще написать Filter вместо этого.Для справки вы можете найти информацию о создании расширений для log4j2 на странице Расширение Log4j2 руководства

В примере ниже я создал простой фильтр, который соответствует, когда событие журнала имеет Throwable связано с ним и не соответствует, когда нет Throwable (т. е. Throwable равно нулю или журнал был создан из вызова метода, который не включал параметр Throwable).

В этом примере я отправляю все соответствующие события журнала простому файловому приложению, чтобы проиллюстрировать, что на самом деле он захватывает только события с Throwable.Вы можете изменить этот фильтр, чтобы сделать все, что вам нужно.Вы можете изменить его так, чтобы оно всегда было NEUTRAL для каждого события, но когда обнаруживается ненулевое Throwable, оно запускает некоторую специальную логику для отправки этого Throwable вашему внешнему инструменту.В основном вы будете использовать фильтр как перехватчик.Я опишу это изменение в конце.

Во-первых, вот некоторый базовый Java-код для генерации некоторой регистрации, включая событие журнала, которое имеет 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:

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, который я использовал для проверки этого:

<?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 приводит кследующий вывод:

На консоли:

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:

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/:?]

Теперь измените фильтр, чтобы он действовал больше какПерехватчик вы можете изменить следующие методы:

//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();
}

Затем в конфигурации вы удалите параметры фильтра.Теперь это выглядело бы так:

<ThrowableFilter/>

Надеюсь, это поможет вам.

...