aboutsummaryrefslogtreecommitdiffstats
path: root/packages/api
diff options
context:
space:
mode:
Diffstat (limited to 'packages/api')
-rw-r--r--packages/api/index.ts5
-rw-r--r--packages/api/middlewares/prometheusAuth.ts33
-rw-r--r--packages/api/package.json1
-rw-r--r--packages/api/routes/metrics.ts16
4 files changed, 54 insertions, 1 deletions
diff --git a/packages/api/index.ts b/packages/api/index.ts
index 2eb22d8f..4103e033 100644
--- a/packages/api/index.ts
+++ b/packages/api/index.ts
@@ -10,6 +10,7 @@ import bookmarks from "./routes/bookmarks";
import health from "./routes/health";
import highlights from "./routes/highlights";
import lists from "./routes/lists";
+import metrics, { registerMetrics } from "./routes/metrics";
import publicRoute from "./routes/public";
import rss from "./routes/rss";
import tags from "./routes/tags";
@@ -37,6 +38,7 @@ const app = new Hono<{
}>()
.use(logger())
.use(poweredBy())
+ .use("*", registerMetrics)
.use(async (c, next) => {
// Ensure that the ctx is set
if (!c.var.ctx) {
@@ -49,6 +51,7 @@ const app = new Hono<{
.route("/trpc", trpc)
.route("/v1", v1)
.route("/assets", assets)
- .route("/public", publicRoute);
+ .route("/public", publicRoute)
+ .route("/metrics", metrics);
export default app;
diff --git a/packages/api/middlewares/prometheusAuth.ts b/packages/api/middlewares/prometheusAuth.ts
new file mode 100644
index 00000000..bf35608f
--- /dev/null
+++ b/packages/api/middlewares/prometheusAuth.ts
@@ -0,0 +1,33 @@
+import { createMiddleware } from "hono/factory";
+import { HTTPException } from "hono/http-exception";
+
+import serverConfig from "@karakeep/shared/config";
+
+export const prometheusAuthMiddleware = createMiddleware(async (c, next) => {
+ const { metricsToken } = serverConfig.prometheus;
+
+ // If no token is configured, deny access (safe default)
+ if (!metricsToken) {
+ throw new HTTPException(404, {
+ message: "Not Found",
+ });
+ }
+
+ const auth = c.req.header("Authorization");
+
+ if (!auth || !auth.startsWith("Bearer ")) {
+ throw new HTTPException(401, {
+ message: "Unauthorized",
+ });
+ }
+
+ const token = auth.slice(7); // Remove "Bearer " prefix
+
+ if (token !== metricsToken) {
+ throw new HTTPException(401, {
+ message: "Unauthorized",
+ });
+ }
+
+ await next();
+});
diff --git a/packages/api/package.json b/packages/api/package.json
index 54656e64..18d70501 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -13,6 +13,7 @@
"test": "vitest"
},
"dependencies": {
+ "@hono/prometheus": "^1.0.2",
"@hono/trpc-server": "^0.4.0",
"@hono/zod-validator": "^0.5.0",
"@karakeep/db": "workspace:*",
diff --git a/packages/api/routes/metrics.ts b/packages/api/routes/metrics.ts
new file mode 100644
index 00000000..90eff5b9
--- /dev/null
+++ b/packages/api/routes/metrics.ts
@@ -0,0 +1,16 @@
+// Import stats to register Prometheus metrics
+import "@karakeep/trpc/stats";
+
+import { prometheus } from "@hono/prometheus";
+import { Hono } from "hono";
+import { register } from "prom-client";
+
+import { prometheusAuthMiddleware } from "../middlewares/prometheusAuth";
+
+export const { printMetrics, registerMetrics } = prometheus({
+ registry: register,
+});
+
+const app = new Hono().get("/", prometheusAuthMiddleware, printMetrics);
+
+export default app;