49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import { formatMetrics } from "@/shared/prometheus";
|
|
|
|
export async function metricsResponse(
|
|
request: Pick<Request, "headers">,
|
|
read: (tokenHash: string) => Promise<unknown>,
|
|
) {
|
|
const headers = {
|
|
"Cache-Control": "private, no-store",
|
|
"X-Content-Type-Options": "nosniff",
|
|
};
|
|
const match = /^Bearer (mg_metrics_[a-f0-9]{64})$/.exec(
|
|
request.headers.get("authorization") ?? "",
|
|
);
|
|
if (!match)
|
|
return new Response("Metrics authentication required\n", {
|
|
status: 401,
|
|
headers: { ...headers, "WWW-Authenticate": "Bearer" },
|
|
});
|
|
try {
|
|
const start = performance.now();
|
|
const snapshot = await read(
|
|
createHash("sha256").update(match[1]).digest("hex"),
|
|
);
|
|
if (snapshot === null)
|
|
return new Response("Metrics authentication required\n", {
|
|
status: 401,
|
|
headers: { ...headers, "WWW-Authenticate": "Bearer" },
|
|
});
|
|
const body =
|
|
formatMetrics(snapshot) +
|
|
"# HELP minegeo_exporter_read_duration_seconds Time to read and validate the database snapshot.\n" +
|
|
"# TYPE minegeo_exporter_read_duration_seconds gauge\n" +
|
|
`minegeo_exporter_read_duration_seconds ${(performance.now() - start) / 1000}\n`;
|
|
return new Response(body, {
|
|
headers: {
|
|
...headers,
|
|
"Content-Type": "text/plain; version=0.0.4; charset=utf-8",
|
|
},
|
|
});
|
|
} catch {
|
|
// Never return database errors, credentials, or a misleading all-zero snapshot.
|
|
return new Response("Metrics temporarily unavailable\n", {
|
|
status: 503,
|
|
headers,
|
|
});
|
|
}
|
|
}
|