はじめに
初めまして、tunamayoです。
GCEに保存された2つのログファイルから、内容を構造化してCloud Loggingに送信できるようOpsエージェントを構成してみました。
Ops エージェントの設定に関する記事は少ない上、複数のパイプラインを構成している例はあまりみたことがないので、備忘録 & もしや誰かの参考になるかも?と思い記載しました。
目的
- GCEインスタンスからLoggingに構造化したログを送信し、確認を容易にする
GCEインスタンス上で動作するアプリケーションのログが /usr/local/myApp/log
の
myapp-01.log
myapp-02.log
に書き出されており、内容を見るにはインスタンスにsshする必要がありました。
(問題点:各ファイルをTerminalで見るのは煩雑で、コマンドの誤操作リスクも増える)
↑のログがLog Exprolerから確認できるようになれば、問題点が解消できそうです。
前提 : Ops エージェントとは
GCEインスタンスからテレメトリーを収集するエージェント
➡︎これを設定すると、GCEインスタンスからLoggingへのログ送信が可能になります。
又、Ops エージェントはログを加工する機能(processor)を持っており、目的に応じてログを構造化した上でCloud Loggingに送信することができます。
config.yaml
Ops エージェントの設定は/etc/google-cloud-ops-agent/config.yaml
で構成します。
# 基本構成
logging:
receivers: # ログを収集する対象ファイルを定義
syslog:
type: files
include_paths:
- /var/log/messages
- /var/log/syslog
processors: # ログをパースする場合に処理を定義
log_parser:
type: parse_regex
regex: "^(?<msg>.*)$"
service:
pipelines: # パイプラインを定義
default_pipeline:
receivers: [hostmetrics]
processors: [metrics_filter]
処理の全体的な流れはpipelines:
で定義されます。
Ops エージェントを実行すると、
-
service
配下のpipelines:
で定義したパイプラインが走る - パイプラインに設定した
receivers
が呼ばれ、指定パスからログを取得 - パイプラインに設定した
processors
が呼ばれ、↑で取得したログを加工 - Loggingに送信される
といった流れで処理が進みます。
実装
今回は2つの.logファイルをLoggingに送信するため、pipeline
を2つ用意します
(各ファイルは内容のフォーマットが異なるので、processor
もそれぞれに合わせ複数用意。
processor
に記載した順序で段階的に加工し、各ファイルのログを構造化します)
パイプライン仕様
- parse_myapp_01_logs :
myapp-01.log
をパースするパイプライン - parse_myapp_02_logs :
myapp-02.log
をパースするパイプライン
logging:
receivers:
# myapp-01.logのレシーバ
myapp_01_logs:
type: files
include_paths:
- /usr/local/myApp/log/myapp-01.log
# myapp-02.logのレシーバ
myapp_02_logs:
type: files
include_paths:
- /usr/local/myApp/log/myapp-02.log
processors:
# myapp-01.logのpaese
## 1.正規表現でパースして構造化
parse_myapp_01:
type: parse_regex
field: message
regex: "^\[(?<time>[^\]]+)\] ip\[ *(?<ip>[^\]]*)\] op\[ *(?<op>[^\]]*)\] cid\[ *(?<cid>[^\]]*)\] sid\[ *(?<sid>[^\]]*)\] - (?<method>(?:START )?[A-Z]+) (?<url>[^:]+):(?: code=(?<status_code>\d+), time=(?<response_time>\d+)ms,)? (?<param>.*)$"
time_key: time
time_format: "%Y-%m-%d %H:%M:%S,%LJST"
## 2.フィールドの型を指定
conv_int:
type: modify_fields
fields:
jsonPayload.ip:
default_value: ""
jsonPayload.op:
default_value: ""
jsonPayload.cid:
default_value: ""
jsonPayload.sid:
default_value: ""
jsonPayload.status_code:
default_value: 0
type: integer
jsonPayload.response_time:
default_value: 0
type: integer
# myapp-02.logのparse
## 1.複数行exeptionを結合
parse_myapp_02_multiline:
type: parse_multiline
match_any:
- type: language_exceptions
language: java
## 2.text+json混合ログを分離
parse_myapp_02_mixed_json_extract:
type: parse_regex
regex: '^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\s+(?<level>[A-Z]+)\s+(?:\[(?<thread>[^\]]+)\]\s+)?(?<class>[\w\.$]+):?\s+(?<message>.*?)\n(?<json_content>{.*})'
time_key: time
time_format: "%Y-%m-%d %H:%M:%S,%LJST"
## 3.分離したjson_contentをparse
parse_myapp_02_mixed_json_parse:
type: parse_json
field: json_content
## 4.標準的な単一行ログを解析
parse_myapp_02_oneline_corrected:
type: parse_regex
regex: '^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\s+(?<level>[A-Z]+)\s+\[(?<thread>[^\]]+)\]\s+(?<class>[\w\.$]+):?\s+(?<message>.*)$'
time_key: time
time_format: "%Y-%m-%d %H:%M:%S,%LJST"
## 5.単一行のjsonをparse
parse_myapp_02_oneline_json:
type: parse_json
## 6.フィールドをlogEntryの標準形に整形
standardize_fields:
type: modify_fields
fields:
severity:
### levelをトップレベルのseverityとして移動/変換
move_from: jsonPayload.level
map_values:
"WARN": "WARNING"
"ERROR": "ERROR"
"INFO": "INFO"
"DEBUG": "DEBUG"
service:
pipelines:
# 1つ目のパイプライン(myapp-01.log用)
parse_myapp_01_logs:
receivers:
- myapp_01_logs
processors:
- parse_myapp-01
- conv_int_myapp_01
# 2つ目のパイプライン(myapp-02.log用)
parse_myapp_02_logs:
receivers:
- myapp_02_logs
processors:
- parse_myapp_02_log_multiline
- parse_myapp_02_mixed_json_extract
- parse_myapp_02_mixed_json_parse
- parse_myapp_02_oneline_corrected
- parse_myapp_02_oneline_json
- standardize_fields
設定反映(コマンド)
/etc/google-cloud-ops-agent/config.yaml
を更新したら、
Ops エージェントを再起動し設定を反映します。
systemctl restart google-cloud-ops-agent.service
結果
Cloud LoggingのLog Exprolerで myapp-01.log
/ myapp-02.log
が表示されるようになりました
構造化も、processor
で設定した通りできている模様です
myapp-01.log |
myapp-02.log |
---|---|
![]() |
![]() |
まとめ
結果:2つのログファイルから、それぞれの内容をCloud Loggingに送信できました。
「Log ExprolerからGCEのログファイル内容を見られるようにする」という目標は、達成できたと思います!
(ログの構造化については、ファイル毎に内容/フォーマット/パターンが異なり、processor
の構成に苦労しました😇。まだ完璧な構造化とは言えないので、今後修正したいです)
参考