about summary refs log tree commit diff stats
path: root/src/index.ts
diff options
context:
space:
mode:
authorAlan Pearce2023-09-13 15:55:48 +0200
committerAlan Pearce2023-09-13 16:57:07 +0200
commit627aec8448ca075ea4bf87f85229c67a7374eac0 (patch)
tree9a91925e1b3df03cc9965e879338fbe44064b0c7 /src/index.ts
parentae9de0eaaf7f6f5aa6114671aefe297ce6e8f3f1 (diff)
downloadwebsite-627aec8448ca075ea4bf87f85229c67a7374eac0.tar.lz
website-627aec8448ca075ea4bf87f85229c67a7374eac0.tar.zst
website-627aec8448ca075ea4bf87f85229c67a7374eac0.zip
Collect metrics for prometheus
Diffstat (limited to 'src/index.ts')
-rw-r--r--src/index.ts38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/index.ts b/src/index.ts
index ff154fa..6699a10 100644
--- a/src/index.ts
+++ b/src/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 @@ type File = {
   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 @@ async function serveFile(
   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 @@ async function serveFile(
       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") || "")