@evlog/nuxthub 将你的 evlog 宽事件直接存储在 NuxtHub 数据库中。不需要外部日志服务。你的日志与数据存放在一起,并基于保留策略自动清理。
将 evlog 宽事件存储在 NuxtHub 中
为什么要自托管日志?
外部日志服务(如 Axiom、Datadog 等)在大规模生产环境中表现很好。但有时你可能希望:
- 零外部依赖 - 日志存储在与应用相同的数据库中
- 完全的数据所有权 - 第三方无法访问你的日志数据
- 免费层级友好 - 没有按事件计费,仅使用你现有的数据库
- 开发与预发布环境 - 无需付费即可获得完整的日志可见性
@evlog/nuxthub 可以作为一个即插即用的“数据排出器”(drain)。你现有的 evlog 设置保持不变,只需要在上方添加一层数据库支持。
安装
pnpm add @nuxthub/core @evlog/nuxthub
bun add @nuxthub/core @evlog/nuxthub
yarn add @nuxthub/core @evlog/nuxthub
npm install @nuxthub/core @evlog/nuxthub
或者使用 nuxi:
npx nuxi module add @nuxthub/core @evlog/nuxthub
配置
将模块添加到你的 nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@nuxthub/core', '@evlog/nuxthub'],
evlog: {
retention: '7d',
},
})
即使 @evlog/nuxthub 可以自动注册缺失的模块,我们仍然建议显式安装 @nuxthub/core 并在 modules 中注册它,以获得更清晰、更可预测的配置。
仅此而已。该模块会自动完成以下操作:
- 如果尚未注册,则安装
evlog/nuxt和@nuxthub/core - 使用 NuxtHub 注册
evlog_events数据库架构 - 挂钩到
evlog:drain以将每个事件存储在数据库中 - 根据你的保留策略安排清理任务
@evlog/nuxthub 使用 Drizzle ORM 与数据库交互。工作原理
请求 → evlog 宽事件 → evlog:drain 钩子 → 插入到 evlog_events 表
↓
定时任务(自动) → 删除早于保留策略的事件
evlog 发出的每个宽事件都会作为一行存储在 evlog_events 表中。该 drain 插件同时处理单个事件和批量事件(当与 pipeline 一起使用时)。
数据库架构
evlog_events 表存储用于快速查询的索引列,以及包含所有其他字段的 data JSON 列:
| 列名 | 类型 | 描述 |
|---|---|---|
id | text | UUID 主键 |
timestamp | text | 事件时间戳 |
level | text | 日志级别(info、warn、error、debug) |
service | text | 服务名称 |
environment | text | 环境(生产、预发布等) |
method | text | HTTP 方法 |
path | text | 请求路径 |
status | integer | HTTP 状态码 |
duration_ms | integer | 请求持续时间(毫秒) |
request_id | text | 请求关联 ID |
source | text | 事件来源(服务器、客户端) |
error | text | 错误详情(JSON 字符串) |
data | text | 所有剩余事件字段(JSON) |
created_at | text | 行插入时间戳 |
索引列:timestamp、level、service、status、request_id、created_at。
方言支持
架构会根据你的 NuxtHub 数据库方言自动注册:
- SQLite(Cloudflare D1 的默认值)
- MySQL
- PostgreSQL
根据你的 NuxtHub 配置,会通过 hub:db:schema:extend 钩子自动选择正确的架构。
与外部适配器结合使用
@evlog/nuxthub 不会取代外部适配器,你可以同时使用两者。该模块注册了自己的 evlog:drain 钩子,因此你拥有的其他任何 drain 插件仍可正常工作:
import { createAxiomDrain } from 'evlog/axiom'
export default defineNitroPlugin((nitroApp) => {
// 这将与 @evlog/nuxthub 内置的排出器并行运行
nitroApp.hooks.hook('evlog:drain', createAxiomDrain())
})
保留
@evlog/nuxthub 会根据你的保留策略自动删除旧事件。无需手动清理。
配置
在你的 nuxt.config.ts 中设置保留期:
export default defineNuxtConfig({
modules: ['@nuxthub/core', '@evlog/nuxthub'],
evlog: {
retention: '7d', // 默认值
},
})
保留值由一个数字后跟单位组成:
| 单位 | 描述 | 示例 |
|---|---|---|
d | 天 | 7d = 7 天 |
h | 小时 | 24h = 24 小时 |
m | 分钟 | 60m = 60 分钟 |
清理如何工作
该模块注册了一个 Nitro 定时任务(evlog:cleanup),它会按照基于你的保留值推导出的 cron 计划运行。cron 频率大约设为保留期的一半:
| 保留期 | Cron 计划 | 描述 |
|---|---|---|
60m | */30 * * * * | 每 30 分钟一次 |
24h | 0 */12 * * * | 每 12 小时一次 |
7d | 0 3 * * * | 每天凌晨 3:00 |
30d | 0 3 * * * | 每天凌晨 3:00 |
清理任务会删除 evlog_events 中所有 created_at 早于保留期的行。
手动清理
你可以通过 API 端点手动触发清理:
curl https://your-app.com/api/_cron/evlog-cleanup
如果设置了 CRON_SECRET 环境变量,该端点需要 Bearer token:
curl -H "Authorization: Bearer your-secret" \
https://your-app.com/api/_cron/evlog-cleanup
建议在生产部署中这样做,以防止未经授权的清理触发。
Vercel Cron
使用 nuxi module add 安装该模块时,会提示你创建一个包含合适 cron 计划的 vercel.json:
{
"crons": [
{
"path": "/api/_cron/evlog-cleanup",
"schedule": "0 3 * * *"
}
]
}
在 Vercel 上,CRON_SECRET 环境变量会自动设置并验证。
Cloudflare 与其他平台
在 Cloudflare Workers 和其他平台上,Nitro 定时任务会自动处理清理,无需额外的 cron 配置。该任务在 Nitro 配置中启用了 experimental.tasks 后注册。