Я не думаю, что вы действительно хотите 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/>
Надеюсь, это поможет вам.