The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

ログの一元管理(Graylog、Logstash、Fluentd)

このガイドでは、Graylog、Logstash(Elastic StackやELK - Elasticsearch、Logstash、Kibanaの内部)、Fluentd(EFK - Elasticsearch、Fluentd、Kibanaの内部)のような集中型ログ管理システムにログを送信する方法を説明します。

ログを一元化する方法はたくさんあります(Kubernetesを使用している場合、最も簡単な方法はコンソールにログインして、クラスター管理者にクラスター内に一元化されたログマネージャーを統合するように依頼することです)。このガイドでは、TCPまたはUDPを使用してGraylog Extended Log Format (GELF)でログを送信できる quarkus-logging-gelf エクステンションを使用して外部ツールに送信する方法を公開します。

quarkus-logging-gelf エクステンションは、Quarkusが使用する基礎となるロギングバックエンド(jboss-logmanager)にGELFログハンドラーを追加します。デフォルトでは無効になっており、有効にした場合も別のハンドラーも使用している場合(デフォルトではコンソールハンドラーが有効になっています)、ログは両方のハンドラーに送信されます。

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 17+がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.9.9

  • Docker と Docker Compose、または Podman 、および Docker Compose

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

アプリケーション例

以下の例はすべて、以下の手順で作成できる同じアプリケーションの例を基にしています。

quarkus-logging-gelf のエクステンションを持つアプリケーションを作成します。以下のコマンドで作成することができます:

コマンドラインインタフェース
quarkus create app org.acme:gelf-logging \
    --extension='rest,logging-gelf' \
    --no-code
cd gelf-logging

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.17.2:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=gelf-logging \
    -Dextensions='rest,logging-gelf' \
    -DnoCode
cd gelf-logging

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=gelf-logging"

すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに logging-gelf エクステンションを追加することができます。

コマンドラインインタフェース
quarkus extension add logging-gelf
Maven
./mvnw quarkus:add-extension -Dextensions='logging-gelf'
Gradle
./gradlew addExtension --extensions='logging-gelf'

これにより、ビルドファイルに以下の依存関係が追加されます:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-logging-gelf</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-logging-gelf")

デモのために、文をログに記録するだけのエンドポイントを作成します。これをアプリケーション内で行う必要はありません。

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.jboss.logging.Logger;

@Path("/gelf-logging")
@ApplicationScoped
public class GelfLoggingResource {
    private static final Logger LOG = Logger.getLogger(GelfLoggingResource.class);

    @GET
    public void log() {
        LOG.info("Some useful log message");
    }

}

GELF ログハンドラーを構成して、ポート 12201 の外部 UDP エンドポイントにログを送信します:

quarkus.log.handler.gelf.enabled=true
quarkus.log.handler.gelf.host=localhost
quarkus.log.handler.gelf.port=12201

ログをGraylogに送信

Graylogにログを送信するには、まずGraylogスタックを構成するコンポーネントを起動する必要があります:

  • MongoDB

  • Elasticsearch

  • Graylog

これは、以下の docker-compose.yml ファイルから、 docker-compose up -d で起動できます:

version: '3.2'

services:
  elasticsearch:
    image: docker.io/elastic/elasticsearch:8.15.0
    ports:
      - "9200:9200"
    environment:
      ES_JAVA_OPTS: "-Xms512m -Xmx512m"
      discovery.type: "single-node"
      cluster.routing.allocation.disk.threshold_enabled: false
    networks:
      - graylog

  mongo:
    image: mongo:4.0
    networks:
      - graylog

  graylog:
    image: graylog/graylog:4.3.0
    ports:
      - "9000:9000"
      - "12201:12201/udp"
      - "1514:1514"
    environment:
      GRAYLOG_HTTP_EXTERNAL_URI: "http://127.0.0.1:9000/"
      # CHANGE ME (must be at least 16 characters)!
      GRAYLOG_PASSWORD_SECRET: "forpasswordencryption"
      # Password: admin
      GRAYLOG_ROOT_PASSWORD_SHA2: "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918"
    networks:
      - graylog
    depends_on:
      - elasticsearch
      - mongo

networks:
  graylog:
    driver: bridge

次に、GraylogでUDP入力を作成する必要があります。これは、http://localhost:9000 の GraylogのWebコンソール(System → Input → Select GELF UDP)から、 またはAPI経由で行うことができます。

この curl の例では、Graylog (admin/admin) からのデフォルトのログインを使用し、GELF UDP タイプの新しい入力を作成します。

curl -H "Content-Type: application/json" -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "X-Requested-By: curl" -X POST -v -d \
'{"title":"udp input","configuration":{"recv_buffer_size":262144,"bind_address":"0.0.0.0","port":12201,"decompress_size_limit":8388608},"type":"org.graylog2.inputs.gelf.udp.GELFUDPInput","global":true}' \
http://localhost:9000/api/system/inputs

アプリケーションを起動すると、Graylog内にログが届くのがわかるはずです。

Logstash / Elastic Stack (ELK)にログを送信

LogstashにはGELF形式を理解できるInputプラグインがデフォルトで入ってるので、まずこのプラグインを有効にするパイプラインを作成します。

$HOME/pipelines/gelf.conf に以下のファイルを作成します。

input {
  gelf {
    port => 12201
  }
}
output {
  stdout {}
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
  }
}

最後に、Elastic Stackを構成するコンポーネントを起動します:

  • Elasticsearch

  • Logstash

  • Kibana

これは、以下の docker-compose.yml ファイルから、 docker-compose up -d で起動できます:

# Launch Elasticsearch
version: '3.2'

services:
  elasticsearch:
    image: docker.io/elastic/elasticsearch:8.15.0
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      ES_JAVA_OPTS: "-Xms512m -Xmx512m"
      discovery.type: "single-node"
      cluster.routing.allocation.disk.threshold_enabled: false
    networks:
      - elk

  logstash:
    image: docker.io/elastic/logstash:8.15.0
    volumes:
      - source: $HOME/pipelines
        target: /usr/share/logstash/pipeline
        type: bind
    ports:
      - "12201:12201/udp"
      - "5000:5000"
      - "9600:9600"
    networks:
      - elk
    depends_on:
      - elasticsearch

  kibana:
    image: docker.io/elastic/kibana:8.15.0
    ports:
      - "5601:5601"
    networks:
      - elk
    depends_on:
      - elasticsearch

networks:
  elk:
    driver: bridge

アプリケーションを起動すると、Elastic Stack内にログが届いているのが確認できるはずです。 http://localhost:5601/ で利用できるKibanaを使って、ログにアクセスすることができます。

GELF alternative: Send logs to Logstash in the ECS (Elastic Common Schema) format

You can also send your logs to Logstash using a TCP input in the ECS format. To achieve this we will use the quarkus-logging-json extension to format the logs in JSON format and the socket handler to send them to Logstash.

For this you can use the same docker-compose.yml file as above but with a different Logstash pipeline configuration.

input {
  tcp {
    port => 4560
    coded => json
  }
}

filter {
  if ![span][id] and [mdc][spanId] {
    mutate { rename => { "[mdc][spanId]" => "[span][id]" } }
  }
  if ![trace][id] and [mdc][traceId] {
    mutate { rename => {"[mdc][traceId]" => "[trace][id]"} }
  }
}

output {
  stdout {}
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
  }
}

Then configure your application to log in JSON format instead of GELF

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-logging-json</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-logging-json")

and specify the host and port of your Logstash endpoint. To be ECS compliant, specify the log format.

# to keep the logs in the usual format in the console
quarkus.log.console.json=false

quarkus.log.socket.enable=true
quarkus.log.socket.json=true
quarkus.log.socket.endpoint=localhost:4560

# to have the exception serialized into a single text element
quarkus.log.socket.json.exception-output-type=formatted

# specify the format of the produced JSON log
quarkus.log.socket.json.log-format=ECS

Fluentd(EFK)へのログ送信

まず、必要なプラグインである elasticsearch と input-elf を使って Fluentd イメージを作成します。 以下の Dockerfile を使用することができます。このファイルは fluentd ディレクトリー内に作成する必要があります。

FROM fluent/fluentd:v1.3-debian
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--version", "3.7.0"]
RUN ["gem", "install", "fluent-plugin-input-gelf", "--version", "0.3.1"]

イメージをビルドするか、docker-composeにビルドを任せることができます。

次に、$HOME/fluentd/fluent.conf の中にfluentd 設定ファイルを作成する必要があります

<source>
  type gelf
  tag example.gelf
  bind 0.0.0.0
  port 12201
</source>

<match example.gelf>
  @type elasticsearch
  host elasticsearch
  port 9200
  logstash_format true
</match>

最後に、EFKスタックを構成するコンポーネントを起動します:

  • Elasticsearch

  • Fluentd

  • Kibana

これは、以下の docker-compose.yml ファイルから、 docker-compose up -d で起動できます:

version: '3.2'

services:
  elasticsearch:
    image: docker.io/elastic/elasticsearch:8.15.0
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      ES_JAVA_OPTS: "-Xms512m -Xmx512m"
      discovery.type: "single-node"
      cluster.routing.allocation.disk.threshold_enabled: false
    networks:
      - efk

  fluentd:
    build: fluentd
    ports:
      - "12201:12201/udp"
    volumes:
      - source: $HOME/fluentd
        target: /fluentd/etc
        type: bind
    networks:
      - efk
    depends_on:
      - elasticsearch

  kibana:
    image: docker.io/elastic/kibana:8.15.0
    ports:
      - "5601:5601"
    networks:
      - efk
    depends_on:
      - elasticsearch

networks:
  efk:
    driver: bridge

アプリケーションを起動すると、EFK内にログが到着しているのが確認できるはずです: それらにアクセスするには、 http://localhost:5601/ で利用可能な Kibana を使用することができます。

GELFの代替:Syslogの使用

Syslog入力を使ってFluentdにログを送ることもできます。GELF入力とは対照的に、Syslog入力は1つのイベントで複数行のログをレンダリングすることができないため、Quarkusで実装されているGELF入力を使用することをお勧めします。

まず、elasticsearchプラグインでFluentdイメージを作成する必要があります。 以下の Dockerfile を使用することができます。このファイルは fluentd ディレクトリー内に作成する必要があります。

FROM fluent/fluentd:v1.3-debian
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--version", "3.7.0"]

次に、fluentd設定ファイルを $HOME/fluentd/fluent.conf 内に作成する必要があります

<source>
  @type syslog
  port 5140
  bind 0.0.0.0
  message_format rfc5424
  tag system
</source>

<match **>
  @type elasticsearch
  host elasticsearch
  port 9200
  logstash_format true
</match>

次に、EFKスタックを構成するコンポーネントを起動します:

  • Elasticsearch

  • Fluentd

  • Kibana

これは、以下の docker-compose.yml ファイルから、 docker-compose up -d で起動できます:

version: '3.2'

services:
  elasticsearch:
    image: docker.io/elastic/elasticsearch:8.15.0
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      ES_JAVA_OPTS: "-Xms512m -Xmx512m"
      discovery.type: "single-node"
      cluster.routing.allocation.disk.threshold_enabled: false
    networks:
      - efk

  fluentd:
    build: fluentd
    ports:
      - "5140:5140/udp"
    volumes:
      - source: $HOME/fluentd
        target: /fluentd/etc
        type: bind
    networks:
      - efk
    depends_on:
      - elasticsearch

  kibana:
    image: docker.io/elastic/kibana:8.15.0
    ports:
      - "5601:5601"
    networks:
      - efk
    depends_on:
      - elasticsearch

networks:
  efk:
    driver: bridge

最後に、Syslogを使用してEFKにログを送信するようにアプリケーションを設定します:

quarkus.log.syslog.enable=true
quarkus.log.syslog.endpoint=localhost:5140
quarkus.log.syslog.protocol=udp
quarkus.log.syslog.app-name=quarkus
quarkus.log.syslog.hostname=quarkus-test

アプリケーションを起動すると、EFK内にログが到着しているのが確認できるはずです: それらにアクセスするには、 http://localhost:5601/ で利用可能な Kibana を使用することができます。

Elasticsearch インデックスの検討

デフォルトでは、Elasticsearch は未知のフィールド(インデックス設定で無効になっていない場合)を、そのタイプを検出して自動的にマッピングすることに注意してください。これは、ログパラメータ(デフォルトで含まれている)を使用する場合や、MDC インクルード(デフォルトでは無効)を有効にする場合、最初のログがインデックス内のメッセージパラメータ(または MDC パラメータ)フィールドのタイプを定義するため、厄介なことになる可能性があります。

次のようなケースを想像してみてください:

LOG.info("some {} message {} with {} param", 1, 2, 3);
LOG.info("other {} message {} with {} param", true, true, true);

ログメッセージのパラメータを有効にすると、Elasticsearch に送信される最初のログメッセージは int 型の MessageParam0 パラメータが設定され、これにより integer 型のフィールドでインデックスが構成されます。2 番目のメッセージが Elasticsearch に届くと、ブーリアン値 true を持つ MessageParam0 パラメータが設定され、これによりインデックス作成エラーが発生します。

この制限を回避するには、 quarkus.log.handler.gelf.include-log-message-parameters=false を設定して logging-gelf を介したログメッセージパラメータの送信を無効にするか、Elasticsearch インデックスにテキストまたはキーワードとしてこれらのフィールドを保存するように設定して、Elasticsearch は int/boolean から String への変換を自動的に行います。

Graylogについては以下のドキュメントを参照してください(ただし、他のセントラルロギングスタックにも同じ問題があります)。 カスタム インデックス マッピング

設定リファレンス

設定は通常の application.properties ファイルから行います。

ビルド時に固定される構成プロパティ - 他のすべての構成プロパティは実行時にオーバーライド可能

Configuration property

デフォルト

Determine whether to enable the GELF logging handler

Environment variable: QUARKUS_LOG_HANDLER_GELF_ENABLED

Show more

boolean

false

Hostname/IP-Address of the Logstash/Graylog Host By default it uses UDP, prepend tcp: to the hostname to switch to TCP, example: "tcp:localhost"

Environment variable: QUARKUS_LOG_HANDLER_GELF_HOST

Show more

string

localhost

The port

Environment variable: QUARKUS_LOG_HANDLER_GELF_PORT

Show more

int

12201

GELF version: 1.0 or 1.1

Environment variable: QUARKUS_LOG_HANDLER_GELF_VERSION

Show more

string

1.1

Whether to post Stack-Trace to StackTrace field.

Environment variable: QUARKUS_LOG_HANDLER_GELF_EXTRACT_STACK_TRACE

Show more

boolean

true

Only used when extractStackTrace is true. A value of 0 will extract the whole stack trace. Any positive value will walk the cause chain: 1 corresponds with exception.getCause(), 2 with exception.getCause().getCause(), …​ Negative throwable reference walk the exception chain from the root cause side: -1 will extract the root cause, -2 the exception wrapping the root cause, …​

Environment variable: QUARKUS_LOG_HANDLER_GELF_STACK_TRACE_THROWABLE_REFERENCE

Show more

int

0

Whether to perform Stack-Trace filtering

Environment variable: QUARKUS_LOG_HANDLER_GELF_FILTER_STACK_TRACE

Show more

boolean

false

Java date pattern, see java.text.SimpleDateFormat

Environment variable: QUARKUS_LOG_HANDLER_GELF_TIMESTAMP_PATTERN

Show more

string

yyyy-MM-dd HH:mm:ss,SSS

The logging-gelf log level.

Environment variable: QUARKUS_LOG_HANDLER_GELF_LEVEL

Show more

Level

ALL

Name of the facility.

Environment variable: QUARKUS_LOG_HANDLER_GELF_FACILITY

Show more

string

jboss-logmanager

Post additional fields

デフォルト

Additional field value.

Environment variable: QUARKUS_LOG_HANDLER_GELF_ADDITIONAL_FIELD__FIELD_NAME__VALUE

Show more

string

required

Additional field type specification. Supported types: String, long, Long, double, Double and discover. Discover is the default if not specified, it discovers field type based on parseability.

Environment variable: QUARKUS_LOG_HANDLER_GELF_ADDITIONAL_FIELD__FIELD_NAME__TYPE

Show more

string

discover

Whether to include all fields from the MDC.

Environment variable: QUARKUS_LOG_HANDLER_GELF_INCLUDE_FULL_MDC

Show more

boolean

false

Send additional fields whose values are obtained from MDC. Name of the Fields are comma-separated. Example: mdcFields=Application,Version,SomeOtherFieldName

Environment variable: QUARKUS_LOG_HANDLER_GELF_MDC_FIELDS

Show more

string

Dynamic MDC Fields allows you to extract MDC values based on one or more regular expressions. Multiple regexes are comma-separated. The name of the MDC entry is used as GELF field name.

Environment variable: QUARKUS_LOG_HANDLER_GELF_DYNAMIC_MDC_FIELDS

Show more

string

Pattern-based type specification for additional and MDC fields. Key-value pairs are comma-separated. Example: my_field.*=String,business\..*\.field=double

Environment variable: QUARKUS_LOG_HANDLER_GELF_DYNAMIC_MDC_FIELD_TYPES

Show more

string

Maximum message size (in bytes). If the message size is exceeded, the appender will submit the message in multiple chunks.

Environment variable: QUARKUS_LOG_HANDLER_GELF_MAXIMUM_MESSAGE_SIZE

Show more

int

8192

Include message parameters from the log event

Environment variable: QUARKUS_LOG_HANDLER_GELF_INCLUDE_LOG_MESSAGE_PARAMETERS

Show more

boolean

true

Include source code location

Environment variable: QUARKUS_LOG_HANDLER_GELF_INCLUDE_LOCATION

Show more

boolean

true

Origin hostname

Environment variable: QUARKUS_LOG_HANDLER_GELF_ORIGIN_HOST

Show more

string

Bypass hostname resolution. If you didn’t set the originHost property, and resolution is disabled, the value “unknown” will be used as hostname

Environment variable: QUARKUS_LOG_HANDLER_GELF_SKIP_HOSTNAME_RESOLUTION

Show more

boolean

false

このエクステンションは、システムプロパティーを介してより多くの設定オプションを提供する logstash-gelf ライブラリを使用しています。ドキュメントにはこちら: https://logging.paluch.biz/ からアクセスできます。

関連コンテンツ