add metrics middleware to ogcard service
This commit is contained in:
@@ -14,13 +14,16 @@
|
|||||||
"@atproto/common": "^0.4.0",
|
"@atproto/common": "^0.4.0",
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
"express": "^4.19.2",
|
"express": "^4.19.2",
|
||||||
|
"express-prom-bundle": "^7.0.0",
|
||||||
"http-terminator": "^3.2.0",
|
"http-terminator": "^3.2.0",
|
||||||
"pino": "^9.2.0",
|
"pino": "^9.2.0",
|
||||||
|
"prom-client": "^15.1.3",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"satori": "^0.10.13",
|
"satori": "^0.10.13",
|
||||||
"twemoji": "^14.0.2"
|
"twemoji": "^14.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
"@types/node": "^20.14.3",
|
"@types/node": "^20.14.3",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export type Config = {
|
|||||||
|
|
||||||
export type ServiceConfig = {
|
export type ServiceConfig = {
|
||||||
port: number
|
port: number
|
||||||
|
metricsPort: number
|
||||||
version?: string
|
version?: string
|
||||||
appviewUrl: string
|
appviewUrl: string
|
||||||
originVerify?: string
|
originVerify?: string
|
||||||
@@ -13,6 +14,7 @@ export type ServiceConfig = {
|
|||||||
|
|
||||||
export type Environment = {
|
export type Environment = {
|
||||||
port?: number
|
port?: number
|
||||||
|
metricsPort?: number
|
||||||
version?: string
|
version?: string
|
||||||
appviewUrl?: string
|
appviewUrl?: string
|
||||||
originVerify?: string
|
originVerify?: string
|
||||||
@@ -21,6 +23,7 @@ export type Environment = {
|
|||||||
export const readEnv = (): Environment => {
|
export const readEnv = (): Environment => {
|
||||||
return {
|
return {
|
||||||
port: envInt('CARD_PORT'),
|
port: envInt('CARD_PORT'),
|
||||||
|
metricsPort: envInt('CARD_METRICS_PORT'),
|
||||||
version: envStr('CARD_VERSION'),
|
version: envStr('CARD_VERSION'),
|
||||||
appviewUrl: envStr('CARD_APPVIEW_URL'),
|
appviewUrl: envStr('CARD_APPVIEW_URL'),
|
||||||
originVerify: envStr('CARD_ORIGIN_VERIFY'),
|
originVerify: envStr('CARD_ORIGIN_VERIFY'),
|
||||||
@@ -30,6 +33,7 @@ export const readEnv = (): Environment => {
|
|||||||
export const envToCfg = (env: Environment): Config => {
|
export const envToCfg = (env: Environment): Config => {
|
||||||
const serviceCfg: ServiceConfig = {
|
const serviceCfg: ServiceConfig = {
|
||||||
port: env.port ?? 3000,
|
port: env.port ?? 3000,
|
||||||
|
metricsPort: env.metricsPort ?? 3001,
|
||||||
version: env.version,
|
version: env.version,
|
||||||
appviewUrl: env.appviewUrl ?? 'https://api.bsky.app',
|
appviewUrl: env.appviewUrl ?? 'https://api.bsky.app',
|
||||||
originVerify: env.originVerify,
|
originVerify: env.originVerify,
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import events from 'node:events'
|
|||||||
import type http from 'node:http'
|
import type http from 'node:http'
|
||||||
|
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
import promBundle from 'express-prom-bundle'
|
||||||
import {createHttpTerminator, type HttpTerminator} from 'http-terminator'
|
import {createHttpTerminator, type HttpTerminator} from 'http-terminator'
|
||||||
|
import {register} from 'prom-client'
|
||||||
|
|
||||||
import {type Config} from './config.js'
|
import {type Config} from './config.js'
|
||||||
import {AppContext} from './context.js'
|
import {AppContext} from './context.js'
|
||||||
@@ -13,7 +15,9 @@ export * from './logger.js'
|
|||||||
|
|
||||||
export class CardService {
|
export class CardService {
|
||||||
public server?: http.Server
|
public server?: http.Server
|
||||||
|
public metricsServer?: http.Server
|
||||||
private terminator?: HttpTerminator
|
private terminator?: HttpTerminator
|
||||||
|
private metricsTerminator?: HttpTerminator
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public app: express.Application,
|
public app: express.Application,
|
||||||
@@ -24,6 +28,23 @@ export class CardService {
|
|||||||
let app = express()
|
let app = express()
|
||||||
|
|
||||||
const ctx = await AppContext.fromConfig(cfg)
|
const ctx = await AppContext.fromConfig(cfg)
|
||||||
|
|
||||||
|
// Add Prometheus middleware for automatic HTTP instrumentation
|
||||||
|
const metricsMiddleware = promBundle({
|
||||||
|
includeMethod: true,
|
||||||
|
includePath: true,
|
||||||
|
includeStatusCode: true,
|
||||||
|
includeUp: true,
|
||||||
|
promClient: {
|
||||||
|
collectDefaultMetrics: {
|
||||||
|
timeout: 5000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Don't expose /metrics on main app - we'll use separate server
|
||||||
|
autoregister: false,
|
||||||
|
})
|
||||||
|
app.use(metricsMiddleware)
|
||||||
|
|
||||||
app = routes(ctx, app)
|
app = routes(ctx, app)
|
||||||
app.use(errorHandler)
|
app.use(errorHandler)
|
||||||
|
|
||||||
@@ -31,14 +52,27 @@ export class CardService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
|
// Start main application server
|
||||||
this.server = this.app.listen(this.ctx.cfg.service.port)
|
this.server = this.app.listen(this.ctx.cfg.service.port)
|
||||||
this.server.keepAliveTimeout = 90000
|
this.server.keepAliveTimeout = 90000
|
||||||
this.terminator = createHttpTerminator({server: this.server})
|
this.terminator = createHttpTerminator({server: this.server})
|
||||||
await events.once(this.server, 'listening')
|
await events.once(this.server, 'listening')
|
||||||
|
|
||||||
|
// Start separate metrics server
|
||||||
|
const metricsApp = express()
|
||||||
|
metricsApp.get('/metrics', (_req, res) => {
|
||||||
|
res.set('Content-Type', register.contentType)
|
||||||
|
res.end(register.metrics())
|
||||||
|
})
|
||||||
|
|
||||||
|
this.metricsServer = metricsApp.listen(this.ctx.cfg.service.metricsPort)
|
||||||
|
this.metricsTerminator = createHttpTerminator({server: this.metricsServer})
|
||||||
|
await events.once(this.metricsServer, 'listening')
|
||||||
}
|
}
|
||||||
|
|
||||||
async destroy() {
|
async destroy() {
|
||||||
this.ctx.abortController.abort()
|
this.ctx.abortController.abort()
|
||||||
await this.terminator?.terminate()
|
await this.terminator?.terminate()
|
||||||
|
await this.metricsTerminator?.terminate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user