NuxtHub

NuxtHub Storage

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

@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 插件同时处理单个事件和批量事件(当与 流水线 一起使用时)。

数据库架构

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())
})

下一步