ログの一元管理(Graylog、Logstash、Fluentd)
このガイドでは、Graylog、Logstash(Elastic StackやELK - Elasticsearch、Logstash、Kibanaの内部)、Fluentd(EFK - Elasticsearch、Fluentd、Kibanaの内部)のような集中型ログ管理システムにログを送信する方法を説明します。
このドキュメントは、オブザーバビリティコンポーネントとその他のオブザーバビリティ関連コンポーネントを取り上げている Quarkus のオブザーバビリティリファレンスガイド の一部です。
ログを一元化する方法はたくさんあります (Kubernetesを使用している場合、最も簡単な方法は、コンソールにログを記録し、一元的なログマネージャーをクラスター内に統合するようにクラスター管理者に依頼することです)。 このガイドでは、サポートされている Quarkus エクステンションを使用して、Graylog Extended Log Format (GELF)、Elastic Common Schema (ECS)、OpenTelemetry Log シグナルなどのサポートされている標準フォーマットで、ログを外部ツールに送信する方法について説明します。
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 17+がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.9
-
Docker と Docker Compose、または Podman 、および Docker Compose
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
アプリケーション例
以下の例はすべて、以下の手順で作成できる同じアプリケーションの例を基にしています。
REST エクステンションを持つアプリケーションを作成します。以下のコマンドで作成できます。
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=centralized-logging"
デモのために、文をログに記録するだけのエンドポイントを作成します。これをアプリケーション内で行う必要はありません。
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.jboss.logging.Logger;
@Path("/logging")
@ApplicationScoped
public class LoggingResource {
private static final Logger LOG = Logger.getLogger(LoggingResource.class);
@GET
public void log() {
LOG.info("Some useful log message");
}
}
ソケットハンドラーを使用して ECS (Elastic Common Schema) 形式で Elastic Stack (ELK) にログを送信する
ECS フォーマットの TCP 入力を使用して、ログを Logstash に送信できます。
これを実現するには、 quarkus-logging-json
エクステンションを使用してログを JSON でフォーマットし、ソケットハンドラーを使用してログを Logstash に送信します。
$HOME/pipelines/ecs.conf
に次のファイルを作成します。
input {
tcp {
port => 4560
codec => 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"]
}
}
次に、JSON 形式でログインするようにアプリケーションを設定します。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-json</artifactId>
</dependency>
implementation("io.quarkus:quarkus-logging-json")
Logstash エンドポイントのホストとポートを指定します。ECS に準拠するには、ログ形式を指定します。
# to keep the logs in the usual format in the console
quarkus.log.console.json.enabled=false
quarkus.log.socket.enable=true
quarkus.log.socket.json.enabled=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
最後に、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を使って、ログにアクセスすることができます。
Syslog ハンドラーを使用した Fluentd へのログの送信
Syslog 入力を使用してログを Fluentd に送信できます。 GELF 入力とは異なり、Syslog 入力では 1 つのイベントで複数行のログがレンダリングされません。
まず、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 を使用することができます。
OpenTelemetry Loggingを使用したログの送信
OpenTelemetry Loggingは、互換性のある OpenTelemetry コレクターにログを送信できます。その使用方法は、ガイド OpenTelemetry Loggingの使用 に記載されています。
logging-gelf
エクステンションを使用したログの送信
このエクステンションは非推奨です。このガイドで上記に説明した代替手段を検討することを推奨します。 |
quarkus-logging-gelf
エクステンションは、Quarkusが使用する基礎となるロギングバックエンド(jboss-logmanager)にGELFログハンドラーを追加します。デフォルトでは無効になっており、有効にした場合も別のハンドラーも使用している場合(デフォルトではコンソールハンドラーが有効になっています)、ログは両方のハンドラーに送信されます。
プロジェクトのベースディレクトリーで次のコマンドを実行すると、 logging-gelf
エクステンションをプロジェクトに追加できます。
quarkus extension add logging-gelf
./mvnw quarkus:add-extension -Dextensions='logging-gelf'
./gradlew addExtension --extensions='logging-gelf'
これにより、ビルドファイルに以下の依存関係が追加されます:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-gelf</artifactId>
</dependency>
implementation("io.quarkus:quarkus-logging-gelf")
ポート 12201 の外部 UDP エンドポイントにログを送信するように GELF ログハンドラーを設定します。
quarkus.log.handler.gelf.enabled=true
quarkus.log.handler.gelf.host=localhost
quarkus.log.handler.gelf.port=12201
ログをGraylogに送信
代わりに Syslog ハンドラーを使用することを推奨します。 |
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)にログを送信
代わりに OpenTelemetry Logging またはソケットハンドラーを使用することを推奨します。 |
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を使って、ログにアクセスすることができます。
Fluentd(EFK)へのログ送信
代わりに OpenTelemetry Logging またはソケットハンドラーを使用することを推奨します。 |
まず、必要なプラグインである 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 を使用することができます。
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: Show more |
boolean |
|
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: Show more |
string |
|
The port Environment variable: Show more |
int |
|
GELF version: 1.0 or 1.1 Environment variable: Show more |
string |
|
Whether to post Stack-Trace to StackTrace field. Environment variable: Show more |
boolean |
|
Only used when Environment variable: Show more |
int |
|
Whether to perform Stack-Trace filtering Environment variable: Show more |
boolean |
|
Java date pattern, see Environment variable: Show more |
string |
|
The logging-gelf log level. Environment variable: Show more |
|
|
Name of the facility. Environment variable: Show more |
string |
|
型 |
デフォルト |
|
Additional field value. Environment variable: 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: Show more |
string |
|
Whether to include all fields from the MDC. Environment variable: Show more |
boolean |
|
Send additional fields whose values are obtained from MDC. Name of the Fields are comma-separated. Example: mdcFields=Application,Version,SomeOtherFieldName Environment variable: 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: 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: 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: Show more |
int |
|
Include message parameters from the log event Environment variable: Show more |
boolean |
|
Include source code location Environment variable: Show more |
boolean |
|
Origin hostname Environment variable: Show more |
string |
|
Bypass hostname resolution. If you didn’t set the Environment variable: Show more |
boolean |
|
このエクステンションは、システムプロパティーを介してより多くの設定オプションを提供する logstash-gelf
ライブラリを使用しています。
ドキュメントには https://logging.paluch.biz/ からアクセスできます。