Как создать собственное приложение в log4j2?


person saurabh goyal    schedule 13.06.2014    source источник


Ответы (3)


Это работает совершенно иначе в log4j2, чем в log4j-1.2.

В log4j2 вы должны создать для этого плагин. В руководстве есть объяснение с примером настраиваемого приложения здесь: http://logging.apache.org/log4j/2.x/manual/exnding.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.

person Remko Popma    schedule 14.06.2014
comment
Похоже, дополнения плагинов сканируются при запуске и не могут быть добавлены во время выполнения. Это правда? Если это так, это не отвечает на вопрос о том, как программно изменить поведение Log4J 2. - person ingyhere; 18.10.2014
comment
@ingyhere Программная настройка Log4j2 действительно отдельный вопрос. Эта страница руководства log4j2 может стать хорошей отправной точкой для получения дополнительных сведений: logging.apache.org/log4j/2.x/manual/ В противном случае вы можете задать новый вопрос. - person Remko Popma; 18.10.2014
comment
@Remko Я немного сбит с толку, тогда как он будет обнаружен как консольный аппендер, файловый аппендер и т. Д. В качестве примера, если я хочу печатать в консоли с помощью специального приложения, как я могу это сделать? Спасибо! - person Grant; 19.05.2015
comment
Это очень помогает, я хочу отправлять журналы в веб-службы. Тогда что я могу сделать. Спасибо Ремко - person madhu; 28.05.2015
comment
@Remko Почему нам нужно использовать метод блокировки и разблокировки readLock внутри метода doAppend пользовательского приложения? Какую цель он здесь выполняет? - person Aman; 06.06.2017
comment
Блокировка не требуется, если реализация макета является потокобезопасной (большинство, если не все встроенные макеты Log4j2 являются потокобезопасными). - person Remko Popma; 07.06.2017
comment
@RemkoPopma Не могли бы вы уточнить, как реализация макета является потокобезопасной? В настоящее время мы используем log4j PatternLayout в нашей реализации. Более того, делает ли использование метода блокировки и разблокировки readLock внутри метода doAppend его синхронность, т.е. только один поток может писать в приложение одновременно? - person Aman; 07.06.2017
comment
PatternLayout в Log4j2 является потокобезопасным и не требует блокировки. Да, использование блокировки делает приложение синхронным. Если ваш appender записывает полученные байты в какое-то потокобезопасное место назначения, то вашему appender не нужно выполнять блокировку. - person Remko Popma; 08.06.2017
comment
@Aman нескольким потокам разрешено получить одну и ту же блокировку чтения. Поскольку ничто никогда не получает связанную блокировку записи, эти вызовы lock / unlock ничего не делают. Этот код не является потокобезопасным, и несколько потоков могут выполнять защищенный код одновременно. - person Daniel Yankowsky; 08.06.2017
comment
createAppender () устарел в 2.7, может ли кто-нибудь добавить пример @PluginBuilderFactory - person teknopaul; 02.11.2017
comment
как насчет slf4j? - person Shilan; 19.06.2018
comment
@RemkoPopma: как насчет методов vosid start () и void stop () из интерфейса LifeCycle. Когда они называются? Я спрашиваю, так как для меня stop () очень важен, так как мне нужно освободить некоторые ресурсы (не память). Кроме того, я вижу, что мой Appender создается 3 раза при запуске и каждый раз, когда у него другая конфигурация, поэтому мне нужно остановить предыдущий экземпляр и запустить новый. - person Seweryn Habdank-Wojewódzki; 05.07.2018
comment
@ SewerynHabdank-Wojewódzki Может быть лучше спросить в списке рассылки пользователей Log4j или поднять заявку JIRA, если трижды создаваемый Appender выглядит как ошибка. - person Remko Popma; 05.07.2018
comment
@RemkoPopma спасибо за сообщение. Для людей, ищущих ответ, я обновил большое приложение с log4j v1 до v2, и мне нужно было изменить поведение RollingFileAppender, чтобы выполнять некоторые дополнительные действия при запуске. Для этого нужно было клонировать предоставленный класс RollingFileAppender и написать в нем то, что мне было нужно. Их предоставленный класс является последним, поэтому не может быть расширен. - person cbaldan; 18.06.2020
comment
@cbaldan, рад слышать, что это помогло. Обратите внимание: если вам нужно только что-то записать в файл при ролловере, PatternLayout имеет атрибуты header и footer, которые могут быть полезны. Но может быть полезно поднять тему настраиваемых действий в списке рассылки log4j-dev. - person Remko Popma; 19.06.2020

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

чтобы добавить новое приложение во время работы, вы можете использовать свойство monitorInterval для обновления конфигурации журнала, то есть каждые 60 секунд:

    <Configuration monitorInterval="60">
person Javoslaw    schedule 13.10.2016
comment
Вы можете программно добавить Appender, но если monitorInterval установлен, то добавленный appender будет утерян, если в файл конфигурации будут внесены изменения. - person rgoers; 14.10.2016

Как вы отметили, AppenderSkeleton больше не доступен, поэтому решения в Как создать мой собственный Appender в log4j? работать не будет.

Использование Mockito или аналогичной библиотеки для создания Appender с ArgumentCaptor не будет работать, если вы ожидаете нескольких сообщений журнала, потому что MutableLogEvent повторно используется для нескольких сообщений журнала.

Самое общее решение, которое я нашел для 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());
    }
}
person joseph    schedule 15.04.2019