ログを Datadog に送信するには、ファイルにログを記録し、そのファイルを Datadog Agent でテールします。

一般的な Java ログのスタックトレースは複数の行に分割されているため、元のログイベントに関連付けることが困難です。例:

//1 つのはずのイベントに、4 つのイベントが生成される
Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

この問題を解決するには、ログを JSON 形式で生成するようにログライブラリを構成します。JSON にログすると、次のことができます。

  • スタックトレースがログイベントに適切にラップされることを確実にします。
  • すべてのログイベント属性 (重大度、ロガー名、スレッド名など) が適切に抽出されることを確実にします。
  • マップされた診断コンテキスト (MDC) 属性にアクセスできます。この属性は、任意のログイベントにアタッチできます。
  • カスタムパースルールが不要になります。

次の手順は、Log4j、Log4j 2、および Logback ログライブラリのセットアップ例を示しています。

ロガーの構成

JSON 形式

Log4j の場合、SLF4J モジュール log4j-over-slf4j を Logback と組み合わせて使用して JSON 形式でログします。log4j-over-slf4j は、アプリケーションの Log4j を完全に置き換えるため、コードを変更する必要はありません。これを使用するには

  1. pom.xml ファイルで、log4j.jar 依存関係を log4j-over-slf4j.jar 依存関係に置き換え、Logback 依存関係を追加します。

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>log4j-over-slf4j</artifactId>
      <version>1.7.32</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.9</version>
    </dependency>
    <dependency>
      <groupId>net.logstash.logback</groupId>
      <artifactId>logstash-logback-encoder</artifactId>
      <version>6.6</version>
    </dependency>
    
  2. logback.xml の JSON レイアウトを使用してアペンダーを構成します。

    ファイル:

    <configuration>
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/app.log</file>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
      </appender>
    
      <root level="INFO">
        <appender-ref ref="FILE"/>
      </root>
    </configuration>
    

    コンソール:

    <configuration>
      <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
          <encoder class="ch.qos.logback.classic.encoder.JsonEncoder"/>
      </appender>
    
      <root>
        <level value="DEBUG"/>
          <appender-ref ref="CONSOLE"/>
        </root>
    </configuration>
    

Log4j 2 には JSON レイアウトが含まれています。

  1. log4j2.xml の JSON レイアウトを使用してアペンダーを構成します。

    ファイルアペンダー:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
      <Appenders>
        <File name="FILE" fileName="logs/app.log" >
          <JSONLayout compact="true" eventEol="true" properties="true" stacktraceAsString="true" />
        </File>
      </Appenders>
    
      <Loggers>
        <Root level="INFO">
          <AppenderRef ref="FILE"/>
        </Root>
      </Loggers>
    </Configuration>
    

    コンソールアペンダー:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
    
        <Appenders>
            <Console name="console" target="SYSTEM_OUT">
                <JSONLayout compact="true" eventEol="true" properties="true" stacktraceAsString="true" />
            </Console>
        </Appenders>
    
        <Loggers>
            <Root level="INFO">
                <AppenderRef ref="console"/>
            </Root>
    
        </Loggers>
    </Configuration>
    
  2. JSON レイアウトの依存関係を pom.xml に追加します。

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.17.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.13.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.13.0</version>
    </dependency>
    

Logback の JSON 形式のログには、logstash-logback-encoder を使用します。

  1. logback.xml の JSON レイアウトを使用してファイルアペンダーを構成します。

    <configuration>
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/app.log</file>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
      </appender>
    
      <root level="INFO">
        <appender-ref ref="FILE"/>
      </root>
    </configuration>
    
  2. Logstash エンコーダの依存関係を pom.xml ファイルに追加します。

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.9</version>
    </dependency>
    <dependency>
      <groupId>net.logstash.logback</groupId>
      <artifactId>logstash-logback-encoder</artifactId>
      <version>6.6</version>
    </dependency>
    

Tinylog 公式ドキュメントに基づいて、JSON ライターの構成を作成します。

tinylog.properties ファイルには以下のフォーマットを使用します。

writer                     = json
writer.file                = log.json
writer.format              = LDJSON
writer.level               = info
writer.field.level         = level
writer.field.source        = {class}.{method}()
writer.field.message       = {message}
writer.field.dd.trace_id   = {context: dd.trace_id}
writer.field.dd.span_id    = {context: dd.span_id}
writer.field.dd.service    = {context: dd.service}
writer.field.dd.version    = {context: dd.version}
writer.field.dd.env        = {context: dd.env}

ログへのトレース ID の挿入

このアプリケーションで APM が有効になっている場合は、トレース ID インジェクションを有効にすることで、ログとトレースを相互に関連付けることができます。詳細については、Java ログとトレースの接続を参照してください。

未加工の形式

log4j.xml でファイルアペンダーを構成します。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>

  <appender name="FILE" class="org.apache.log4j.FileAppender">
    <param name="File" value="logs/app.log"/>
    <param name="Append" value="true"/>

    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %X{dd.trace_id} %X{dd.span_id} - %m%n"/>
    </layout>
  </appender>

  <root>
    <priority value="INFO"/>
    <appender-ref ref="FILE"/>
  </root>

</log4j:configuration>

log4j2.xml でファイルアペンダーを構成します。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <File name="FILE" fileName="logs/app.log">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %X{dd.trace_id} %X{dd.span_id} - %m%n"/>
    </File>
  </Appenders>

  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="FILE"/>
    </Root>
  </Loggers>
</Configuration>

logback.xml でファイルアペンダーを構成します。

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${dd.test.logfile}</file>
    <append>false</append>
    <immediateFlush>true</immediateFlush>

    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %X{dd.trace_id} %X{dd.span_id} - %m%n</pattern>
    </encoder>
  </appender>

  <root level="INFO">
    <appender-ref ref="FILE"/>
  </root>
</configuration>

Tinylog 公式ドキュメントに基づいて、ファイルに出力するライターの構成を作成します。

tinylog.properties ファイルには以下のフォーマットを使用します。

writer          = file
writer.level    = debug
writer.format   = {level} - {message} - "dd.trace_id":{context: dd.trace_id} - "dd.span_id":{context: dd.span_id}
writer.file     = log.txt

ログへのトレース ID の挿入

このアプリケーションで APM が有効になっている場合は、トレース ID インジェクションを有効にすることで、ログとトレースを相互に関連付けることができます。Java ログとトレースの接続を参照してください。

ログとトレースを相関させていない場合は、上記の構成例に含まれているログパターンから MDC プレースホルダー (%X{dd.trace_id} %X{dd.span_id}) を削除できます。

Datadog Agent の構成

ログ収集が有効になったら、ログファイルを追跡して Datadog に送信するカスタムログ収集を設定します。

  1. java.d/ フォルダーを conf.d/ Agent 構成ディレクトリに作成します。

  2. java.d/ に以下の内容で conf.yaml ファイルを作成します。

    #Log section
    logs:
    
      - type: file
        path: "<path_to_your_java_log>.log"
        service: <service_name>
        source: java
        sourcecategory: sourcecode
        # For multiline logs, if they start by the date with the format yyyy-mm-dd uncomment the following processing rule
        #log_processing_rules:
        #  - type: multi_line
        #    name: new_log_start_with_date
        #    pattern: \d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])
    
  3. Agent を再起動します

  4. Agent の status サブコマンドを実行し、Checks セクションで java を探し、ログが Datadog に正常に送信されることを確認します。

ログが JSON 形式の場合、Datadog は自動的にログメッセージをパースし、ログ属性を抽出します。ログエクスプローラーを使用して、ログを表示し、トラブルシューティングを行うことができます。

エージェントレスのログ収集

アクセスできない、またはファイルにログを記録できないマシンでアプリケーションが実行されている例外的なケースでは、ログを Datadog または Datadog Agent に直接ストリーミングすることができます。アプリケーションが接続の問題を処理する必要があるため、これは推奨される設定ではありません。

ログを Datadog に直接ストリーミングするには

  1. Logback ログライブラリをコードに追加するか、現在のロガーを Logback にブリッジします。
  2. Logback を構成して Datadog にログを送信します。

Java ロギングライブラリから Logback へのブリッジ

まだ Logback を使用していない場合、ほとんどの一般的なログライブラリは Logback にブリッジすることができます。

SLF4J モジュール log4j-over-slf4j を Logback とともに使用して、ログを別のサーバーに送信します。log4j-over-slf4j は、アプリケーションの Log4j を完全に置き換えるため、コードを変更する必要はありません。これを使用するには

  1. pom.xml ファイルで、log4j.jar 依存関係を log4j-over-slf4j.jar 依存関係に置き換え、Logback 依存関係を追加します。
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>log4j-over-slf4j</artifactId>
      <version>1.7.32</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.9</version>
    </dependency>
    <dependency>
      <groupId>net.logstash.logback</groupId>
      <artifactId>logstash-logback-encoder</artifactId>
      <version>6.6</version>
    </dependency>
    
  2. Logback を構成します。

注: この変更の結果、Log4j コンフィギュレーションファイルは使用されなくなります。Log4j トランスレーター を使用して log4j.properties ファイルを logback.xml に移行してください。

Log4j 2 では、リモートホストへのログ記録が可能ですが、ログの前に API キーを付ける機能はありません。このため、SLF4J モジュール log4j-over-slf4j と Logback を使用してください。log4j-to-slf4j.jar は、アプリケーションの Log4j 2 を完全に置き換えるため、コードを変更する必要はありません。これを使用するには

  1. pom.xml ファイルで、log4j.jar 依存関係を log4j-over-slf4j.jar 依存関係に置き換え、Logback 依存関係を追加します。
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-to-slf4j</artifactId>
        <version>2.17.1</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.9</version>
    </dependency>
    <dependency>
        <groupId>net.logstash.logback</groupId>
        <artifactId>logstash-logback-encoder</artifactId>
        <version>6.6</version>
    </dependency>
    
  2. Logback を構成します。

注:

Logback を構成する

logstash-logback-encoder ログライブラリを Logback と一緒に使用して、ログを Datadog に直接ストリーミングします。

  1. logback.xml ファイルに TCP アペンダーを構成します。この構成では、API キーは環境変数 DD_API_KEY から取得されます。あるいは、コンフィギュレーションファイルに直接 API キーを挿入することもできます。

    <configuration>
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/app.log</file>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
      </appender>
      <appender name="JSON_TCP" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>intake.logs.datadoghq.com:10516</destination>
        <keepAliveDuration>20 seconds</keepAliveDuration>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <prefix class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                <layout class="ch.qos.logback.classic.PatternLayout">
                    <pattern>${DD_API_KEY} %mdc{keyThatDoesNotExist}</pattern>
                </layout>
              </prefix>
        </encoder>
        <ssl />
      </appender>
    
      <root level="DEBUG">
        <appender-ref ref="FILE"/>
        <appender-ref ref="JSON_TCP" />
      </root>
    </configuration>
    

    <configuration>
      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/app.log</file>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
      </appender>
      <appender name="JSON_TCP" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>tcp-intake.logs.datadoghq.eu:443</destination>
        <keepAliveDuration>20 seconds</keepAliveDuration>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <prefix class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                <layout class="ch.qos.logback.classic.PatternLayout">
                    <pattern>${DD_API_KEY} %mdc{keyThatDoesNotExist}</pattern>
                </layout>
              </prefix>
        </encoder>
        <ssl />
      </appender>
    
      <root level="DEBUG">
        <appender-ref ref="FILE"/>
        <appender-ref ref="JSON_TCP" />
      </root>
    </configuration>
    

    サポートされていません。

    注: XML コンフィギュレーションで空白が削除されるため、%mdc{keyThatDoesNotExist} が追加されます。プレフィックスパラメータの詳細については、Logback ドキュメントを参照してください。

  2. Logstash エンコーダの依存関係を pom.xml ファイルに追加します。

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.9</version>
    </dependency>
    <dependency>
      <groupId>net.logstash.logback</groupId>
      <artifactId>logstash-logback-encoder</artifactId>
      <version>6.6</version>
    </dependency>
    

補足説明

ログイベントをコンテキスト属性で補完することができます。

キー値パーサーの使用

キー値パーサーは、ログイベント内で認識された <KEY>=<VALUE> パターンを抽出します。

Java のログイベントを補完するには、コードでメッセージを書き直し、<キー>=<値> のシーケンスを挿入します。

たとえば、次のメッセージがあるとします。

logger.info("Emitted 1001 messages during the last 93 seconds for customer scope prod30");

これを次のように変更します。

logger.info("Emitted quantity=1001 messages during the last durationInMs=93180 ms for customer scope=prod30");

キー値パーサーを有効にすると、各ペアが JSON から抽出されます。

{
  "message": "Emitted quantity=1001 messages during the last durationInMs=93180 ms for customer scope=prod30",
  "scope": "prod30",
  "durationInMs": 93180,
  "quantity": 1001
}

これで、scope をフィールド、durationInMs と quantity をログメジャーとして利用できます。

MDC

ログを補完するもう 1 つの方法として、Java の マップされた診断コンテキスト (MDC) の利用があります。

SLF4J を使用する場合は、次の Java コードを使用してください。

...
MDC.put("scope", "prod30");
logger.info("Emitted 1001 messages during the last 93 seconds");
...

この JSON を生成するには

{
  "message": "過去 93 秒間に 1001 メッセージを送信",
  "scope": "prod30"
}

注: MDC は文字列タイプのみを許可するため、数値メトリクスには使用しないでください。

その他の参考資料