Подтвердить что ты не робот

Программно настроить приложение LogBack

У меня есть приложение logback, определенное в logback.xml, это приложение DB, но мне любопытно, есть ли способ настроить appender в java, используя мой собственный пул соединений, определенный как bean.

Я нахожу похожие вещи, но не фактический ответ.

4b9b3361

Ответ 1

Вот простой пример, который работает для меня (обратите внимание, что я использую FileAppender в этом примере)

import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;

public class Loggerutils {

    public static void main(String[] args) {
          Logger foo = createLoggerFor("foo", "foo.log");
          Logger bar = createLoggerFor("bar", "bar.log");
          foo.info("test");
          bar.info("bar");
    }

    private static Logger createLoggerFor(String string, String file) {
          LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
          PatternLayoutEncoder ple = new PatternLayoutEncoder();

          ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
          ple.setContext(lc);
          ple.start();
          FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>();
          fileAppender.setFile(file);
          fileAppender.setEncoder(ple);
          fileAppender.setContext(lc);
          fileAppender.start();

          Logger logger = (Logger) LoggerFactory.getLogger(string);
          logger.addAppender(fileAppender);
          logger.setLevel(Level.DEBUG);
          logger.setAdditive(false); /* set to true if root should log too */

          return logger;
    }

}

Ответ 2

Программные приложения можно настроить программно. Почти все приставки тестируются с использованием программной конфигурации. Из этого следует, что в исходном коде проекта logback имеется много примеров конфигурации программных приложений. Для приложения с поддержкой logback-core найдите под logback-core/src/test/java, а для журнала-классического appender - под logback-classic/src/test/java.

Ответ 3

Просто, если кто-то будет искать конкретный пример программной конфигурации.

Здесь я настраиваю кодировку ConsoleAppender:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
ConsoleAppender<ILoggingEvent> appender =
    (ConsoleAppender) lc.getLogger("appconsole").getAppender("STDOUT");
LayoutWrappingEncoder<ILoggingEvent> enc = 
    (LayoutWrappingEncoder<ILoggingEvent>) appender.getEncoder();
enc.setCharset(Charset.forName("utf-8"));

И мой logback.xml:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <charset>866</charset>
        <pattern>[%level] %msg%n</pattern>
    </encoder>
</appender>

<logger name="appconsole">
    <appender-ref ref="STDOUT" />
</logger>

Почему мне нужно программировать конфигурацию регистратора? Потому что я упаковываю свое приложение (Spring Boot) в файл jar. Следовательно, файл Logback.xml кажется скрытым внутри банки. Хотя, неудобно распаковывать и изменять его. И мне не нужен любой файл logback.xml рядом с моим app.jar. У меня есть только файл app.yaml, который содержит все свойства конфигурации для приложения.

Ответ 4

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

Эти правила были описаны в большой и полезной статье Программная конфигурация slf4j/logback:

Теперь у меня есть опыт программирования программной конфигурации slf4j/logback.

Task

Программа должна открыть отдельный файл журнала для каждого обработанного входного файла.

Решение задачи

Вместо того, чтобы настраивать logback через xml, нужно "вручную" создавать экземпляры кодировщиков, добавок и журналов, а затем настраивать и связывать их вместе.

Предостережение 1

Сбой при регистрации происходит при попытке совместного использования кодировщика (т.е. PatternLayoutEncoder) между приложением.

Решение для оговорки 1

Создайте отдельный кодер для каждого приложения.

Caveat 2

Резервирование отказывается записывать что-либо, если кодеры и приложения не связаны с протоколом ведения журнала.

Решение для оговорки 2

Вызов setContext для каждого кодировщика и приложения, проходящего через LoggerFactory как параметр.

Caveat 3

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

Решение для оговорки 3

Кодеры и апплеты

должны быть запущены в правильном порядке, то есть первые кодеры, а затем приложения.

Caveat 4

Объекты RollingPolicy (т.е. TimeBasedRollingPolicy) создают странные сообщения об ошибках, такие как "формат даты не распознается", если они не привязаны к тому же контексту, что и appender.

Решение для оговорки 4

вызов setContext на RollingPolicy так же, как и для кодеров и добавок.

Вот рабочий пример конфигурации "ручного" журнала:

package testpackage

import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.rolling.RollingFileAppender
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy

import org.slf4j.LoggerFactory

class TestLogConfig {

  public static void main(String[] args) {
    LoggerContext logCtx = LoggerFactory.getILoggerFactory()

    PatternLayoutEncoder logEncoder = new PatternLayoutEncoder()
    logEncoder.setContext(logCtx)
    logEncoder.setPattern('%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level - %msg%n')
    logEncoder.start()

    ConsoleAppender logConsoleAppender = new ConsoleAppender()
    logConsoleAppender.setContext(logCtx)
    logConsoleAppender.setName('console')
    logConsoleAppender.setEncoder(logEncoder)
    logConsoleAppender.start()

    logEncoder = new PatternLayoutEncoder()
    logEncoder.setContext(logCtx)
    logEncoder.setPattern('%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level - %msg%n')
    logEncoder.start()

    RollingFileAppender logFileAppender = new RollingFileAppender()
    logFileAppender.setContext(logCtx)
    logFileAppender.setName('logFile')
    logFileAppender.setEncoder(logEncoder)
    logFileAppender.setAppend(true)
    logFileAppender.setFile('logs/logfile.log')

    TimeBasedRollingPolicy logFilePolicy = new TimeBasedRollingPolicy()
    logFilePolicy.setContext(logCtx)
    logFilePolicy.setParent(logFileAppender)
    logFilePolicy.setFileNamePattern('logs/logfile-%d{yyyy-MM-dd_HH}.log')
    logFilePolicy.setMaxHistory(7)
    logFilePolicy.start()

    logFileAppender.setRollingPolicy(logFilePolicy)
    logFileAppender.start()

    Logger log = logCtx.getLogger("Main")
    log.additive = false
    log.level = Level.INFO
    log.addAppender(logConsoleAppender)
    log.addAppender(logFileAppender)
  }
}

Ответ 5

Не разрешено комментировать (пока?), я просто хотел бы добавить три подсказки;

  • относительно предостережений выше, если у вас есть проблемы, просто добавьте вызов

    StatusPrinter.print(context);
    

    после того, как все настроено, то есть после добавления добавляет root/ "Main" appender: он скажет вам, что не так.

  • Мне очень нравится разделять уровни ведения журналов в разных файлах; при поиске ошибок я начинаю с поиска в файле ошибки и т.д., установив их как

tot_[app name].log   : Level.INFO
deb_[app name].log   : Level.DEBUG
err_[app name].log   : Level.ERROR

с помощью простого частного класса фильтра, такого как

    private static class ThresholdLoggerFilter extends Filter<ILoggingEvent> {

        private final Level level;

        private ThresholdLoggerFilter(Level level){
            this.level = level;
        }

        @Override
        public FilterReply decide(ILoggingEvent event) {
            if (event.getLevel().isGreaterOrEqual(level)) {
                return FilterReply.NEUTRAL;
            } else {
                return FilterReply.DENY;
            }
        }
    }

а затем просто вызовите myFilter.start() и myAppender.addFilter(myFilter);.

  • Наконец, я собираюсь собрать все вместе, я обычно хочу, чтобы динамически менял уровни журналов, имея в настройке какой-нибудь простой интерфейс, например

    public interface LoggingService {
        void setRootLogLevel(Level level);
    }
    

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

    @Override
    public void setRootLogLevel(Level level) {
        if (context != null && context.isStarted()) {
        ((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(level);
        }
    }

с моим новым уровнем корневого регистратора.