Java 如何在 log4j2 中创建自定义 Appender?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24205093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Create a Custom Appender in log4j2?
提问by saurabh goyal
As disscussed in this link : How to create a own Appender in log4j?
正如此链接中所述:How to create a own Appender in log4j?
For creating a custom appender in log4j 1.x we have to extend the AppenderSkeleton class and implements its append method.
为了在 log4j 1.x 中创建自定义 appender,我们必须扩展 AppenderSkeleton 类并实现其 append 方法。
Similarly How we can create a custom appender in log4j2 as we dont have AppenderSkelton class to extend and all other appender extend AppenderBase class .
同样,我们如何在 log4j2 中创建自定义 appender,因为我们没有 AppenderSkelton 类要扩展,而所有其他 appender 都扩展 AppenderBase 类。
采纳答案by Remko Popma
This works quite differently in log4j2 than in log4j-1.2.
这在 log4j2 中与在 log4j-1.2 中的工作方式完全不同。
In log4j2, you would create a plugin for this. The manual has an explanation with an example for a custom appender here: http://logging.apache.org/log4j/2.x/manual/extending.html#Appenders
在 log4j2 中,您将为此创建一个插件。该手册有一个关于自定义附加程序示例的说明:http: //logging.apache.org/log4j/2.x/manual/extending.html#Appenders
It may be convenient to extend org.apache.logging.log4j.core.appender.AbstractAppender
, but this is not required.
扩展可能很方便org.apache.logging.log4j.core.appender.AbstractAppender
,但这不是必需的。
When you annotate your custom Appender class with @Plugin(name="MyCustomAppender", ....
, the plugin name becomes the configuration element name, so a configuration with your custom appender would then look like this:
当您使用 注释自定义 Appender 类时@Plugin(name="MyCustomAppender", ....
,插件名称将成为配置元素名称,因此带有自定义 Appender 的配置将如下所示:
<Configuration packages="com.yourcompany.yourcustomappenderpackage">
<Appenders>
<MyCustomAppender name="ABC" otherAttribute="...">
...
</Appenders>
<Loggers><Root><AppenderRef ref="ABC" /></Root></Loggers>
</Configuration>
Note that the packages
attribute on the configuration is a comma-separated list of all the packages with custom log4j2 plugins. Log4j2 will search these packages in the classpath for classes annotated with @Plugin.
请注意,packages
配置上的属性是以逗号分隔的所有带有自定义 log4j2 插件的包的列表。Log4j2 将在类路径中搜索这些包以查找用 @Plugin 注释的类。
Here is a sample custom appender that prints to the console:
这是打印到控制台的示例自定义 appender:
package com.yourcompany.yourcustomappenderpackage;
import java.io.Serializable;
import java.util.concurrent.locks.*;
import org.apache.logging.log4j.core.*;
import org.apache.logging.log4j.core.config.plugins.*;
import org.apache.logging.log4j.core.layout.PatternLayout;
// note: class name need not match the @Plugin name.
@Plugin(name="MyCustomAppender", category="Core", elementType="appender", printObject=true)
public final class MyCustomAppenderImpl extends AbstractAppender {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
protected MyCustomAppenderImpl(String name, Filter filter,
Layout<? extends Serializable> layout, final boolean ignoreExceptions) {
super(name, filter, layout, ignoreExceptions);
}
// The append method is where the appender does the work.
// Given a log event, you are free to do with it what you want.
// This example demonstrates:
// 1. Concurrency: this method may be called by multiple threads concurrently
// 2. How to use layouts
// 3. Error handling
@Override
public void append(LogEvent event) {
readLock.lock();
try {
final byte[] bytes = getLayout().toByteArray(event);
System.out.write(bytes);
} catch (Exception ex) {
if (!ignoreExceptions()) {
throw new AppenderLoggingException(ex);
}
} finally {
readLock.unlock();
}
}
// Your custom appender needs to declare a factory method
// annotated with `@PluginFactory`. Log4j will parse the configuration
// and call this factory method to construct an appender instance with
// the configured attributes.
@PluginFactory
public static MyCustomAppenderImpl createAppender(
@PluginAttribute("name") String name,
@PluginElement("Layout") Layout<? extends Serializable> layout,
@PluginElement("Filter") final Filter filter,
@PluginAttribute("otherAttribute") String otherAttribute) {
if (name == null) {
LOGGER.error("No name provided for MyCustomAppenderImpl");
return null;
}
if (layout == null) {
layout = PatternLayout.createDefaultLayout();
}
return new MyCustomAppenderImpl(name, filter, layout, true);
}
}
For more details on plugins: http://logging.apache.org/log4j/2.x/manual/plugins.html
有关插件的更多详细信息:http: //logging.apache.org/log4j/2.x/manual/plugins.html
If the manual is not enough, it may be useful to look at the source code for the built-in appenders in log4j-core.
如果手册还不够,查看 log4j-core 中内置 appender 的源代码可能会很有用。
回答by Javoslaw
It looks like plugin appenders are scanned at startup and cannot be added during runtime. Is that true?
看起来插件 appender 在启动时被扫描,不能在运行时添加。真的吗?
to add new appender while running you can use monitorInterval property to update log configuration i.e. every 60 sec:
要在运行时添加新的 appender,您可以使用 monitorInterval 属性来更新日志配置,即每 60 秒更新一次:
<Configuration monitorInterval="60">
回答by pppk520
For people need to output to TextArea, here is a working tweak
对于需要输出到 TextArea 的人,这是一个有效的调整
Make the TextArea static
使 TextArea 为静态
NetBeans Swing TextArea is not static, causes trouble
NetBeans Swing TextArea 不是静态的,会引起麻烦
Add static method in your Frame
在您的框架中添加静态方法
public class MyFrame extends javax.swing.JFrame {
...
public static void outputToTextArea(String message) {
jTextArea.append(message);
}
Call in Appender's append
调用 Appender 的 append
@Override
public void append(LogEvent event) {
final byte[] bytes = getLayout().toByteArray(event);
MyFrame.outputToTextArea(new String(bytes));
}
回答by joseph
As you pointed out AppenderSkeleton is not available anymore so the solutions in How to create my own Appender in log4j?will not work.
正如您所指出的 AppenderSkeleton 不再可用,因此如何在 log4j 中创建我自己的 Appender 中的解决方案?不管用。
Using Mockito, or similar library to create an Appender with an ArgumentCaptor will not work if you're expecting multiple logging messages because the MutableLogEvent is reused over multiple log messages.
如果您期望多个日志消息,则使用 Mockito 或类似库创建带有 ArgumentCaptor 的 Appender 将不起作用,因为 MutableLogEvent 在多个日志消息上重用。
The most generic solution I found for log4j2 is to provide a mock implementation that records all the messages. It does not require any additional libraries like Mockito or JMockit.
我为 log4j2 找到的最通用的解决方案是提供一个记录所有消息的模拟实现。它不需要任何额外的库,如 Mockito 或 JMockit。
private static MockedAppender mockedAppender;
private static Logger logger;
@Before
public void setup() {
mockedAppender.message.clear();
}
/**
* For some reason mvn test will not work if this is @Before, but in eclipse it works! As a
* result, we use @BeforeClass.
*/
@BeforeClass
public static void setupClass() {
mockedAppender = new MockedAppender();
logger = (Logger)LogManager.getLogger(ClassWithLoggingToTest.class);
logger.addAppender(mockedAppender);
logger.setLevel(Level.INFO);
}
@AfterClass
public static void teardown() {
logger.removeAppender(mockedAppender);
}
@Test
public void test() {
// do something that causes logs
for (String e : mockedAppender.message) {
// add asserts for the log messages
}
}
private static class MockedAppender extends AbstractAppender {
List<String> message = new ArrayList<>();
protected MockedAppender() {
super("MockedAppender", null, null);
}
@Override
public void append(LogEvent event) {
message.add(event.getMessage().getFormattedMessage());
}
}