all repos — homestead @ 627aec8448ca075ea4bf87f85229c67a7374eac0

Code for my website

Collect metrics for prometheus

Alan Pearce
commit

627aec8448ca075ea4bf87f85229c67a7374eac0

parent

ae9de0eaaf7f6f5aa6114671aefe297ce6e8f3f1

3 files changed, 39 insertions(+), 0 deletions(-)

jump to
M bun.lockbbun.lockb

Not showing binary file.

M package.jsonpackage.json
@@ -9,6 +9,7 @@ "typescript": "^5.0.0"
}, "type": "module", "dependencies": { + "bun-prometheus-client": "^0.0.2", "toml": "^3.0.0" } }
M src/index.tssrc/index.ts
@@ -1,6 +1,7 @@
import path from "node:path"; import fs, { Stats } from "node:fs"; import type { BunFile, Serve } from "bun"; +import prom from "bun-prometheus-client"; import readConfig from "./config";
@@ -22,6 +23,26 @@ size: number;
mtime: Date; }; +const collectDefaultMetrics = prom.collectDefaultMetrics; +collectDefaultMetrics({ + labels: { + FLY_APP_NAME: Bun.env.FLY_APP_NAME, + FLY_ALLOC_ID: Bun.env.FLY_ALLOC_ID, + FLY_REGION: Bun.env.FLY_REGION, + }, +}); +const counters = { + requestsByStatus: new prom.Counter({ + name: "requests_by_status", + help: "Number of requests by status code", + labelNames: ["status_code"], + }), + requestsByPath: new prom.Counter({ + name: "requests_by_path", + help: "Number of requests by path", + }), +}; + let files = new Map<string, File>(); function registerFile(
@@ -77,6 +98,7 @@ statusCode: number = 200,
extraHeaders: Record<string, string> = {}, ): Promise<Response> { if (file && (await file.handle.exists())) { + counters.requestsByStatus.inc({ status_code: statusCode }); return new Response(file.handle, { headers: { "last-modified": file.mtime.toUTCString(),
@@ -86,6 +108,7 @@ },
status: statusCode, }); } else { + counters.requestsByStatus.inc({ status_code: 404 }); // TODO return encoded return serveFile(files.get("/404.html"), 404); }
@@ -105,15 +128,30 @@ function parseIfModifiedSinceHeader(header: string | null): number {
return header ? new Date(header).getTime() + 999 : 0; } +Bun.serve({ + port: 9091, + fetch: async function (request) { + const pathname = new URL(request.url).pathname; + switch (pathname) { + case "/metrics": + return new Response(await prom.register.metrics()); + default: + return new Response("", { status: 404 }); + } + }, +}); + export default { fetch: async function (request) { const pathname = new URL(request.url).pathname; const file = files.get(pathname); + counters.requestsByPath.inc({ path: pathname }); if (file) { if ( parseIfModifiedSinceHeader(request.headers.get("if-modified-since")) >= file?.mtime.getTime() ) { + counters.requestsByStatus.inc({ status_code: 304 }); return new Response("", { status: 304, headers: defaultHeaders }); } const encodings = (request.headers.get("accept-encoding") || "")