fix(datum): surface fetch error cause + url in logs
Node's fetch wraps the underlying network error in `.cause`; the bare `err.message` is just "fetch failed" which tells us nothing about DNS vs connection refused vs network unreachable. Add formatErr() that walks .cause and includes its .code, plus the url being attempted, so logs distinguish between the actual failure modes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,16 @@ let lastSnapshot: DatumSnapshot = {
|
||||
};
|
||||
let timer: NodeJS.Timeout | null = null;
|
||||
|
||||
function formatErr(err: unknown): string {
|
||||
if (!(err instanceof Error)) return String(err);
|
||||
const cause = (err as Error & { cause?: unknown }).cause;
|
||||
if (cause instanceof Error) {
|
||||
const code = (cause as Error & { code?: string }).code;
|
||||
return code ? `${err.message}: ${cause.message} (${code})` : `${err.message}: ${cause.message}`;
|
||||
}
|
||||
return err.message;
|
||||
}
|
||||
|
||||
function abortableSignal(timeoutMs: number): { signal: AbortSignal; cancel: () => void } {
|
||||
const ctrl = new AbortController();
|
||||
const t = setTimeout(() => ctrl.abort(new Error("upstream_timeout")), timeoutMs);
|
||||
@@ -71,11 +81,8 @@ async function pollOnce(): Promise<DatumSnapshot> {
|
||||
threadsTimeout.cancel();
|
||||
|
||||
if (clientsResSettled.status === "rejected") {
|
||||
const reason =
|
||||
clientsResSettled.reason instanceof Error
|
||||
? clientsResSettled.reason.message
|
||||
: "unknown";
|
||||
logger.warn({ reason }, "datum_clients_fetch_failed");
|
||||
const reason = formatErr(clientsResSettled.reason);
|
||||
logger.warn({ reason, url: `${config.datum.url}/clients` }, "datum_clients_fetch_failed");
|
||||
return {
|
||||
...lastSnapshot,
|
||||
ok: false,
|
||||
@@ -110,12 +117,7 @@ async function pollOnce(): Promise<DatumSnapshot> {
|
||||
threadsHtml = await threadsResSettled.value.text();
|
||||
} else if (threadsResSettled.status === "rejected") {
|
||||
logger.warn(
|
||||
{
|
||||
reason:
|
||||
threadsResSettled.reason instanceof Error
|
||||
? threadsResSettled.reason.message
|
||||
: "unknown",
|
||||
},
|
||||
{ reason: formatErr(threadsResSettled.reason) },
|
||||
"datum_threads_fetch_failed",
|
||||
);
|
||||
}
|
||||
@@ -151,7 +153,7 @@ async function pollOnce(): Promise<DatumSnapshot> {
|
||||
} catch (err) {
|
||||
clientsTimeout.cancel();
|
||||
threadsTimeout.cancel();
|
||||
const reason = err instanceof Error ? err.message : "unknown";
|
||||
const reason = formatErr(err);
|
||||
logger.warn({ reason }, "datum_poll_unexpected_error");
|
||||
return {
|
||||
...lastSnapshot,
|
||||
|
||||
Reference in New Issue
Block a user