Openstatus www.openstatus.dev
at be8b3dce20e2a4122fcd2d6e643e11905aa31457 115 lines 2.4 kB view raw
1import { AsyncLocalStorage } from "node:async_hooks"; 2 3import { sentry } from "@hono/sentry"; 4import { 5 configureSync, 6 getConsoleSink, 7 getLogger, 8 jsonLinesFormatter, 9 withContext, 10} from "@logtape/logtape"; 11import { Hono } from "hono"; 12import { showRoutes } from "hono/dev"; 13 14import { prettyJSON } from "hono/pretty-json"; 15import { requestId } from "hono/request-id"; 16import { env } from "./env"; 17import { handleError } from "./libs/errors"; 18import { publicRoute } from "./routes/public"; 19import { api } from "./routes/v1"; 20 21configureSync({ 22 sinks: { 23 console: getConsoleSink({ formatter: jsonLinesFormatter }), 24 }, 25 loggers: [ 26 { 27 category: "api-server", 28 lowestLevel: "debug", 29 sinks: ["console"], 30 }, 31 ], 32 contextLocalStorage: new AsyncLocalStorage(), 33}); 34 35const logger = getLogger("api-server"); 36 37export const app = new Hono({ strict: false }); 38 39/** 40 * Middleware 41 */ 42app.use("*", sentry({ dsn: process.env.SENTRY_DSN })); 43app.use("*", requestId()); 44// app.use("*", logger()); 45app.use("*", prettyJSON()); 46 47app.use("*", async (c, next) => { 48 const requestId = c.get("requestId"); 49 const startTime = Date.now(); 50 51 await withContext( 52 { 53 requestId, 54 method: c.req.method, 55 url: c.req.url, 56 userAgent: c.req.header("User-Agent"), 57 // ipAddress: c.req.header("CF-Connecting-IP") || c.req.header("X-Forwarded-For") 58 }, 59 async () => { 60 logger.info("Request started", { 61 method: c.req.method, 62 url: c.req.url, 63 requestId, 64 }); 65 66 await next(); 67 68 const duration = Date.now() - startTime; 69 logger.info("Request completed", { 70 status: c.res.status, 71 duration, 72 requestId, 73 }); 74 }, 75 ); 76}); 77 78app.onError(handleError); 79 80/** 81 * Public Routes 82 */ 83app.route("/public", publicRoute); 84 85/** 86 * Ping Pong 87 */ 88app.get("/ping", (c) => { 89 return c.json( 90 { ping: "pong", region: env.FLY_REGION, requestId: c.get("requestId") }, 91 200, 92 ); 93}); 94 95/** 96 * API Routes v1 97 */ 98app.route("/v1", api); 99 100/** 101 * TODO: move to `workflows` app 102 * This route is used by our checker to update the status of the monitors, 103 * create incidents, and send notifications. 104 */ 105 106const isDev = process.env.NODE_ENV === "development"; 107const port = 3000; 108 109if (isDev) showRoutes(app, { verbose: true, colorize: true }); 110 111console.log(`Starting server on port ${port}`); 112 113const server = { port, fetch: app.fetch }; 114 115export default server;