プロジェクトは GitHub にホストされています:y0ngb1n/spring-boot-samples、Star や Fork を歓迎します 😘
ログの重要性#
なぜ重要か#
- 運用:医者が患者を診るように、ログは患者が自分の病状を述べるものです
- 悪意のある攻撃、悪意のある登録、偽の注文、悪意のあるパスワード推測など
直面する課題#
- 注目すべき点が多く、どの点も問題を引き起こす可能性がある
- ログが多くのマシンに分散しており、問題が発生したときにログが削除されていることに気づく
- 多くの運用担当者は消防士のように、問題があるところに行く
集中化ログ管理#
ログ検索 > フォーマット分析 > 検索と可視化 > リスク警告
ELK 統合環境の迅速な構築#
技術選定#
では、ELK とは何でしょうか?「ELK」は 3 つのオープンソースプロジェクトの頭文字を取ったもので、これらのプロジェクトはそれぞれ次の通りです:
E
(Elasticsearch)は検索と分析エンジンです。L
(Logstash)はサーバーサイドのデータ処理パイプラインで、複数のソースからデータを同時に収集し、データを変換し、Elasticsearch などの「ストレージ」にデータを送信します。K
(Kibana)はユーザーが Elasticsearch 内でデータを視覚化するためにグラフやチャートを使用できるようにします。
迅速なデプロイ#
Docker を使用して上記の基本環境をデプロイし、設定ファイルdocker-compose.yml
を参照して、以下のコマンドを入力してワンクリックデプロイを行います:
# 設定を確認
docker-compose config
# サービスを起動(-dはバックグラウンドで起動)
docker-compose up -d
# サービスを停止し、クリーンアップ
docker-compose down
Logstash の設定#
設定ファイルlogstash-config.conf
を参照し、以下のように設定します:
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 8080
codec => json_lines
}
}
output {
elasticsearch {
hosts => "elasticsearch:9200"
# インデックス名はindex templatesの設定を参照する必要があります。例:logs-*-*
# index => "app-logs-%{app_name}-%{+YYYY.MM.dd}"
index => "app-logs-%{+YYYY.MM.dd}"
}
}
Spring Boot と ELK の統合によるログ管理#
依存関係の追加 #
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash-logback-encoder.version}</version>
</dependency>
logback 設定の追加#
方法 1:logback-spring.xml による設定#
設定ファイルlogback-spring.xmlを参照し、以下のように設定します:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<!-- デフォルトでログ文書にシリアライズされます -->
<springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>192.168.50.88:8880</destination>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" >
<!-- customFieldsの役割はLogstash設定でインデックス名を指定する際のオプションパラメータで、ログ文書にこのフィールドが追加されます -->
<customFields>{"app_name":"${APP_NAME}"}</customFields>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="LOGSTASH" />
<appender-ref ref="CONSOLE" />
</root>
</configuration>
方法 2:Java Config による設定(カスタマイズ可能なスターター)#
@Slf4j
@Configuration
@ConditionalOnProperty(prefix = "elk.logstash", name = "enabled", havingValue = "true")
public class LogstashLogbackConfig {
private static final String LOGSTASH_APPENDER_NAME = "LOGSTASH";
private static final String LOGSTASH_ASYNC_APPENDER_NAME = "ASYNC_LOGSTASH";
@Value("${spring.application.name}")
private String appName;
@Autowired
private LogstashProperties logstash;
@Bean
@ConfigurationProperties(prefix = "elk.logstash")
public LogstashProperties logstash() {
return new LogstashProperties();
}
@PostConstruct
private void addLogstashAppender() {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
log.info("LogstashAppenderの初期化");
final LogstashTcpSocketAppender logstashAppender = new LogstashTcpSocketAppender();
logstashAppender.setName(LOGSTASH_APPENDER_NAME);
logstashAppender.setContext(loggerContext);
logstashAppender.addDestinations(
new InetSocketAddress(this.logstash.getHost(), this.logstash.getPort())
);
// https://github.com/logstash/logstash-logback-encoder
final LogstashEncoder logstashEncoder = new LogstashEncoder();
logstashEncoder.setIncludeContext(false);
String customFields = "{\"app_name\":\"" + this.appName +"\",\"idol\":\"yangbin\"}";
logstashEncoder.setCustomFields(customFields);
final ShortenedThrowableConverter throwableConverter = new ShortenedThrowableConverter();
throwableConverter.setRootCauseFirst(true);
logstashEncoder.setThrowableConverter(throwableConverter);
logstashAppender.setEncoder(logstashEncoder);
logstashAppender.start();
// パフォーマンスのためにアペンダーを非同期アペンダーでラップ
final AsyncAppender asyncLogstashAppender = new AsyncAppender();
asyncLogstashAppender.setContext(loggerContext);
asyncLogstashAppender.setName(LOGSTASH_ASYNC_APPENDER_NAME);
asyncLogstashAppender.setQueueSize(this.logstash.getQueueSize());
asyncLogstashAppender.addAppender(logstashAppender);
asyncLogstashAppender.start();
loggerContext.getLogger("ROOT").addAppender(asyncLogstashAppender);
}
}
タイマーを使用してランダムなログをシミュレート#
...
2021-07-25 23:00:36.552 INFO 15928 --- [ main] i.g.y.s.e.config.LogstashLogbackConfig : LogstashAppenderの初期化
2021-07-25 23:00:36.813 INFO 15928 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : ExecutorService 'applicationTaskExecutor'の初期化
2021-07-25 23:00:37.017 INFO 15928 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : ExecutorService 'taskScheduler'の初期化
2021-07-25 23:00:37.084 INFO 15928 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcatがポート8080(http)で起動しました。コンテキストパスは''です
2021-07-25 23:00:37.095 INFO 15928 --- [ scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler : [4a2fa762-9390-48f3-8478-4fcdbf6ba017] モックログイベント、何かをログに記録...
2021-07-25 23:00:37.097 WARN 15928 --- [ scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler : [c859978e-5150-4fe4-979f-9acd7957a55a] モックログイベント、何かをログに記録...
2021-07-25 23:00:37.097 ERROR 15928 --- [ scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler : [7625e2e6-62e9-4bbf-a998-1e741723f824] モックログイベント、何かをログに記録...
2021-07-25 23:00:37.599 INFO 15928 --- [ scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler : [54ba65f2-05d7-4f27-ab63-bd19a0165b6b] モックログイベント、何かをログに記録...
2021-07-25 23:00:37.599 WARN 15928 --- [ scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler : [901ca6a0-fc7b-4749-8661-4c81f7c4701d] モックログイベント、何かをログに記録...
2021-07-25 23:00:37.599 ERROR 15928 --- [ scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler : [e2010eda-3f63-49ec-bb97-1157a2b11f01] モックログイベント、何かをログに記録...
...
Kibana を使用してログを管理する#
Logstash によって自動的に作成されたインデックスを確認#
インデックスを追加#
Discover を通じてログインデックス情報を確認#