From b36975b68034cd2fc56849e26cda43aee9954a00 Mon Sep 17 00:00:00 2001 From: Sven laptop Date: Wed, 23 Sep 2026 20:00:30 +0200 Subject: [PATCH] Add comprehensive local logging to all microservices; log all errors locally and forward to error_log_api --- auth_api/index.js | 40 ++++++++++++++++++++++++++-------------- employee_api/index.js | 20 +++++++++++--------- error_log_api/index.js | 18 ++++++++++++++---- transit_api/index.js | 4 +++- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/auth_api/index.js b/auth_api/index.js index a8d783b..1dab1a6 100644 --- a/auth_api/index.js +++ b/auth_api/index.js @@ -55,6 +55,7 @@ app.use((req, res, next) => { if (res.statusCode >= 400 && body && typeof body === "object") { const rawError = body.error || body.message || body.details || `HTTP ${res.statusCode}`; + log("warn", `HTTP ${res.statusCode}`, { path: req.originalUrl, method: req.method, error: rawError }); void reportError({ partofservice: `${req.method} ${req.originalUrl}`, error: rawError, @@ -86,10 +87,16 @@ app.post("/login", async (req, res) => { [userCode], ); const user = result.rows[0]; - if (!user) return res.status(401).json({ error: "invalid_credentials" }); + if (!user) { + log("warn", "Login attempt for non-existent user", { userCode }); + return res.status(401).json({ error: "invalid_credentials" }); + } const ok = await bcrypt.compare(password, user.password); - if (!ok) return res.status(401).json({ error: "invalid_credentials" }); + if (!ok) { + log("warn", "Invalid password for user", { userCode }); + return res.status(401).json({ error: "invalid_credentials" }); + } const isAdmin = ADMIN_USER_CODES.has(Number(user.usercode)); const payload = { @@ -99,6 +106,7 @@ app.post("/login", async (req, res) => { }; const token = jwt.sign(payload, JWT_SECRET, { expiresIn: "1h" }); + log("info", "User logged in", { userCode: user.usercode, isAdmin }); res.json({ token, user: { @@ -109,28 +117,25 @@ app.post("/login", async (req, res) => { }, }); } catch (err) { - await reportError({ - partofservice: `${req.method} ${req.originalUrl}`, - error: err?.stack || err?.message || String(err), - }); - console.error(err); + log("error", "Login error", { error: err.message, stack: err.stack }); + reportError({ partofservice: `${req.method} ${req.originalUrl}`, error: err.stack || err.message }); res.status(500).json({ error: friendlyErrorMessage(500) }); } }); app.get("/me", async (req, res) => { const auth = req.headers.authorization; - if (!auth || !auth.startsWith("Bearer ")) + if (!auth || !auth.startsWith("Bearer ")) { + log("warn", "Missing or invalid Authorization header", { path: req.originalUrl }); return res.status(401).json({ error: "missing_token" }); + } const token = auth.slice(7); try { const payload = jwt.verify(token, JWT_SECRET); res.json({ user: payload }); } catch (err) { - void reportError({ - partofservice: `${req.method} ${req.originalUrl}`, - error: err?.stack || err?.message || String(err), - }); + log("error", "JWT verification failed", { error: err.message, stack: err.stack }); + reportError({ partofservice: `${req.method} ${req.originalUrl}`, error: err.stack || err.message }); res.status(401).json({ error: friendlyErrorMessage(401) }); } }); @@ -143,8 +148,15 @@ app.get("/me", async (req, res) => { const PORT = process.env.PORT || 5000; app.listen(PORT, () => console.log(`Auth API listening on ${PORT}`)); -app.get("/health", (_req, res) => { - res.json({ status: "ok", service: "auth_api" }); +app.get("/health", async (_req, res) => { + try { + await db.query("SELECT 1"); + res.json({ status: "ok", service: "auth_api", database: "ok" }); + } catch (err) { + log("error", "Health check DB query failed", { error: err.message, stack: err.stack }); + reportError({ partofservice: "GET /health", error: err.stack || err.message }); + res.status(503).json({ status: "unavailable", service: "auth_api" }); + } }); module.exports = app; diff --git a/employee_api/index.js b/employee_api/index.js index b7327f5..c194d75 100644 --- a/employee_api/index.js +++ b/employee_api/index.js @@ -51,6 +51,7 @@ app.use((req, res, next) => { if (res.statusCode >= 400 && body && typeof body === "object") { const rawError = body.error || body.message || body.details || `HTTP ${res.statusCode}`; + log("warn", `HTTP ${res.statusCode}`, { path: req.originalUrl, method: req.method, error: rawError }); void reportError({ partofservice: `${req.method} ${req.originalUrl}`, error: rawError, @@ -67,10 +68,12 @@ app.use((req, res, next) => { app.post("/createemployee", async (req, res) => { try { const { firstname, lastname, job, password } = req.body; - if (!firstname || !lastname || !job || !password) + if (!firstname || !lastname || !job || !password) { + log("warn", "Missing required fields in createemployee", { body: req.body }); return res.status(400).json({ error: "Firstname, Lastname, Job title and password are required", }); + } const resultCreateEmployee = await db.query( "INSERT INTO workers.employees (firstname, lastname, job) VALUES ($1, $2, $3) RETURNING id", @@ -83,15 +86,13 @@ app.post("/createemployee", async (req, res) => { [newEmployee.id, encryptedpassword], ); const newUser = resultCreateUser.rows[0]; + log("info", "Employee created", { employeeId: newEmployee.id, userCode: newUser.usercode }); return res .status(201) - .json({ employee: firstname, code: newUser.usercoden }); + .json({ employee: firstname, code: newUser.usercode }); } catch (err) { - void reportError({ - partofservice: `${req.method} ${req.originalUrl}`, - error: err?.stack || err?.message || String(err), - }); - console.error(err); + log("error", "Create employee error", { error: err.message, stack: err.stack }); + reportError({ partofservice: `${req.method} ${req.originalUrl}`, error: err.stack || err.message }); res.status(500).json({ error: friendlyErrorMessage(500) }); } }); @@ -101,12 +102,13 @@ app.get("/health", async (_req, res) => { await db.query("SELECT 1"); return res.status(200).json({ endpoint: "reachable", database: "ok" }); } catch (err) { - console.error(err); + log("error", "Health check DB query failed", { error: err.message, stack: err.stack }); + reportError({ partofservice: "GET /health", error: err.stack || err.message }); res.status(503).json({ endpoint: "unreachable", database: "down" }); } }); const PORT = process.env.PORT || 4000; -app.listen(PORT, () => console.log(`Auth API listening on ${PORT}`)); +app.listen(PORT, () => console.log(`Employee API listening on ${PORT}`)); module.exports = app; diff --git a/error_log_api/index.js b/error_log_api/index.js index a5c4a87..3c4d6ce 100644 --- a/error_log_api/index.js +++ b/error_log_api/index.js @@ -64,6 +64,7 @@ app.use((req, res, next) => { if (res.statusCode >= 400 && body && typeof body === "object") { const rawError = body.error || body.message || body.details || `HTTP ${res.statusCode}`; + log("warn", `HTTP ${res.statusCode}`, { path: req.originalUrl, method: req.method, error: rawError }); void reportError({ partofservice: `${req.method} ${req.originalUrl}`, error: rawError, @@ -110,18 +111,22 @@ async function insertErrorLog({ function verifyAdmin(req, res, next) { const auth = req.headers.authorization; if (!auth || !auth.startsWith("Bearer ")) { + log("warn", "Missing or invalid Authorization header", { path: req.originalUrl }); return res.status(401).json({ error: toFriendlyError(401) }); } try { const payload = jwt.verify(auth.slice(7), JWT_SECRET); if (!payload?.isAdmin) { + log("warn", "Non-admin user attempted admin access", { userCode: payload?.userCode, path: req.originalUrl }); return res.status(403).json({ error: toFriendlyError(403) }); } req.user = payload; return next(); } catch (err) { + log("error", "JWT verification failed", { error: err.message, path: req.originalUrl }); + reportError({ partofservice: `verifyAdmin ${req.method} ${req.originalUrl}`, error: err.stack || err.message }); return res.status(401).json({ error: toFriendlyError(401) }); } } @@ -131,7 +136,8 @@ app.get("/health", async (_req, res) => { await db.query("SELECT 1"); res.json({ status: "ok", service: "error_log_api", database: "ok" }); } catch (err) { - console.error("GET /health error:", err); + log("error", "Health check DB query failed", { error: err.message, stack: err.stack }); + reportError({ partofservice: "GET /health", error: err.stack || err.message }); res.status(503).json({ status: "unavailable", service: "error_log_api" }); } }); @@ -144,13 +150,15 @@ app.post("/error_log", async (req, res) => { const error = req.body?.error; if (!service || !error) { + log("warn", "Missing required fields in error_log", { body: req.body }); return res.status(400).json({ error: toFriendlyError(400) }); } await insertErrorLog({ service, partofservice, error }); return res.status(201).json({ ok: true }); } catch (err) { - console.error("POST /error_log failed:", err); + log("error", "POST /error_log failed", { error: err.message, stack: err.stack }); + reportError({ partofservice: "POST /error_log", error: err.stack || err.message }); return res.status(500).json({ error: toFriendlyError(500) }); } }); @@ -189,12 +197,14 @@ app.get("/error_log", verifyAdmin, async (req, res) => { return res.json({ errors: rows.rows }); } catch (err) { - console.error("GET /error_log failed:", err); + log("error", "GET /error_log failed", { error: err.message, stack: err.stack }); + reportError({ partofservice: "GET /error_log", error: err.stack || err.message }); return res.status(500).json({ error: toFriendlyError(500) }); } }); app.use(async (err, req, res, _next) => { + log("error", "Unhandled error", { error: err?.message, stack: err?.stack, path: req.originalUrl }); try { await insertErrorLog({ service: "error_log_api", @@ -202,7 +212,7 @@ app.use(async (err, req, res, _next) => { error: err?.stack || err?.message || String(err), }); } catch (logErr) { - console.error("Failed to log internal error:", logErr); + log("error", "Failed to log internal error", { error: logErr.message }); } if (res.headersSent) return; diff --git a/transit_api/index.js b/transit_api/index.js index 9786123..78cfef0 100644 --- a/transit_api/index.js +++ b/transit_api/index.js @@ -54,6 +54,7 @@ app.use((req, res, next) => { if (res.statusCode >= 400 && body && typeof body === "object") { const rawError = body.error || body.message || body.details || `HTTP ${res.statusCode}`; + log("warn", `HTTP ${res.statusCode}`, { path: req.originalUrl, method: req.method, error: rawError }); void reportError({ partofservice: `${req.method} ${req.originalUrl}`, error: rawError, @@ -71,7 +72,8 @@ app.get("/health", async (_req, res) => { await db.query("SELECT 1"); res.json({ status: "ok", service: "transit_api", database: "ok" }); } catch (err) { - console.error("GET /health error:", err); + log("error", "GET /health error", { error: err.message, stack: err.stack }); + reportError({ partofservice: "GET /health", error: err.stack || err.message }); res.status(503).json({ status: "unavailable", service: "transit_api" }); } });