🧊

Cloudflare R2に保存した、Workers Trace Events Logpushのデータを見る

Logpush · Cloudflare Workers docs https://developers.cloudflare.com/workers/observability/logging/logpush/

3rdの監視サービスに連携してる場合は、こんな地道なことをする必要はない。

けど、まあたまに必要になるので・・・。

R2の保存形式

Logpushを有効化し、保存先をR2にした場合、そのバケットにはこんな風にログが溜まっていく。

  • 20240501/20240501T004901Z_20240501T004901Z_1747b6ef.log.gz
  • 20240501/20240501T005251Z_20240501T005251Z_7d19e3fe.log.gz
  • 20240501/20240501T005937Z_20240501T005937Z_660b60c6.log.gz

YYYYMMDD/からはじまり、fromTime_toTime_hash.log.gzという感じ。

この日付やタイムゾーンはUTCらしい。

R2から取得

というわけで、R2のAPIを使って、バケットからまずはログファイルを落としてくる。

R2.list()でキーを割り出し、R2.get()でファイルの実体にアクセスする。

const keys: Array<string> = [];

let cursor: string | undefined;
while (true) {
  const list = await LOGPUSH.list({
    // 日付によってフィルタするならココで
    // prefix: "20240501",
    cursor,
  });

  for (const item of list.objects) {
    const [_, name] = item.key.split("/");
    const [fromTime, toTime] = name.split("_");
    const [from, to] = [toDate(fromTime), toDate(toTime)];

    // 時間によってフィルタするならココで

    keys.push(item.key);
  }

  if (!list.truncated) { break; }
  cursor = list.cursor;
}

function toDate(t: string) {
  const [date, time] = t.split("T");
  return new Date(
    Date.UTC(
      Number(date.slice(0, 4)),
      Number(date.slice(4, 6)),
      Number(date.slice(6, 8)),
      Number(time.slice(0, 2)),
      Number(time.slice(2, 4)),
      Number(time.slice(4, 6)),
    ),
  );
};

フィルタするとき、日付はUTCベースであることに気をつける。

これでキーが得られたので、それを使って.gzをダウンロードして解凍する。

import { gunzipSync } from "node:zlib";

let json = "";
for (const key of keys) {
  const r2o = await LOGPUSH.get(key);
  if (r2o === null) { continue; }

  const buffer = await r2o.arrayBuffer();
  const buf = gunzipSync(buffer);

  // 改行区切りで複数のアイテムが入ってる可能性がある
  // なので`JSON.parse()`にそのままかけるとエラーになる
  const str = buf.toString();
  json += str + "\n";
}

こうすると、改行ごとに1JSONが並んだテキストが得られるようになる。

あとは煮るなり焼くなり。

データの形式

{
    "Event":{
        "RayID":"12fc93e241586f47",
        "Request":{
            "URL": "https://example.com/dummy",
            "Method":"GET"
        },
        "Response":{
            "Status":200
        }
    },
    "EventTimestampMs":1715036498250,
    "EventType":"fetch",
    "Exceptions":[],
    "Logs":[],
    "Outcome":"ok",
    "ScriptName":"my-dummy-api",
    "ScriptTags":[]
}

いわゆるfetchイベントによる記録はこんな感じ。

console.log()を使ってると、Logsの配列にそのデータが入ってくる。