🐶

【Terraform】FastlyのログをDatadogに送る

に公開

こんにちは。株式会社スペースマーケットでWebエンジニアをしていますwado63と申します。
最近LLMの性能が高まり、簡単な問題解決であればChatGPTなどに聞けば一発で解決してくれるので、ブログが書きづらくなったなと感じている今日このごろです。
今回のケースも『terraformでfastlyのvclを管理しているのですが、datadogにログを連携するにはどうすればいいでしょうか。』とか聞けば8割ぐらいの精度の回答が返ってきます。
とはいえつまづくところもあったのでその辺含めてまとめてみました。

前提として、DatadogやFastlyのアカウントはすでに作成済み、FastlyはTerraformでVCLの管理をしているとします。
TerraformでFastlyをimportする方法については、以前の記事でまとめていますので、そちらを参考にしてください。
https://zenn.dev/spacemarket/articles/terraform-import-fastly

ログ設定の流れ

Fastlyがドキュメントを用意してくれているので、これを参考に進めていきます。
https://www.fastly.com/documentation/ja/guides/integrations/logging-endpoints/log-streaming-datadog/

  1. DatadogのAPIキーを取得する
  2. FastlyのサービスにDatadogのログエンドポイントを追加する

終わり。簡単ですね!

一連の内容を理解しやすいようにまずはGUIで追ってみましょう。

DatadogのAPIキーを取得する

Datadog の設定ページから Datadog API キーを 取得 Datadog インターフェイスで Integrations -> APIs にアクセスすることで API キーを作成・取得できます。

ドキュメントにはこのように書かれていますが、実際には少し異なります。
Datadog のドキュメントを見てみると、APIキーの発行は Organization のセッティングからできるとなっているので、こちらから発行していきましょう。


DatadogのAPIキーの発行


APIキーを発行したら、FastlyのサービスにDatadogのログエンドポイントを追加していきます。
Service configurationsのページから、Loggingのタブを開きCreate your first logging endpointをクリックします。

つぎにDatadogのCreate endpointを選択し、必要な内容を入力します。

Name: このエンドポイントの名前を入力します。わかりやすい名前にしておきましょう。
Placement: Format Version Defaultを選択します。Noneを選択するとログがでません。
Log Format: Datadogのログフォーマットを記入します。初期状態の内容をそのまま使えば簡単です。
Region: Datadogのドキュメントを参考に使用しているDatadogのリージョンを選択します。
API Key: 先ほど取得したDatadogのAPIキーを入力します。

これでDatadogへのログの設定が完了です。簡単ですね。


Logのendpoint追加

Terraformでの設定

同じ内容をTerraformで設定していきます。
Fastly Providerのドキュメントを参考に、fastly_service_vclリソースのlogging_datadogブロックを使って設定していきます。

resource "fastly_service_vcl" "default" {
 # 他の設定は省略

  logging_datadog {
    name        = "datadog-logs"
    token       = "ここにDatadogのAPIキーを入力"
    format      = file("${path.module}/datadog_log_format.json")
  }
}
// datadog_log_format.json
{
  "ddsource": "fastly",
  "service": "%{req.service_id}V",
  "date": "%{begin:%Y-%m-%dT%H:%M:%S%z}t",
  "time_start": "%{begin:%Y-%m-%dT%H:%M:%S%Z}t",
  "time_end": "%{end:%Y-%m-%dT%H:%M:%S%Z}t",
  "http": {
    "request_time_ms": %{time.elapsed.msec}V,
    "method": "%m",
    "url": "%{json.escape(req.url)}V",
    "useragent": "%{json.escape(req.http.User-Agent)}V",
    "referer": "%{json.escape(req.http.referer)}V",
    "protocol": "%H",
    "request_x_forwarded_for": "%{X-Forwarded-For}i",
    "status_code": "%s"
  },
  // 以下省略
}

基本的にはこのように設定するだけで、Datadogへのログの送信が可能になります。
placementやregionは設定しない場合、デフォルトの値が使用されるのでここでは省略しています。
APIキーも本番ではパラメーターストアなどから取得するようにして、ハードコーディングしないようにしましょう。

ここで僕がつまづいた点をいくつか紹介します。

Log Formatの改行とスペースの取り扱い

この例の JSON ログは、読み取りやすくフォーマットされています。正しく解析されるためには、改行とインデントの空白をすべて取り除いた上で Log format 欄に1行で入力する必要があります。

Fastlyのドキュメントでは上記のように記載されています。

この内容に従うと、formatから改行・スペースを取り除く必要があります。
ゆえに僕はこのようにreplace()を使って改行とスペースを取り除くようにしました。

format = replace(file("${path.module}/datadog_log_format.json"), “/((?m)^\\s+|\n)/“, "")

ちなみにreplace()は、"/(\\s|\n)/" のようにスラッシュで囲むと正規表現として扱われます。ここが最初わからず、terraform console 上で試行錯誤していました。

このような書き方で改行・スペースを取り除くことはできますが、実際には改行やスペースを取り除かなくても動作することがわかりました。GUIで設定した内容をterraform apply -refresh-onlyで取り込んで確認してみると見事に\nやスペースが入っています。
とはいえ、公式に書かれているので一応対応しておきました。

“/((?m)^\\s+|\n)/“は改行と行頭のスペースを取り除く正規表現です。
“/((?m)^\\s+|\n)/“の部分は、"\\s"でスペースを、\nで改行を表しています。
(?m)はマルチラインモードを有効にするためのフラグです。
^\\s+は行頭のスペースを表し、|はOR条件を表しています。
この正規表現を使うことで、改行と行頭のスペースを取り除くことができます。

フラグをオンにする書き方がわからずはちょっとハマりました。

ビット演算子とtemplatefileのエラー

先ほどの例ではfile("${path.module}/datadog_log_format.json")のようにファイルを読み込んでいます。あえてtemplatefile()を使っておりません。
formatの中にterraform.workspaceなどの変数を入れたいケースはあるとおもいます。

ただしtemplatefile()を使うと、以下のようなエラーが発生します。

Planning failed. Terraform encountered an error while generating this plan.

Error: Error in function call
│
│   on main.tf line 188, in resource "fastly_service_vcl" "default":188:         templatefile("${path.module}/datadog_logging_format_template.json", { service_name : var.logging_datadog.service_name }),
│     ├────────────────
│     │ path.module is "."
│     │ var.logging_datadog.service_name is "servcie_name"
│
│ Call to function "templatefile" failed: ./datadog_logging_format_template.json:60,42-43: Unsupported operator; Bitwise operators are not supported. Did you mean
│ boolean NOT ("!")?, and 11 other diagnostic(s).

"is_cacheable": %{if(fastly_info.state~"^(HIT|MISS)$", "true","false")}V,の『~』の部分でエラーとなりますので、file()を使い、何か値を差し込みたいところはreplace()関数を使うなどして対応するといいでしょう。

まとめ

FastlyのログをDatadogに送る方法についてまとめてみました。
APIキーを発行して、あらかじめ用意されているDatadog用の設定をするだけですぐに使用できます。

あとは自分たちの運用にあわせてカスタマイズしていくだけです。Datadog上でのログ管理がどんどん便利になりますよ!

https://www.fastly.com/documentation/ja/guides/integrations/streaming-logs/custom-log-formats/
https://www.fastly.com/documentation/reference/vcl/variables/

スペースマーケット Engineer Blog

Discussion