日志与监控:集成 Sentry、Datadog、Prometheus
通过中间件收集指标:req_duration_ms, http_status
在生产环境中,可观测性(Observability) 是保障服务稳定性的核心。Hono 作为轻量级框架,虽不内置监控功能,但其灵活的中间件机制让你能轻松集成主流监控工具如 Sentry(错误追踪)、Datadog(APM & 日志)、Prometheus(指标)。
本文将展示如何通过自定义中间件,统一收集关键指标并上报。
一、核心目标
- 记录每个请求的 响应时间(
req_duration_ms) - 记录 HTTP 状态码(
http_status) - 捕获未处理异常并上报
- 支持多平台(Sentry / Datadog / Prometheus)
二、通用监控中间件设计
ts
// middleware/monitoring.ts
import { Hono } from 'hono'
type MonitoringOptions = {
sentry?: boolean
datadog?: boolean
prometheus?: boolean
}
export const monitoringMiddleware = (options: MonitoringOptions = {}) => {
// Prometheus 指标(如果启用)
let requestCounter: any = null
let durationHistogram: any = null
if (options.prometheus) {
const client = require('prom-client')
requestCounter = new client.Counter({
name: 'http_requests_total',
help: 'Total HTTP requests',
labelNames: ['method', 'path', 'status']
})
durationHistogram = new client.Histogram({
name: 'http_request_duration_ms',
help: 'Duration of HTTP requests in ms',
labelNames: ['method', 'path', 'status'],
buckets: [10, 50, 100, 200, 500, 1000, 2000]
})
}
return async (c: any, next: () => Promise<any>) => {
const start = Date.now()
// 增强 c 对象以记录状态
let statusCode = 500 // 默认失败
const originalStatus = c.status
c.status = (code: number) => {
statusCode = code
return originalStatus.call(c, code)
}
try {
await next()
} catch (error: any) {
statusCode = 500
// 上报错误
if (options.sentry) {
// Sentry.captureException(error)
console.error('[Sentry] Captured error:', error.message)
}
if (options.datadog) {
// Datadog.logger.error('Request failed', { error })
console.error('[Datadog] Error:', error.message)
}
throw error
} finally {
const duration = Date.now() - start
// 标签化指标
const labels = {
method: c.req.method,
path: c.req.path,
status: statusCode.toString()
}
// Prometheus
if (options.prometheus && requestCounter && durationHistogram) {
requestCounter.inc(labels)
durationHistogram.observe(duration, labels)
}
// Datadog APM / Logs
if (options.datadog) {
// Datadog.metrics.increment('http.requests', 1, labels)
// Datadog.tracer.trace('http.request', { duration, ...labels })
console.log('[Datadog Metric]', { duration, ...labels })
}
// 可选:结构化日志
console.log({
level: 'info',
msg: 'HTTP Request',
req_method: c.req.method,
req_path: c.req.path,
req_query: c.req.query(),
req_ip: c.req.header('x-forwarded-for') || c.req.ip,
res_status: statusCode,
req_duration_ms: duration,
user_agent: c.req.header('user-agent')
})
}
}
}三、集成 Sentry(错误追踪)
Sentry 用于捕获异常和性能问题。
1. 安装
bash
npm install @sentry/hono @sentry/serverless2. 配置
ts
// sentry.ts
import * as Sentry from '@sentry/serverless'
import { Hono } from 'hono'
Sentry.AWSLambda.init({
dsn: 'YOUR_SENTRY_DSN',
tracesSampleRate: 0.2,
})
const app = new Hono()
// 使用 Sentry 中间件(自动捕获错误)
app.use('*', Sentry.Handlers.requestHandler())
app.use('*', Sentry.Handlers.tracingHandlers())
// 你的路由
app.get('/error', () => {
throw new Error('Test Sentry')
})
// 错误处理
app.onError((err, c) => {
Sentry.captureException(err)
return c.json({ error: 'Internal Server Error' }, 500)
})Sentry 会自动捕获未处理异常、慢请求、数据库调用等。
四、集成 Datadog(APM & 日志)
Datadog 提供全栈可观测性。
1. Cloudflare Workers + Datadog
使用 Datadog Log Forwarder 或 RUM。
ts
// 在中间件中发送日志
if (options.datadog) {
const log = {
service: 'hono-app',
http: { method: c.req.method, url: c.req.url, status: statusCode },
duration_ms: duration,
timestamp: new Date().toISOString()
}
// 通过 fetch 发送到 Datadog Log API 或边车代理
fetch('https://http-intake.logs.datadoghq.com/v1/input/YOUR_API_KEY', {
method: 'POST',
body: JSON.stringify(log),
headers: { 'Content-Type': 'application/json' }
}).catch(() => {})
}2. Node.js 环境
bash
npm install dd-tracets
// tracer.js
const tracer = require('dd-trace').init()
const app = new Hono()
app.use(monitoringMiddleware({ datadog: true }))五、集成 Prometheus(指标监控)
Prometheus 用于时序指标监控。
1. 安装
bash
npm install prom-client2. 暴露指标端点
ts
// metrics.ts
import client from 'prom-client'
export const register = new client.Registry()
// 暴露指标
app.get('/metrics', async (c) => {
const metrics = await register.metrics()
return c.text(metrics, 200, {
'Content-Type': client.contentType
})
})3. 使用中间件
ts
app.use('*', monitoringMiddleware({
prometheus: true
}))4. Grafana 面板建议
- QPS:
rate(http_requests_total[5m]) - P95 延迟:
histogram_quantile(0.95, rate(http_request_duration_ms_bucket[5m])) - 错误率:
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
六、最终应用结构
ts
const app = new Hono()
// 监控中间件(可组合)
app.use('*', monitoringMiddleware({
sentry: true,
datadog: true,
prometheus: true
}))
app.get('/', (c) => c.text('Hello World'))
app.get('/error', () => { throw new Error('Oops') })
// Prometheus 指标
app.get('/metrics', serveMetrics)
// Kubernetes 健康检查
app.get('/healthz', (c) => c.text('OK'))
export default app七、最佳实践总结
| 实践 | 说明 |
|---|---|
| ✅ 使用中间件统一收集指标 | 避免重复代码 |
| ✅ 分离关注点 | 错误(Sentry)、指标(Prometheus)、日志(Datadog) |
✅ 添加 req_ip、user-agent 等上下文 | 便于排查问题 |
✅ 避免在 /healthz 中做监控检查 | 防止级联故障 |
| ✅ 采样上报 | 高频请求避免打爆监控系统 |
| ✅ 设置告警规则 | 如 P95 > 1s 或错误率 > 1% |
八、结论
通过一个简单的中间件,你就能为 Hono 应用接入完整的监控体系:
- Sentry:第一时间发现线上错误;
- Prometheus + Grafana:可视化性能趋势;
- Datadog:全链路追踪与日志聚合。
可观测性不是事后补救,而是架构设计的一部分。尽早集成,让你的应用“看得见、管得住”。