Отдельная регистрация ошибок в Log4j 2

1

Log4j 2 позволяет включать информацию о классе и строке в записи журнала. Однако авторы утверждают, что для создания записи требуется 4-5 раз больше времени.

99,5% моего журнала состоит из обычных рабочих записей (информация), где строка и класс действительно не нужны. Интересно, есть ли способ настроить log4j 2, что он включает только файл, класс и строку в записи с "предупреждением" или более высоким уровнем?

Теги:
logging
configuration
log4j2

2 ответа

2
Лучший ответ

Начиная с RC2, Log4j2 не предоставляет такую функцию. Для этого вы можете вызвать запрос функции на log4j2 Jira.

Между тем, контроль, который у вас есть, включать или отключать информацию о местоположении, зависит от каждого регистратора. Таким образом, одна идея может заключаться в том, чтобы иметь один системный регистратор уровня FATAL, который настроен с includeLocation="true".

Пример конфигурационного фрагмента:

  ...
  <Loggers>
    <AsyncLogger name="FATAL_LOGGER" level="fatal" includeLocation="true" additivity="false">
      <AppenderRef ref="someAppender"/>
    </AsyncLogger>
    <Root level="trace" includeLocation="false">
      <AppenderRef ref="someAppender"/>
    </Root>
  </Loggers>
</Configuration>

Пример использования:

public class MyApp {
  private static final Logger logger = LogManager.getLogger(MyApp.class);

  public void someMethod(int value) {
    // normal trace-level logging does not include location info
    logger.trace("Doing some work with param {}", value);
    try {
      callAnotherMethod();
    } catch (Throwable t) {
      // use the shared fatal logger to include location info
      LogManager.getLogger("FATAL_LOGGER").fatal("Unexpected error", t);
    }
  }
}
3

Кажется, что это не поддерживается. Однако вы можете использовать собственную реализацию фильтра и 2 приложения для архивирования желаемого результата.

Каждый appender выводит только диапазон уровней, а приложение для более крупных событий может добавлять номера строк. Журналу необходимо использовать оба приложения, чтобы избавить вас от обработки различия в коде, который регистрируется:

// Will have line numbers in output.
LogManager.getLogger().error("bla");
// Won't have line numbers in output.
LogManager.getLogger().info("blub");

Конфигурация Log4j 2 похожа на (note %line для ConsoleMoreSevere):

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="yield.log4j2">
    <Appenders>
        <Console name="ConsoleLessSevere" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger{36} - %msg%n" />
            <LevelRangeFilter maxLevel="INFO"/>
        </Console>
        <Console name="ConsoleMoreSevere" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger{36}:%line - %msg%n" />
            <LevelRangeFilter minLevel="WARN"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="WARN">
            <AppenderRef ref="ConsoleLessSevere" />
            <AppenderRef ref="ConsoleMoreSevere" />
        </Root>
    </Loggers>
</Configuration>

Это оставляет необходимость определить реализацию пользовательского фильтра, называемую yield.log4j2.LevelRangeFilter в моем примере. Реализация моделируется после примера в документации Log4j 2 и может быть найдена с https://github.com/AugustusKling/yield/blob/master/src/main/java/yield/log4j2/LevelRangeFilter.java. Не стесняйтесь копировать класс.

Чтобы сделать этот ответ полным без внешних источников, выполняется реализация LevelRangeFilter:

package yield.log4j2;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
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;

/**
 * Filters log events within given bounds.
 */
@Plugin(name = "LevelRangeFilter", category = "Core", elementType = "filter", printObject = true)
public class LevelRangeFilter extends AbstractFilter {
    private final Level minLevel;
    private final Level maxLevel;

    private LevelRangeFilter(final Level minLevel, final Level maxLevel,
            final Result onMatch, final Result onMismatch) {
        super(onMatch, onMismatch);
        this.minLevel = minLevel;
        this.maxLevel = maxLevel;
    }

    @Override
    public Result filter(final Logger logger, final Level level,
            final Marker marker, final String msg, final Object... params) {
        return filter(level);
    }

    @Override
    public Result filter(final Logger logger, final Level level,
            final Marker marker, final Object msg, final Throwable t) {
        return filter(level);
    }

    @Override
    public Result filter(final Logger logger, final Level level,
            final Marker marker, final Message msg, final Throwable t) {
        return filter(level);
    }

    @Override
    public Result filter(final LogEvent event) {
        return filter(event.getLevel());
    }

    private Result filter(final Level level) {
        if (maxLevel.intLevel() <= level.intLevel()
                && minLevel.intLevel() >= level.intLevel()) {
            return onMatch;
        } else {
            return onMismatch;
        }
    }

    /**
     * @param minLevel
     *            Minimum log Level.
     * @param maxLevel
     *            Maximum log level.
     * @param onMatch
     *            Action to take on a match.
     * @param onMismatch
     *            Action to take on a mismatch.
     * @return The created filter.
     */
    @PluginFactory
    public static LevelRangeFilter createFilter(
            @PluginAttribute(value = "minLevel", defaultString = "TRACE") final Level minLevel,
            @PluginAttribute(value = "maxLevel", defaultString = "FATAL") final Level maxLevel,
            @PluginAttribute(value = "onMatch", defaultString = "NEUTRAL") final Result onMatch,
            @PluginAttribute(value = "onMismatch", defaultString = "DENY") final Result onMismatch) {
        return new LevelRangeFilter(minLevel, maxLevel, onMatch, onMismatch);
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню