リアルタイムでログを分析できることは、生産アプリケーションにとって非常に重要です。ClickHouseがログデータの保存と分析に優れているかどうか、考えたことはありますか? ELKからClickHouseへのログインフラの移行に関するUberの経験をチェックしてみてください。
このガイドでは、人気のデータパイプラインVectorを使用して、Nginxのログファイルをテールし、それをClickHouseに送信する方法を示します。以下のステップは、任意の種類のログファイルをテールする際にも似ています。すでにClickHouseが稼働しており、Vectorがインストールされていると仮定します(まだ起動する必要はありません)。
1. データベースとテーブルの作成
ログイベントを保存するためのテーブルを定義します:
- 新しいデータベース
nginxdb
から始めます:
CREATE DATABASE IF NOT EXISTS nginxdb
- 初めは、全ログイベントを単一の文字列として挿入します。明らかにこれはログデータの分析に適した形式ではありませんが、マテリアライズドビューを使用してその部分を後で解決します。
CREATE TABLE IF NOT EXISTS nginxdb.access_logs (
message String
)
ENGINE = MergeTree()
ORDER BY tuple()
注記
現時点では主キーは本当に必要ありませんので、ORDER BYは**tuple()**に設定されています。
Nginxの詳細をあまり説明するつもりはありませんが、すべての詳細を隠すつもりもありませんので、このステップではNginxのログ設定を行うために十分な詳細を提供します。
- 次の
access_log
プロパティは、combined形式でログを /var/log/nginx/my_access.log
に送信します。この値は、nginx.conf
ファイルの http
セクションに入ります:
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/my_access.log combined;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}
-
nginx.conf
を変更した場合は、必ずNginxを再起動してください。
-
ウェブサーバーのページを訪問して、アクセスログにいくつかのログイベントを生成します。combined形式のログは次のような形式を持っています:
192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://localhost/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
192.168.208.1 - - [12/Oct/2021:03:31:49 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
Vectorは、ログ、メトリクス、およびトレース(ソースと呼ばれます)を収集、変換し、多くの異なるベンダー(シンクと呼ばれます)にルーティングします。ClickHouseとの標準的な互換性があります。ソースとシンクは、vector.tomlという設定ファイルで定義します。
- 次の vector.toml は、my_access.log の末尾をテールする fileタイプのソースを定義し、上記で定義した access_logs テーブルを シンクとして定義しています:
[sources.nginx_logs]
type = "file"
include = [ "/var/log/nginx/my_access.log" ]
read_from = "end"
[sinks.clickhouse]
type = "clickhouse"
inputs = ["nginx_logs"]
endpoint = "http://clickhouse-server:8123"
database = "nginxdb"
table = "access_logs"
skip_unknown_fields = true
-
上記の設定を使用してVectorを起動します。ソースとシンクの定義についてはVectorのドキュメントを参照してください。
-
アクセスログがClickHouseに挿入されているかどうかを確認します。次のクエリを実行すると、テーブルにアクセスログが表示されるはずです:
SELECT * FROM nginxdb.access_logs
4. ログの解析
ClickHouseにログがあるのは素晴らしいことですが、各イベントを単一の文字列として保存すると、あまりデータ分析ができません。マテリアライズドビューを使用してログイベントを解析する方法を見てみましょう。
- マテリアライズドビュー(MVの略)は、既存のテーブルに基づく新しいテーブルであり、既存のテーブルに挿入が行われると、新しいデータもマテリアライズドビューに追加されます。access_logsにログイベントの解析された表現を含むMVを定義する方法を見てみましょう、言い換えれば:
192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
ClickHouseには文字列を解析するためのさまざまな関数がありますが、初めに見てみるべきはsplitByWhitespaceです。これは、空白で文字列を解析し、各トークンを配列として返します。デモンストレーションのために、次のコマンドを実行します:
SELECT splitByWhitespace('192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')
返答は私たちが欲しいものにかなり近いことに気付いてください!いくつかの文字列には余分な文字があり、ユーザーエージェント(ブラウザの詳細)は解析する必要がありませんでしたが、次のステップでそれを解決します:
["192.168.208.1","-","-","[12/Oct/2021:15:32:43","+0000]","\"GET","/","HTTP/1.1\"","304","0","\"-\"","\"Mozilla/5.0","(Macintosh;","Intel","Mac","OS","X","10_15_7)","AppleWebKit/537.36","(KHTML,","like","Gecko)","Chrome/93.0.4577.63","Safari/537.36\""]
- splitByWhitespaceに似て、splitByRegexp関数は正規表現に基づいて文字列を配列に分割します。次のコマンドを実行すると、2つの文字列が返されます。
SELECT splitByRegexp('\S \d+ "([^"]*)"', '192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')
返された2番目の文字列は、ログから正常に解析されたユーザーエージェントです:
["192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] \"GET / HTTP/1.1\" 30"," \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36\""]
- 最終的なCREATE MATERIALIZED VIEWコマンドを確認する前に、データをクリーンアップするために使用されるいくつかの関数を見てみましょう。たとえば、
RequestMethod
は "GET という不要な二重引用符を持っています。次の trim 関数を実行すると、二重引用符を削除できます:
SELECT trim(LEADING '"' FROM '"GET')
- 時間文字列には先頭に角括弧があり、ClickHouseが日付に解析できる形式でもありません。しかし、区切り文字をコロン(:)からカンマ(,)に変更すれば、解析がうまくいきます:
SELECT parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM '[12/Oct/2021:15:32:43'), ':', ' '))
- マテリアライズドビューを定義する準備が整いました。私たちの定義には POPULATE が含まれており、これにより access_logs の既存の行がすぐに処理されて挿入されます。次のSQL文を実行します:
CREATE MATERIALIZED VIEW nginxdb.access_logs_view
(
RemoteAddr String,
Client String,
RemoteUser String,
TimeLocal DateTime,
RequestMethod String,
Request String,
HttpVersion String,
Status Int32,
BytesSent Int64,
UserAgent String
)
ENGINE = MergeTree()
ORDER BY RemoteAddr
POPULATE AS
WITH
splitByWhitespace(message) as split,
splitByRegexp('\S \d+ "([^"]*)"', message) as referer
SELECT
split[1] AS RemoteAddr,
split[2] AS Client,
split[3] AS RemoteUser,
parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM split[4]), ':', ' ')) AS TimeLocal,
trim(LEADING '"' FROM split[6]) AS RequestMethod,
split[7] AS Request,
trim(TRAILING '"' FROM split[8]) AS HttpVersion,
split[9] AS Status,
split[10] AS BytesSent,
trim(BOTH '"' from referer[2]) AS UserAgent
FROM
(SELECT message FROM nginxdb.access_logs)
- 正常に機能したことを確認します。アクセスログがきれいにカラムに解析されて表示されるはずです:
SELECT * FROM nginxdb.access_logs_view
注記
上記のレッスンではデータを2つのテーブルに保存しましたが、最初の nginxdb.access_logs
テーブルを Null テーブルエンジンを使用するように変更することもできます - 解析されたデータは依然として nginxdb.access_logs_view
テーブルに入りますが、生のデータはテーブルに保存されません。
まとめ: シンプルなインストールと迅速な設定を必要とするVectorを使用することで、NginxサーバーからClickHouseのテーブルにログを送信できます。巧妙なマテリアライズドビューを使用することで、これらのログをカラムに解析し、より簡単に分析できるようになります。