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
の配列にそのデータが入ってくる。