このリンクで説明されているように: log4jで独自のアペンダーを作成する方法
Log4j 1.xでカスタムアペンダーを作成するには、AppenderSkeletonクラスを拡張し、そのappendメソッドを実装する必要があります。
同様に、拡張するAppenderSkeltonクラスや他のすべてのアペンダーがAppenderBaseクラスを拡張しないため、log4j2でカスタムアペンダーを作成する方法。
これは、log4j2とlog4j-1.2での動作がまったく異なります。
Log4j2では、このためのプラグインを作成します。マニュアルには、カスタムアペンダーの例の説明があります: http://logging.Apache.org/log4j/2.x/manual/extending.html#Appenders
org.Apache.logging.log4j.core.appender.AbstractAppender
を拡張すると便利かもしれませんが、これは必須ではありません。
カスタムAppenderクラスに@Plugin(name="MyCustomAppender", ....
アノテーションを付けると、プラグイン名が構成要素名になるため、カスタムアペンダーを使用した構成は次のようになります。
<Configuration packages="com.yourcompany.yourcustomappenderpackage">
<Appenders>
<MyCustomAppender name="ABC" otherAttribute="...">
...
</Appenders>
<Loggers><Root><AppenderRef ref="ABC" /></Root></Loggers>
</Configuration>
構成のpackages
属性は、カスタムlog4j2プラグインを含むすべてのパッケージのコンマ区切りリストであることに注意してください。 Log4j2は、@ Pluginアノテーションが付けられたクラスのクラスパスでこれらのパッケージを検索します。
コンソールに出力するカスタムアペンダーのサンプルを次に示します。
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);
}
}
プラグインの詳細: http://logging.Apache.org/log4j/2.x/manual/plugins.html
マニュアルが十分でない場合は、log4j-coreの組み込みアペンダーのソースコードを調べると役立つ場合があります。
プラグインアペンダーは起動時にスキャンされ、実行時に追加できないようです。本当?
実行中に新しいアペンダーを追加するには、monitorIntervalプロパティを使用してログ構成を更新します(60秒ごと)。
<Configuration monitorInterval="60">
TextAreaに出力する必要がある人のために、ここで機能するTweakを紹介します。
TextAreaを静的にします
NetBeans Swing TextAreaは静的ではないため、問題が発生します
フレームに静的メソッドを追加します
public class MyFrame extends javax.swing.JFrame {
...
public static void outputToTextArea(String message) {
jTextArea.append(message);
}
アペンダーのアペンドで呼び出す
@Override
public void append(LogEvent event) {
final byte[] bytes = getLayout().toByteArray(event);
MyFrame.outputToTextArea(new String(bytes));
}
あなたが指摘したように、AppenderSkeletonはもう利用できないので、 log4jで独自のAppenderを作成する方法 のソリューションは機能しません。
MutableLogEventは複数のログメッセージで再利用されるため、複数のログメッセージが予想される場合、Mockitoまたは同様のライブラリを使用してArgumentCaptorでAppenderを作成することはできません。
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());
}
}