log API 是 evlog 的通用日志记录器。你可以像使用 pino、consola 或 console.log 一样使用它——每次调用都会通过与广泛事件相同的排水管道发出一个结构化事件。这两种模式可以共存;二者之间没有升级关系。
在 CLIs、库、任务和边缘环境中寻找相同的 API?请从 Standalone TypeScript 和 Cloudflare 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
标签日志 针对控制台可读性进行了优化。结构化事件(对象形式)会生成完整的广泛事件,并通过排水管道传输到外部服务。
日志级别
| 级别 | 方法 | 使用场景 |
|---|---|---|
info | log.info() | 正常操作:启动、关闭、成功操作 |
warn | log.warn() | 可恢复但意外的情况:缓存未命中、重试、弃用 |
error | log.error() | 需要关注的失败:API 错误、超时、无效状态 |
debug | log.debug() | 仅开发环境详细信息:SQL 查询、中间状态、路由 |
常见模式
应用程序生命周期
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' })
import { createLogger, format, transports } from 'winston'
const log = createLogger({
defaultMeta: { service: 'checkout' },
format: format.json(),
transports: [new transports.Console()],
})
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' })
import { consola } from 'consola'
const log = consola.withTag('checkout')
log.info('开始结账')
log.info('购物车已加载', { items: 3, total: 9999 })
log.warn('库存不足', { sku: 'SKU-42' })
log.error('支付失败', { reason: 'card_declined' })
console.log('[checkout] 开始结账')
console.log('[checkout] 购物车已加载', { items: 3, total: 9999 })
console.warn('[checkout] 库存不足', { sku: 'SKU-42' })
console.error('[checkout] 支付失败', { 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。
与广泛事件配对使用
log 和 createLogger 处在同一个 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 块会让你的仪表盘每次运行都得到一行可查询记录。两者都会通过同一个排水管道。
下一步
- Wide Events: 累积上下文并发出完整事件
- Structured Errors: 抛出带有
why、fix和link的错误 - Configuration: 所有
initLogger选项 - Adapters: 将事件发送到 Axiom、Sentry、PostHog 等
- Standalone TypeScript: 无需 Web 框架的脚本、工作进程和库
- evlog vs other loggers: 与 pino、winston、consola 并排对比