Node.js Backend
import { createGunsoleClient } from "gunsole-js";
const gun = createGunsoleClient({ projectId: "my-api", apiKey: "dev", mode: "local", env: process.env.NODE_ENV, appName: "api-server", appVersion: process.env.npm_package_version, defaultTags: { service: "api", },});
// Catch unhandled errorsgun.attachGlobalErrorHandlers();Express middleware
Section titled “Express middleware”Log every request:
import express from "express";
const app = express();
app.use((req, res, next) => { const start = Date.now();
res.on("finish", () => { const duration = Date.now() - start; const level = res.statusCode >= 500 ? "error" : res.statusCode >= 400 ? "warn" : "info";
gun[level]({ bucket: "http", message: `${req.method} ${req.path} → ${res.statusCode} (${duration}ms)`, context: { method: req.method, path: req.path, statusCode: res.statusCode, duration, userAgent: req.get("user-agent"), ip: req.ip, }, tags: { method: req.method, route: req.route?.path || req.path, status: String(res.statusCode), }, }); });
next();});Database queries
Section titled “Database queries”async function query(sql, params) { const start = Date.now(); try { const result = await db.query(sql, params); gun.debug({ bucket: "db", message: `Query OK (${Date.now() - start}ms)`, context: { sql, params, rowCount: result.rowCount }, tags: { operation: sql.trim().split(" ")[0].toUpperCase() }, }); return result; } catch (err) { gun.error({ bucket: "db", message: `Query failed: ${err.message}`, context: { sql, params, error: err.message }, tags: { operation: sql.trim().split(" ")[0].toUpperCase() }, }); throw err; }}Graceful shutdown
Section titled “Graceful shutdown”Flush remaining logs before exiting:
process.on("SIGTERM", async () => { await gun.flush(); gun.destroy(); process.exit(0);});Custom fetch (Node.js < 18)
Section titled “Custom fetch (Node.js < 18)”If you’re on Node.js < 18 where fetch isn’t built-in:
import fetch from "node-fetch";
const gun = createGunsoleClient({ projectId: "my-api", apiKey: "dev", mode: "local", fetch: fetch,});