学习

简单日志记录

evlog 的通用日志记录器。可直接替代 console.log、pino 或 consola,具备与广泛事件相同的级别过滤、排水管道、脱敏以及美观/JSON 输出。

log API 是 evlog 的通用日志记录器。你可以像使用 pino、consola 或 console.log 一样使用它——每次调用都会通过与广泛事件相同的排水管道发出一个结构化事件。这两种模式可以共存;二者之间没有升级关系。

在 CLIs、库、任务和边缘环境中寻找相同的 API?请从 Standalone TypeScriptCloudflare Workers 开始。
在 Nuxt 中,log自动导入 的。不需要导入语句。

设置

对于独立项目(非 Nuxt),请在启动时初始化一次:

src/index.ts
import { initLogger, log } from 'evlog'

initLogger({
  env: { service: 'my-app' },
})

log.info('app', '服务器已启动')
如果未指定,env.service 默认值为 'app'。仅当你想使用自定义服务名称时才设置它。

两种调用风格

标签日志

传递一个标签和一条消息,以获得快速、可读的输出:

src/index.ts
import { log } from 'evlog'

log.info('auth', '用户已登录')
log.warn('cache', '键 user:42 的缓存未命中')
log.error('payment', 'Stripe webhook 失败')
log.debug('router', '匹配到路由 /api/checkout')
输出(美观格式)
10:23:45.612 [auth] 用户已登录
10:23:45.613 [cache] 键 user:42 的缓存未命中
10:23:45.614 ERROR [payment] Stripe webhook 失败
10:23:45.615 [router] 匹配到路由 /api/checkout

结构化事件

传递一个对象以生成丰富、可查询的事件,这些事件会通过排水管道传输:

src/index.ts
import { log } from 'evlog'

log.info({ action: 'user_login', userId: 42, method: 'oauth', provider: 'github' })
log.error({ action: 'sync_failed', source: 'postgres', target: 's3', error: 'connection_timeout' })
输出(美观格式)
10:23:45.612 INFO [my-app]
  ├─ action: user_login
  ├─ userId: 42
  ├─ method: oauth
  └─ provider: github
标签日志 针对控制台可读性进行了优化。结构化事件(对象形式)会生成完整的广泛事件,并通过排水管道传输到外部服务。

日志级别

级别方法使用场景
infolog.info()正常操作:启动、关闭、成功操作
warnlog.warn()可恢复但意外的情况:缓存未命中、重试、弃用
errorlog.error()需要关注的失败:API 错误、超时、无效状态
debuglog.debug()仅开发环境详细信息:SQL 查询、中间状态、路由
可以使用 Vite 插件 或 Nuxt 模块的 strip 选项,从生产构建中剥离 log.debug() 调用。

常见模式

应用程序生命周期

src/index.ts
import { log } from 'evlog'

log.info('app', 'Starting server on port 3000')
log.info({ action: 'db_connected', host: 'localhost', database: 'mydb', pool: 10 })
log.info('app', 'Ready to accept connections')

后台任务

src/jobs/cleanup.ts
import { log } from 'evlog'

log.info({ action: 'cron_started', job: 'cleanup', schedule: '0 */6 * * *' })
log.info({ action: 'cron_completed', job: 'cleanup', deleted: 42, duration: 1200 })

实用函数

src/utils/webhook.ts
import { log } from 'evlog'

function processWebhook(payload: WebhookPayload) {
  log.info({ action: 'webhook_received', type: payload.type, source: payload.source })

  if (!isValid(payload)) {
    log.warn({ action: 'webhook_invalid', type: payload.type, reason: 'missing_signature' })
    return
  }
}

排水管道集成

当使用对象形式时,事件会像广泛事件一样通过 排水管道 发送:

src/index.ts
import { initLogger, log } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'

initLogger({
  env: { service: 'my-app' },
  drain: createAxiomDrain(),
})

log.info({ action: 'deploy', version: '1.2.3', region: 'us-east-1' })

从 console / pino / consola / winston 迁移

选择与你当前日志记录器对应的选项卡,查看 迁移前 的调用方式。下面的 迁移后(evlog) 代码片段无论你来自哪里都相同。

import pino from 'pino'

const log = pino({ name: 'checkout' })

log.info({ event: 'checkout_started' })
log.info({ event: 'cart_loaded', items: 3, total: 9999 })
log.warn({ event: 'inventory_low', sku: 'SKU-42' })
log.error({ event: 'payment_failed', reason: 'card_declined' })

以上四种都会变成这样——无需 formatter、transport 或 peer 依赖接线:

After (evlog)
import { initLogger, log } from 'evlog'

initLogger({ env: { service: 'checkout' } })

log.info({ event: 'checkout_started' })
log.info({ event: 'cart_loaded', items: 3, total: 9999 })
log.warn({ event: 'inventory_low', sku: 'SKU-42' })
log.error({ event: 'payment_failed', reason: 'card_declined' })

initLogger 只需在启动时写一行。排水管道、脱敏、采样、美观/JSON 切换以及级别过滤都会默认接好——无需 pino-pretty peer 依赖,无需 winston transport 组装,无需 consola reporter 设置。

想查看完整的并排对比(功能比较表、真实差距、逐项映射)?请参阅 evlog vs pino, winston, consola

与广泛事件配对使用

logcreateLogger 处在同一个 logger 中。对于独立存在的事件(启动消息、临时警告、调试跟踪),使用 log.*;当你希望一个事件捕获整个操作时,使用 createLogger。它们共享全局排水管道、脱敏和类型——按需选择。

scripts/sync-data.ts
import { initLogger, log, createLogger } from 'evlog'

initLogger({ env: { service: 'sync-worker' } })

log.info('sync', 'Worker starting')

const run = createLogger({ source: 'postgres', target: 's3' })
try {
  const records = await fetchRecords()
  run.set({ found: records.length })

  for (const record of records) {
    await syncOne(record)
    log.debug({ event: 'record_synced', id: record.id })
  }

  run.set({ status: 'complete', synced: records.length })
} catch (err) {
  log.error({ event: 'sync_failed' })
  run.error(err as Error)
  throw err
} finally {
  run.emit()
}

log.info('sync', 'Worker finished')

log.* 调用会在开发环境中为你提供实时轨迹;createLogger 块会让你的仪表盘每次运行都得到一行可查询记录。两者都会通过同一个排水管道。

下一步