📊

OpenTelemetry Collectorにログを集計させるためにfilelog receiverとcount connectorを使う

2023/08/31に公開

こんにちは、Splunk Observabilityの導入支援をしている @katzchang です。今日はOpenTelemetry Collectorを使って、ログファイルを集計して、メトリクスプラットフォームに送るということをやってみたいと思います。

ログはとても柔軟なデータフォーマットで、あらゆることが自由な形式で記録できます。しかしその反面、データ転送や保管、可視化のためのクエリ処理など各所の処理コストが高く、データ転送料金が跳ね上がったり、収集サーバーの計算機リソースを食いつぶしたり、SaaSのライセンスコストも多くかかります。使用用途が限られたログ、つまりどのようなクエリをするか予めわかっているログは、事前に集計してメトリクスとして扱うことで、上記の処理コストを抑えつつより素早い可視化が実現できます。

ログをメトリクスに変換する箇所はいくつかあります。たとえば、ログをフィルタして件数を数えるような処理をするとしたら:

  • 集計クエリが発行された時点で、ログをフィルタして、件数を数える
  • ログ分析プラットフォームにログが取り込まれた時点で、フィルタして、件数を数える
  • ログ分析プラットフォームにログを送るエージェントが、フィルタして、件数を数える
  • ログを出力するアプリケーションが、生ログではなく、メトリクスとしてレポートとする機能を備える

すごく大雑把に言うと、下にいくほどコスト効率が良くなり、上にいくほど柔軟性が高まります。

今回はこの中の3番目、「ログ分析プラットフォームにログを送るエージェントが、フィルタして、件数を数える」を、OpenTelemetry Collectorの機能を使って実現してみましょう。このやり方は、アプリケーションを変更することなく、また、ログ分析プラットフォームに依存しない形でメトリクスの集計ができるというのがメリットです。

OpenTelemetry Collectorってなんだったっけ?

OpenTelemetry Collectorは、テレメトリーデータの受信、処理、送信を担うエージェントで、様々な形式データを受け取り、加工し、任意のバックエンドに送信することができます。利用者はコンポーネント化された部品つかって、自由にテレメトリーデータのパイプラインを組み立てることができます。OpenTelemetryの公式サイトのRegisitoryを見ると、どのようなコンポーネントが使えるかがわかります。

設定はyamlファイルで行われます。シンプルな設定はたとえばこんな感じです:

receivers:
  otlp:
    protocols:
      grpc:

exporters:
  otlp:
    endpoint: otelcol.observability.svc.cluster.local:443

service:
  extensions: []
  pipelines:
    logs:
      receivers: [otlp]
      processors: []
      exporters: [otlp]

otlpのgprcプロトコル版でテレメトリデータ(トレース、ログ、メトリクスなど)を受け取り、とくに処理はせず、ログ形式のものを otelcol.observability.svc.cluster.local の443ポートにotlpプロトコルで送信するという風にパイプラインが設定されています。

これでとりあえず問題なく動くのですが、ここでログの件数を数えたいときに、どういうコンポーネントを使えばいいでしょうか?このような問題をシンプルに解決するために、最近「コネクター(connector)」という新しいコンポーネントのタイプが登場しました。

コネクターとは

OpenTelemetry Collectorのコネクターは、レシーバーとエクスポーターの2つの役割を持ち、あるパイプラインで受け取ったものを別のパイプラインに送るというものです。スパンを受け取ってメトリクスにしたり一つのパイプラインに流れてきたデータをアトリビュートによって分岐させたり、いままでよりも柔軟にパイプラインを構成できるようになるものです。

ということで、今回はログの件数を数えるためにCount Connectorを使ってみましょう。

OpenTelemetry Collectorを設定する

今回はSplunk distroであるsplunk-otel-collectorから始めてみます。セットアップは基本的にシェルスクリプトを叩くだけでいい感じにインストールされ、204行のデフォルトの設定が入ります。これをベースに、次の変更をしていきます。

  • filelog receiverの追加
  • count connectorの追加
  • filelog receiver -> count connector -> metricsバックエンドのパイプラインの追加

気の早いかたは最終的なdiffを見てみてください。

filelog receiverの追加

ログファイルを取り込むために、filelog receiverを使います。

receivers の下に記述していきます.

  filelog/hoge:
    include: [ /var/log/hoge/*.log ]
    operators:
      - type: json_parser
        timestamp:
          parse_from: attributes.time
          layout: '%Y-%m-%d %H:%M:%S'
  • filelog/hoge というコンポーネントとして命名する(この名前はパイプラインの中で使われます)
  • /var/log/hoge/*.log のログファイルを対象とする
  • 行分割のjson形式でパースする
  • time という属性をログ生成の時刻として扱う

という程度の定義がされています。ほかにも正規表現でパースさせるなどいくつかのオプションがあるので、詳しくはREADME.mdを眺めてみてください。

count connectorの追加

次に、count connectorを追加していきます。

これはトップレベル(っていう表現でいいんだっけ?)に記述していきます。

connectors:
  count/hoge:
    logs:
      hoge.count:
        description: The number of hoge logs
        attributes:
          - key: type
            default_value: unknown
  • count/hoge というコンポーネントとして命名する
  • logs で、ログをカウントの対象とする
  • hoge.count というメトリクス名とする
  • 属性 type の値毎に集計する

これで、集計に関する定義ができました。

filelog receiver -> count connector -> metricsバックエンドのパイプラインの追加

コンポーネントは定義できたので、パイプラインを定義していきます。それぞれ、コンポーネントを定義するときの名前 filelog/hoge, count/hoge を思い出しながら、作っていきましょう。

service > pipelines の下に、次のパイプラインを追加します。

    logs/hoge:
      receivers: [filelog/hoge]
      exporters: [count/hoge]

次に、既存のメトリクスパイプラインの中に、 count/hogereceivers の一つとして追加します。

      receivers: [count/hoge, hostmetrics, otlp, signalfx, smartagent/signalfx-forwarder]

これで準備ができました!

結果を確認する

では、実際に動かしてみて、動作を見てみます。Collectorの再起動を忘れずにやりましょう。

sudo systemctl restart splunk-otel-collector

データを作る

ログファイルを作っていくために、たとえばechoを使ってこんな感じにできます。

echo "{\"time\": \"$(date +"%Y-%m-%d %H:%M:%S")\", \"type\":\"B\", \"message\":\"hoge\"}" >> /var/log/hoge/hoge.log

type の値を変えながら何度かコマンドを叩くと、 /var/log/hoge/hoge.log はこんな感じのファイルが出来上がります。

{"time": "2023-08-31 05:19:14", "type":"C", "message":"hoge"}
{"time": "2023-08-31 05:19:14", "type":"C", "message":"hoge"}
{"time": "2023-08-31 05:19:22", "message":"hoge"}
{"time": "2023-08-31 05:19:23", "message":"hoge"}
{"time": "2023-08-31 05:19:23", "message":"hoge"}
{"time": "2023-08-31 05:20:18", "message":"hoge"}
{"time": "2023-08-31 05:20:20", "type":"C", "message":"hoge"}
{"time": "2023-08-31 05:20:23", "message":"hoge"}
{"time": "2023-08-31 05:20:26", "type":"B", "message":"hoge"}

問題がなければ、すでにメトリクスがバックエンドに送られているはずです。

メトリクスをクエリする

count connectorで定義したメトリクス名で、クエリをしてみましょう。Splunk ObservabilityではMetrics Finderで検索することができるはずです。

チャートを見ると、ログの件数が type をディメンションとしてカウントされていることがわかります。

まとめ

さまざまなテレメトリーデータを目的に応じて使い分けるのは、オブザーバビリティのコストコントロールの第一歩です。OpenTelemetry Collectorを使うことで、そのようなコントロールが設定だけで出来るようになります。また、今回はメトリクスをSplunk Observabilityへ送りましたが、エクスポーターを変更することで、Prometheusなど様々なメトリクスバックエンドに送信することができます。

もちろん、ログを処理することでOpenTelemetry Collectorサービスの負荷は高まります。十分なCPU/メモリを確保する必要があるかもしれません。また、Count Connectorは「in development」であり、今後仕様や動作の変更があるかもしれません。しかしまあ、シンプルな機能なので、おそらく大丈夫じゃないかな。たぶん。

Discussion