开始使用

快速开始

几分钟内上手 evlog。学习日志 API、为广泛事件创建 createLogger、处理请求的 useLogger,以及结构化错误。

本指南介绍你最常与 evlog 一起使用的核心 API。

在 Nuxt 中,evlog 自动导入 所有函数(useLoggerlogcreateErrorparseError)。无需导入语句。

log(简单日志)

使用 evlog 的最简单方式。随时随地发送无需关注的已结构化的日志:

import { log } from 'evlog'

log.info('auth', '用户已登录')
log.error({ action: 'payment', error: 'card_declined' })
log.warn('cache', '缓存未命中')

两种调用风格:

  • 带标签log.info('tag', '消息'),适合快速、可读的控制台输出
  • 结构化log.info({ key: value }),适合在排水管道中传递的丰富事件
查看完整的简单日志指南,了解所有模式和与排水管道的集成。

createLogger(广泛事件)

当你需要在操作的多个步骤中累积上下文时,无论是在脚本、后台作业、队列工作者还是工作流中,请使用 createLogger

import { initLogger, createLogger } from 'evlog'

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

const log = createLogger({ jobId: job.id, queue: 'emails' })

log.set({ batch: { size: 50 } })
log.set({ batch: { processed: 50 } })
log.emit()

createLogger() 接受一个纯对象作为初始上下文。它会返回一个带有 seterrorinfowarnemitgetContext 方法的日志记录器。

对于 HTTP 请求上下文,请使用 createRequestLogger(),它会自动预填充 methodpathrequestId

src/worker.ts
import { createRequestLogger } from 'evlog'

const log = createRequestLogger({ method: 'POST', path: '/api/checkout' })
使用 createLoggercreateRequestLogger 时,必须手动调用 log.emit()。在框架集成中,此操作会自动完成。

useLogger(获取请求日志记录器)

在使用框架集成(Nuxt、Hono、Express 等)时,中间件会在请求开始时自动创建一个广泛事件日志记录器,并在响应结束时发出它。useLogger(event) 从请求上下文中获取该日志记录器:

import { useLogger } from 'evlog'

export default defineEventHandler(async (event) => {
  const log = useLogger(event)

  log.set({ user: { id: 1, plan: 'pro' } })
  log.set({ cart: { items: 3, total: 9999 } })

  const order = await processCheckout()
  log.set({ orderId: order.id })

  return { success: true, orderId: order.id }
})
useLogger 不会创建日志记录器;框架中间件已经创建好了。它只是从事件上下文中检索出来,以便你可以通过 set() 添加数据。

何时使用什么

使用 log使用 createLogger() / createRequestLogger()使用 useLogger(event)
快速的一次性事件脚本、作业、工作者、队列、无框架的 HTTP 操作使用框架集成的 API 路由
无需累积上下文在操作过程中累积上下文获取自动管理的广泛事件
客户端日志记录每个操作一个广泛事件访问自动管理的广泛事件

服务识别

在多服务架构中,使用以下方式区分日志属于哪个服务:

基于路由的配置

nuxt.config.ts 中按路由模式配置服务名称:

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

  evlog: {
    env: {
      service: 'default-service',
    },
    routes: {
      '/api/auth/**': { service: 'auth-service' },
      '/api/payment/**': { service: 'payment-service' },
      '/api/booking/**': { service: 'booking-service' },
    },
  },
})

匹配这些路由模式的日志会自动包含配置的服务名称:

输出
21:57:10.442 INFO [auth-service] POST /api/auth/login 200 in 1ms
  ├─ requestId: 88ced16a-bef2-4483-86cb-2b4fb677ea52
  ├─ user: id=user_123 email=demo@example.com
  └─ action: login

显式服务参数

使用第二个参数覆盖特定路由的服务名称:

server/api/legacy/process.post.ts
import { useLogger } from 'evlog'

export default defineEventHandler((event) => {
  const log = useLogger(event, 'legacy-service')

  log.set({ action: 'process_legacy_request' })

  return { success: true }
})
优先级顺序: 显式 useLogger 参数 > 路由配置 > env.service > 自动检测自环境

createError(结构化错误)

使用 createError() 抛出带有可操作上下文的错误:

import { createError } from 'evlog'

throw createError({
  message: 'Payment failed',
  status: 402,
  why: 'Card declined by issuer',
  fix: 'Try a different payment method',
  link: 'https://docs.example.com/payments/declined',
})

错误字段

字段必填描述
message发生了什么(面向用户)
statusHTTP 状态码(默认:500)
why技术原因(用于调试)
fix可操作的解决方案
link更多信息文档 URL
cause原始错误(如果包装)
internal仅用于日志和广泛事件的后端字段 — 永远不会包含在 HTTP JSON 或 parseError()

前端集成

使用 parseError() 在客户端提取所有错误字段:

composables/useCheckout.ts
import { parseError } from 'evlog'

export async function checkout(cart: Cart) {
  try {
    await $fetch('/api/checkout', { method: 'POST', body: cart })
  } catch (err) {
    const error = parseError(err)

    toast.add({
      title: error.message,
      description: error.why,
      color: 'error',
      actions: error.link
        ? [{ label: 'Learn more', onClick: () => window.open(error.link) }]
        : undefined,
    })

    if (error.fix) {
      console.info(`Fix: ${error.fix}`)
    }
  }
}

log(客户端)

相同的 log API 在客户端也适用,输出到浏览器控制台:

<script setup lang="ts">
async function handleCheckout() {
  log.info('checkout', '用户已发起结算')

  try {
    await $fetch('/api/checkout', { method: 'POST' })
    log.info({ action: 'checkout', status: 'success' })
  } catch (err) {
    log.error({ action: 'checkout', error: 'failed' })
  }
}
</script>
查看客户端日志,了解传输配置、身份上下文和浏览器排水设置。

下一步