diff --git a/README.md b/README.md index adecad0..05d9286 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ Express 5 + TypeScript backend generated from `nholtware/service-template-expres - `GET /healthz` liveness, always 200 once listening - `GET /readyz` readiness: Postgres `SELECT 1` and Redis `PING` for whichever of `DATABASE_URL` / `REDIS_URL` are set; 503 + JSON reason otherwise - `GET /` service name, version (git sha), pod, a `service_info` row, Redis hit counter -- `GET /log-demo?msg=...` logs `{ demo: true, text }` with message `log-demo` (logging-pipeline demo; delete when you don't need it) ## Local dev @@ -21,20 +20,6 @@ Env is validated at boot (`src/lib/config.ts`): `PORT`, `SERVICE_NAME` (required Migrations: SQL files in `migrations/`, applied with `npm run migrate`. Logs: one JSON object per line on stdout (`level,time,msg,service,version`, plus `req.*`/`res.statusCode`/`responseTime` per request). -## Seeing your logs - -Every container's stdout is shipped to Elasticsearch by Fluent Bit; nothing to configure per service. - -1. Open Kibana: http://kibana.192.168.1.83.nip.io, user `elastic`, password from - `kubectl get secret -n logging logging-es-elastic-user -o jsonpath='{.data.elastic}' | base64 -d`. -2. **Discover**, data view `kube-*` (the default). -3. Query with KQL, e.g. `service:"${REPO_NAME}" and demo:true`, or `service:"${REPO_NAME}" and level:"error"`. - -Any field you pass to the logger becomes a queryable field: -`req.log.info({ orderId }, "order placed")` → KQL `orderId:123`. The message string always -overrides a `msg` key in the object, so don't name a field `msg`. Lines show up within ~10 s; -retention is 14 days. - ## Using this template 1. **Generate** a repo from this template in Forgejo (public). The repo name is substituted into `package.json`, this README, `.env.example`, and the first migration (CI derives the app name from the repo name itself). diff --git a/src/app.test.ts b/src/app.test.ts index 2cddb5e..54e64a0 100644 --- a/src/app.test.ts +++ b/src/app.test.ts @@ -67,26 +67,3 @@ describe("routes", () => { expect(b.headers["x-request-id"]).toMatch(/^[0-9a-f-]{36}$/); }); }); - -describe("log-demo", () => { - it("logs one JSON line with demo fields and the request id", async () => { - const lines: Record[] = []; - const captured = pino( - { base: { service: "test-svc" } }, - { write: (l: string) => lines.push(JSON.parse(l)) }, - ); - const app = createApp({ config: parseConfig(base), logger: captured }); - const res = await request(app) - .get("/log-demo?msg=hello") - .set("X-Request-Id", "rid-demo"); - expect(res.status).toBe(200); - expect(res.body).toMatchObject({ logged: true, text: "hello" }); - const line = lines.find((l) => l.msg === "log-demo"); - expect(line).toMatchObject({ - service: "test-svc", - demo: true, - text: "hello", - req: { id: "rid-demo" }, - }); - }); -}); diff --git a/src/app.ts b/src/app.ts index ba2d677..dd409b3 100644 --- a/src/app.ts +++ b/src/app.ts @@ -6,7 +6,6 @@ import type { Config } from "./lib/config.js"; import type { Db } from "./lib/db.js"; import type { Cache } from "./lib/redis.js"; import { healthRouter } from "./routes/health.js"; -import { logDemoRouter } from "./routes/log-demo.js"; import { rootRouter } from "./routes/root.js"; export interface Deps { @@ -44,7 +43,6 @@ export function createApp({ config, logger, db, cache }: Deps) { app.use(healthRouter({ db, cache })); app.use(rootRouter({ config, db, cache })); - app.use(logDemoRouter()); // Express identifies error handlers by arity; keep all four args. // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/src/routes/log-demo.ts b/src/routes/log-demo.ts deleted file mode 100644 index 02356de..0000000 --- a/src/routes/log-demo.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Router } from "express"; - -// Developer-story demo for the logging pipeline: every field in the first -// argument to req.log.* becomes a queryable field in Kibana (data view kube-*). -// The message string always wins over a `msg` key in the object, so the -// caller's text goes in `text`. -export function logDemoRouter(): Router { - const router = Router(); - - router.get("/log-demo", (req, res) => { - const text = typeof req.query.msg === "string" ? req.query.msg : ""; - req.log.info({ demo: true, text }, "log-demo"); - res.json({ logged: true, text, requestId: req.id }); - }); - - return router; -}