web-dev-qa-db-ja.com

LogBackアペンダーをプログラムで構成する

Logback.xmlにログバックアペンダーが定義されています。これはDBアペンダーですが、Beanとして定義された独自の接続プールを使用してJavaにアペンダーを構成する方法があるかどうか興味があります。

私は同じようなものを見つけますが、実際の答えは決してありません。

63
user1732480

ここで私のために働く簡単な例(この例では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;
    }

}
106
reto

アペンダーはプログラムで構成できます。ほとんどすべてのアペンダーは、プログラム構成を使用してテストされます。したがって、logbackプロジェクトのソースコードには、プログラムによるアペンダー構成の多くの例があります。 logback-core appenderについては、logback-core/src/test/Java、およびlogback-classic appenderの場合はlogback-classic/src/test/Java

14
Ceki

参考として、ロガーの作成を担当するコードを変更しようとすると、ロガーが機能するために満たさなければならない一連のルールがあります。

これらのルールは、すばらしい役立つ記事で説明されていました slf4j/logbackのプログラム構成

現在、プログラムでslf4j/logbackを構成した経験があります。

タスク

プログラムは、処理された入力ファイルごとに個別のログファイルを開く必要があります。

タスクの解決策

Xml経由でlogbackを構成する代わりに、エンコーダ、アペンダー、ロガーを「手動で」インスタンス化し、それらを構成してリンクする必要があります。

注意1

Logbackは、アペンダー間でエンコーダー(PatternLayoutEncoder)を共有しようとすると夢中になります。

警告1の解決策

アペンダーごとに個別のエンコーダーを作成します。

警告2

エンコーダーとアペンダーがロギングコンテキストに関連付けられていない場合、Logbackは何も記録しません。

警告2の解決策

各エンコーダーとアペンダーでsetContextを呼び出し、LoggerFactoryをパラメーターとして渡します。

警告3

エンコーダーとアペンダーが開始されていない場合、Logbackは何も記録しません。

警告3の解決策

エンコーダーとアペンダーは正しい順序で起動する必要があります。つまり、最初にエンコーダー、次にアペンダーです。

警告4

RollingPolicyオブジェクト(つまり、TimeBasedRollingPolicy)は、アペンダーと同じコンテキストにアタッチされていない場合、「日付形式が認識されない」などの奇妙なエラーメッセージを生成します。

注意事項4の解決策

エンコーダーおよびアペンダーと同じ方法で、RollingPolicyでsetContextを呼び出します。

「手動」ログバック構成の動作例:

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);
  }
}
7
dominik

誰かがプログラムによる設定の具体例を探しているなら。

ここで、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ファイルはjar内に隠れているように見えます。ただし、パッケージを展開して変更すると便利ではありません。そして、私は必要ない app.jarの横にあるlogback.xmlファイル。 appのすべての構成プロパティを含むapp.yamlファイルのみがあります。

6
Yan Pak

コメントは許可されていません(まだですか?)。3つのヒントを追加したいと思います。

  • 上記の警告に関して、問題がある場合は、次の呼び出しを追加してください。

    _StatusPrinter.print(context);
    _

    すべてが設定された後、つまりアペンダーにルート/「メイン」アペンダーを追加した後:it will何が悪いのかを教えてくれます。

  • さまざまなファイルのログレベルを分離するのが大好きです。エラーを探すときは、まずエラーファイルなどを調べて、次のようにセットアップします。

_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);
        }
    }
_

私の新しいルートロガーレベルで。

0
Ola Aronsson