tech.guitarrapc.cóm

Technical updates

Datadog Log Management で Kubernetes の external-dns やkube2iam のログレベルを適切に扱いたい

Kubernetesのログを見るといえば、Datadog Log Mangementが楽なのですがログメッセージがレベルで扱われないことが度々あります。

そんなときによくやる「ログメッセージからレベルになるフィールドを取り出してLog Statusとして認識させる」ことを見てみましょう。

Before

After

概要

  • Custom Pipelineを使って、ログメッセージを構造化とLog Statusの変更すればok
  • ログメッセージがkey=valueで構造化されているとさくさく構築できるので神

問題

Kubernetesに限らず、Log Managementでログを取り込んだ時に意図と違ったログレベルとして認識されることがあります。

たとえばKubernetesでexternal-dnsを使っているとき、実行するものがないときはAll records are already up to dateというメッセージ出力されるのですが、Datadog Log ManagementではStatusがErrorとなっています。

level=info msg="All records are already up to date"

しかしこのログは、Messageにlevel=infoとある通りエラーログではありません。 これをInfoとして扱いたいのでさくっと対処しましょう。

ログを見てみる

まずはログがどう認識されているのか見てみましょう。

何も実行するものがないときのログ

対象のログを見てみると、Log StatusがErrorとなっていることがわかります。

Log Status が Error

また、ログも構造化されていません。

ログが構造化されていない

対処法針

external-dnsのログは、level keyでログレベルを表現しています。 こういったログへの追加対応は、Log ManagementのPipelineに追加のカスタムパイプラインを追加できます。 パイプラインには様々な処理(Processor)を設定できます。 今回はデフォルトのパイプラインで設定されたログレベルを書き換えたいので、Log Status Remapperを用いることでログに含まれるlevelキーの値をLog Statusとして認識させることができます。

Use this Processor if you want to assign some attributes as the official status. For example, it can transform this log:

before

after

Log status remapper - Datadog

対応方針は次の通りです。

  • 新規パイプランを作る
  • ログメッセージがただの文字列として扱われているのでJSONとして認識されるように構造化
  • 構造化したデータから対象のlevel keyを拾ってLog Statusを書き換える

パイプライン対応

Custom Pipelineを追加して、2つProcessorを追加していきます。

Custom Pipeline の追加

Datadog AgentのPipelineの後ろに新規Pipelineを追加します。

パイプラインを作成するときに、対象となるログを絞り込みます。 今回はAll records are already up to dateとなっているログを絞りたいので、Sourceとメッセージで指定してみましょう。

source:external-dns message:"*All records are already up to date"

Processor の追加: Grok Parserで構造化する

パイプラインができたら、具体的な処理単位であるProcessorを追加します。 まずは、ただの文字列になっているログを構造化 (JSON) 変換するため、Grok Parserを用います。

Grok Parser - Datadog

変換方法を考えるため、対象にしたいログメッセージを見てみましょう。

time="2020-01-07T09:49:07Z" level=info msg="All records are already up to date"

今回のログは「key=valueがスペースで羅列されている構造」とわかります。 こういった、文字列がkey{何かの文字}valueで構成されている場合、%{data::keyvalue}を使うだけでサクッと構造化できます。

external_dns_rule %{data::keyvalue}

Key value or logfmt - Datadog

これでいい感じのJSONに変換されてました。

{
  "time": "2020-01-07T09:49:07Z",
  "level": "info",
  "msg": "All records are already up to date"
}

Grok Parser で構造化

Processor の追加: Log Status Remapperでログステータスとする

構造化したデータからステータスをとります。 もう一度Processorを追加して、今度はLog Status Remapperを使ってログステータスの差し替えを行います。

Log status remapper - Datadog

levelキーの値を使うので、対象キーにlevelを指定します。

Log Status Remapper で level キーを用いる

これでおしまいます。

Pipelineの結果を確認

Log Explorerでログの結果を見てみると、いい感じにStatusが変わったことと確認できます。

先ほどなにもデータがなかったATTRIBUTESにも、変換した構造化データがのっていることがわかります。

このパターンはちょくちょく使うので、さくっとできると捗るでしょう。

REF

https://github.com/kubernetes-sigs/external-dns/issues/772