自托管

NuxtHub Storage

使用 NuxtHub 数据库存储为 evlog 提供自托管日志保留功能。无需任何外部依赖即可存储、查询和自动清理结构化的日志。

@evlog/nuxthub 将你的 evlog 宽事件直接存储在 NuxtHub 数据库中。不需要外部日志服务。你的日志与数据存放在一起,并基于保留策略自动清理。

将 evlog 宽事件存储在 NuxtHub 中

为什么要自托管日志?

外部日志服务(如 Axiom、Datadog 等)在大规模生产环境中表现很好。但有时你可能希望:

  • 零外部依赖 - 日志存储在与应用相同的数据库中
  • 完全的数据所有权 - 第三方无法访问你的日志数据
  • 免费层级友好 - 没有按事件计费,仅使用你现有的数据库
  • 开发与预发布环境 - 无需付费即可获得完整的日志可见性

@evlog/nuxthub 可以作为一个即插即用的“数据排出器”(drain)。你现有的 evlog 设置保持不变,只需要在上方添加一层数据库支持。

安装

pnpm add @nuxthub/core @evlog/nuxthub

或者使用 nuxi

Terminal
npx nuxi module add @nuxthub/core @evlog/nuxthub

配置

将模块添加到你的 nuxt.config.ts

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core', '@evlog/nuxthub'],

  evlog: {
    retention: '7d',
  },
})

即使 @evlog/nuxthub 可以自动注册缺失的模块,我们仍然建议显式安装 @nuxthub/core 并在 modules 中注册它,以获得更清晰、更可预测的配置。

仅此而已。该模块会自动完成以下操作:

  1. 如果尚未注册,则安装 evlog/nuxt@nuxthub/core
  2. 使用 NuxtHub 注册 evlog_events 数据库架构
  3. 挂钩到 evlog:drain 以将每个事件存储在数据库中
  4. 根据你的保留策略安排清理任务
前提条件: 你的项目必须使用 NuxtHub 并配置了数据库。@evlog/nuxthub 使用 Drizzle ORM 与数据库交互。

工作原理

请求 → evlog 宽事件 → evlog:drain 钩子 → 插入到 evlog_events 表
                                                          ↓
                定时任务(自动) → 删除早于保留策略的事件

evlog 发出的每个宽事件都会作为一行存储在 evlog_events 表中。该 drain 插件同时处理单个事件和批量事件(当与 pipeline 一起使用时)。

数据库架构

evlog_events 表存储用于快速查询的索引列,以及包含所有其他字段的 data JSON 列:

列名类型描述
idtextUUID 主键
timestamptext事件时间戳
leveltext日志级别(info、warn、error、debug)
servicetext服务名称
environmenttext环境(生产、预发布等)
methodtextHTTP 方法
pathtext请求路径
statusintegerHTTP 状态码
duration_msinteger请求持续时间(毫秒)
request_idtext请求关联 ID
sourcetext事件来源(服务器、客户端)
errortext错误详情(JSON 字符串)
datatext所有剩余事件字段(JSON)
created_attext行插入时间戳

索引列:timestamplevelservicestatusrequest_idcreated_at

方言支持

架构会根据你的 NuxtHub 数据库方言自动注册:

  • SQLite(Cloudflare D1 的默认值)
  • MySQL
  • PostgreSQL

根据你的 NuxtHub 配置,会通过 hub:db:schema:extend 钩子自动选择正确的架构。

与外部适配器结合使用

@evlog/nuxthub 不会取代外部适配器,你可以同时使用两者。该模块注册了自己的 evlog:drain 钩子,因此你拥有的其他任何 drain 插件仍可正常工作:

server/plugins/evlog-drain.ts
import { createAxiomDrain } from 'evlog/axiom'

export default defineNitroPlugin((nitroApp) => {
  // 这将与 @evlog/nuxthub 内置的排出器并行运行
  nitroApp.hooks.hook('evlog:drain', createAxiomDrain())
})

保留

@evlog/nuxthub 会根据你的保留策略自动删除旧事件。无需手动清理。

配置

在你的 nuxt.config.ts 中设置保留期:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core', '@evlog/nuxthub'],

  evlog: {
    retention: '7d', // 默认值
  },
})

保留值由一个数字后跟单位组成:

单位描述示例
d7d = 7 天
h小时24h = 24 小时
m分钟60m = 60 分钟

清理如何工作

该模块注册了一个 Nitro 定时任务(evlog:cleanup),它会按照基于你的保留值推导出的 cron 计划运行。cron 频率大约设为保留期的一半:

保留期Cron 计划描述
60m*/30 * * * *每 30 分钟一次
24h0 */12 * * *每 12 小时一次
7d0 3 * * *每天凌晨 3:00
30d0 3 * * *每天凌晨 3:00

清理任务会删除 evlog_events 中所有 created_at 早于保留期的行。

手动清理

你可以通过 API 端点手动触发清理:

Terminal
curl https://your-app.com/api/_cron/evlog-cleanup

如果设置了 CRON_SECRET 环境变量,该端点需要 Bearer token:

Terminal
curl -H "Authorization: Bearer your-secret" \
  https://your-app.com/api/_cron/evlog-cleanup

建议在生产部署中这样做,以防止未经授权的清理触发。

Vercel Cron

使用 nuxi module add 安装该模块时,会提示你创建一个包含合适 cron 计划的 vercel.json

vercel.json
{
  "crons": [
    {
      "path": "/api/_cron/evlog-cleanup",
      "schedule": "0 3 * * *"
    }
  ]
}

在 Vercel 上,CRON_SECRET 环境变量会自动设置并验证。

Cloudflare 与其他平台

在 Cloudflare Workers 和其他平台上,Nitro 定时任务会自动处理清理,无需额外的 cron 配置。该任务在 Nitro 配置中启用了 experimental.tasks 后注册。

下一步

  • Adapters - 将日志发送到外部服务,同时使用 NuxtHub 存储
  • Pipeline - 对事件进行批处理,以获得更好的数据库性能