fix(lolschedule): structured error logging for cargoquery failures

Swaps the best-effort console.warn for JSON log lines emitted via
console.log so Workers Observability + wrangler tail surface the real
cause (HTTP status, API error info, or non-JSON body) when /lol_today
and /lol_week fall into the error branch.
This commit is contained in:
2026-04-21 09:51:43 +07:00
committed by Tien Nguyen Minh
parent 57c6528af7
commit 436664c8a1
3 changed files with 41 additions and 8 deletions
+29 -4
View File
@@ -51,10 +51,35 @@ async function cargoQuery(params) {
body,
cf: { cacheTtl: 30, cacheEverything: true },
});
if (!res.ok) throw new Error(`Leaguepedia API HTTP ${res.status}`);
const json = await res.json();
if (json?.error) throw new Error(`Leaguepedia error: ${json.error.info || json.error.code}`);
return (json?.cargoquery || []).map((r) => r.title);
const text = await res.text();
if (!res.ok) {
console.log(
JSON.stringify({ msg: "lolschedule_fetch", status: res.status, body: text.slice(0, 500) }),
);
throw new Error(`Leaguepedia API HTTP ${res.status}`);
}
let json;
try {
json = JSON.parse(text);
} catch {
console.log(
JSON.stringify({ msg: "lolschedule_parse_fail", body: text.slice(0, 500) }),
);
throw new Error("Leaguepedia non-JSON response");
}
if (json?.error) {
console.log(
JSON.stringify({
msg: "lolschedule_api_error",
code: json.error.code,
info: json.error.info,
}),
);
throw new Error(`Leaguepedia error: ${json.error.info || json.error.code}`);
}
const rows = (json?.cargoquery || []).map((r) => r.title);
console.log(JSON.stringify({ msg: "lolschedule_fetch_ok", rows: rows.length }));
return rows;
}
/** Format a JS Date as Leaguepedia's UTC literal: `YYYY-MM-DD HH:MM:SS`. */
+6 -2
View File
@@ -41,7 +41,9 @@ export async function handleToday(ctx, db) {
const rows = await getCachedMatches(db, from, to, CACHE_TTL_TODAY_SEC);
await ctx.reply(renderToday(rows, from), { parse_mode: "HTML" });
} catch (err) {
console.warn("lolschedule /lol_today failed", String(err));
console.log(
JSON.stringify({ msg: "lolschedule_today_fail", err: String(err) }),
);
await ctx.reply("Could not fetch today's matches. Try again later.");
}
}
@@ -61,7 +63,9 @@ export async function handleWeek(ctx, db) {
const rows = await getCachedMatches(db, from, to, CACHE_TTL_WEEK_SEC);
await ctx.reply(renderWeek(rows, from, to), { parse_mode: "HTML" });
} catch (err) {
console.warn("lolschedule /lol_week failed", String(err));
console.log(
JSON.stringify({ msg: "lolschedule_week_fail", err: String(err) }),
);
await ctx.reply("Could not fetch this week's matches. Try again later.");
}
}
+6 -2
View File
@@ -7,10 +7,12 @@ import {
import { makeFakeKv } from "../../fakes/fake-kv-namespace.js";
function cargoResponse(rows) {
const payload = { cargoquery: rows.map((title) => ({ title })) };
return {
ok: true,
status: 200,
json: async () => ({ cargoquery: rows.map((title) => ({ title })) }),
text: async () => JSON.stringify(payload),
json: async () => payload,
};
}
@@ -53,10 +55,12 @@ describe("fetchMatchesInRange", () => {
});
it("surfaces Leaguepedia API error field", async () => {
const errPayload = { error: { info: "Bad query", code: "x" } };
global.fetch = vi.fn().mockResolvedValue({
ok: true,
status: 200,
json: async () => ({ error: { info: "Bad query", code: "x" } }),
text: async () => JSON.stringify(errPayload),
json: async () => errPayload,
});
await expect(
fetchMatchesInRange(new Date("2026-04-21T00:00:00Z"), new Date("2026-04-22T00:00:00Z")),