fix: scope request logs to incoming traffic

This commit is contained in:
2026-10-02 13:44:14 +00:00 Unverified
parent d3e9753c4b
commit 00fe2bb2a6
2 changed files with 383 additions and 28 deletions
+87 -26
View File
@@ -1,3 +1,5 @@
import { AsyncLocalStorage } from "node:async_hooks";
export type ProcessLogEntry = Record<string, unknown>;
export type ProcessLogger = {
@@ -5,6 +7,7 @@ export type ProcessLogger = {
};
const MAX_RESPONSE_LOG_BYTES = 64 * 1024;
const requestContext = new AsyncLocalStorage<{ active: boolean }>();
export function logValue(
value: unknown,
@@ -42,10 +45,63 @@ export function logValue(
}
}
const METHOD_LABELS: Record<string, string> = {
GET: "GET",
POST: "PST",
PUT: "PUT",
PATCH: "PTC",
DELETE: "DEL",
HEAD: "HED",
OPTIONS: "OPT",
CONNECT: "CON",
TRACE: "TRC",
};
function requestLine(entry: ProcessLogEntry): string | undefined {
const event = entry.event;
if (
event === "kuber.server.request.start" ||
event === "kuber.k8s.request.start" ||
event === "kuber.server.response.body"
)
return "";
const kubernetes =
event === "kuber.k8s.request.end" ||
event === "kuber.k8s.request.failed";
if (kubernetes && !requestContext.getStore()?.active) return "";
if (
!kubernetes &&
event !== "kuber.server.request.end" &&
event !== "kuber.server.request.failed"
)
return;
if (typeof entry.method !== "string" || typeof entry.pathname !== "string")
return;
if (
!kubernetes &&
entry.method.toUpperCase() === "GET" &&
entry.pathname === "/api/v2/health"
)
return "";
const method = entry.method.toUpperCase();
const label = METHOD_LABELS[method] ?? method.slice(0, 3).padEnd(3, "_");
const status =
event === "kuber.k8s.request.failed" ||
event === "kuber.server.request.failed"
? "ERR"
: entry.status;
if (typeof status !== "number" && status !== "ERR") return;
const indent = kubernetes ? " " : "";
return `${indent}${label} ${entry.pathname} ${status}`;
}
export const processLogger: ProcessLogger = {
log(entry) {
try {
console.log(`KUBER_REQUEST ${JSON.stringify(logValue(entry))}`);
const line = requestLine(entry);
if (line === "") return;
console.log(line ?? `KUBER_REQUEST ${JSON.stringify(logValue(entry))}`);
} catch {
// Process logging must never change request behavior.
}
@@ -168,33 +224,38 @@ export async function logServerRequest<T>(
headers: headers(request.headers),
};
safeLog(logger, { event: "kuber.server.request.start", ...base });
try {
const response = await handler();
safeLog(logger, {
event: "kuber.server.request.end",
...base,
status: response instanceof Response ? response.status : 101,
durationMs: Date.now() - startedAt,
...(response instanceof Response && {
responseHeaders: headers(response.headers),
}),
});
if (response instanceof Response)
logResponseBody(response, logger, {
event: "kuber.server.response.body",
const context = { active: true };
return requestContext.run(context, async () => {
try {
const response = await handler();
safeLog(logger, {
event: "kuber.server.request.end",
...base,
status: response.status,
status: response instanceof Response ? response.status : 101,
durationMs: Date.now() - startedAt,
...(response instanceof Response && {
responseHeaders: headers(response.headers),
}),
});
return response;
} catch (error) {
safeLog(logger, {
event: "kuber.server.request.failed",
...base,
durationMs: Date.now() - startedAt,
error: logValue(error),
});
throw error;
}
if (response instanceof Response)
logResponseBody(response, logger, {
event: "kuber.server.response.body",
...base,
status: response.status,
});
return response;
} catch (error) {
safeLog(logger, {
event: "kuber.server.request.failed",
...base,
durationMs: Date.now() - startedAt,
error: logValue(error),
});
throw error;
} finally {
context.active = false;
}
});
}
export async function logKubernetesRequest<T>(