服务器日志告诉你后端发生了什么。客户端日志补全了整个画面:用户交互、页面浏览、前端错误,以及那些不会到达服务器的性能信号(除非你主动捕获它们)。
快速起步
evlog 提供了一个可在任何浏览器环境中使用的客户端日志 API:
import { initLog, log } from 'evlog/client'
export default defineNuxtPlugin(() => {
initLog({ service: 'web' })
log.info({ action: 'app_init', path: window.location.pathname })
})
'use client'
import { useEffect } from 'react'
import { initLog, log } from 'evlog/client'
export function LogProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
initLog({ service: 'web' })
log.info({ action: 'app_init', path: window.location.pathname })
}, [])
return <>{children}</>
}
import { initLog, log } from 'evlog/client'
initLog({ service: 'web' })
log.info({ action: 'app_init', path: window.location.pathname })
log 对象可以在你的客户端代码中任何地方使用:组件、composables、事件处理器。
最低级别(minLevel)
使用 initLog({ minLevel: 'warn' }) 来保持浏览器控制台安静(仅显示警告和错误)。严重性顺序为:debug < info < warn < error。默认值为 'debug'(输出所有级别)。
如果需要无需重新加载即可切换调试模式,可以在用户选择开启或关闭详细日志时,从 evlog/client 调用 setMinLevel('debug') 或 setMinLevel('warn')。
minLevel 同时适用于控制台输出和向服务器发送日志 的有效载荷。
两种调用签名
log API 根据上下文接受两种形式。
对象形式(结构化上下文)
传递一个对象以捕获结构化数据,就像服务器端的 log.set() 一样:
log.info({ action: 'page_view', path: '/products', referrer: document.referrer })
[web] info { action: 'page_view', path: '/products', referrer: 'https://google.com' }
标签 + 消息形式(快速日志)
传递标签和消息以输出快速、可读的日志:
log.info('auth', 'User logged in')
[auth] User logged in
可用级别
两种形式均支持四个级别:log.info()、log.warn()、log.error() 和 log.debug()。
在浏览器中,log.debug() 会通过 console.log(而不是 console.debug)输出,以便在默认的 DevTools Info 过滤器下仍可见;结构化事件仍然包含 level: 'debug'。
身份上下文
使用 setIdentity() 跟踪生成日志的用户:
import { setIdentity, clearIdentity, log } from 'evlog/client'
// 登录后
setIdentity({ userId: 'usr_123', plan: 'pro' })
log.info({ action: 'dashboard_view' })
// → { userId: 'usr_123', plan: 'pro', action: 'dashboard_view', ... }
// 注销后
clearIdentity()
身份字段会在清除之前自动合并到每个日志事件中。这使得你可以在可观测性工具中将浏览器事件关联到特定用户。
配置
initLog() 接受以下选项:
| 选项 | 默认值 | 描述 |
|---|---|---|
enabled | true | 启用或禁用所有客户端日志记录 |
console | true | 输出日志到浏览器控制台 |
pretty | true | 使用带颜色的格式化控制台输出 |
minLevel | 'debug' | 最低严重级别:debug < info < warn < error |
service | 'client' | 每个日志事件中包含的服务名称 |
transport | - | 将日志发送到服务器端点(参见下文) |
initLog({
service: 'web',
transport: {
enabled: true,
endpoint: '/api/_evlog/ingest', // 默认端点
},
})
enabled、console 和 pretty 默认均为 true。仅当你希望修改默认值时才需要设置它们。向服务器发送日志
默认情况下,客户端日志只会显示在浏览器控制台中。若要持久化存储,有两种选择:
内置传输
最简单的方法是在 initLog() 中启用内置传输。每个日志都会通过 fetch 以 keepalive: true 单独发送。适合低流量应用。
import { initLog } from 'evlog/client'
export default defineNuxtPlugin(() => {
initLog({
service: 'web',
transport: {
enabled: true,
endpoint: '/api/_evlog/ingest',
},
})
})
import { initLog } from 'evlog/client'
initLog({
service: 'web',
transport: {
enabled: true,
endpoint: '/api/_evlog/ingest',
},
})
HTTP 接收器管道
对于更高流量或需要批量、重试以及在页面关闭时刷新的场景,请使用 HTTP 接收器(evlog/http)。这适用于任何前端,且不依赖具体框架。
import { initLogger, log } from 'evlog'
import { createHttpLogDrain } from 'evlog/http'
export default defineNuxtPlugin(() => {
const drain = createHttpLogDrain({
drain: { endpoint: '/api/_evlog/ingest' },
pipeline: {
batch: { size: 25, intervalMs: 2000 },
retry: { maxAttempts: 2 },
},
})
initLogger({ drain })
log.info({ action: 'app_init' })
})
import { initLogger, log } from 'evlog'
import { createHttpLogDrain } from 'evlog/http'
const drain = createHttpLogDrain({
drain: { endpoint: 'https://logs.example.com/v1/ingest' },
pipeline: {
batch: { size: 25, intervalMs: 2000 },
retry: { maxAttempts: 2 },
},
})
initLogger({ drain })
log.info({ action: 'app_init' })
HTTP 接收器会自动:
- 批量处理事件(按大小和时间间隔)
- 重试失败的发送(带指数退避)
- 刷新缓冲的事件,在页面隐藏时(标签切换、导航、关闭)通过
sendBeacon发送