---
title: "客户端日志记录"
description: "捕获浏览器事件并使用结构化日志记录。与服务器端拥有相同的 API，自动添加控制台样式、用户身份上下文，并可选择发送到服务器。"
canonical_url: "https://evlog.zhcndoc.com/use-cases/client-logging"
---
# 客户端日志记录

> 捕获浏览器事件并使用结构化日志记录。与服务器端拥有相同的 API，自动添加控制台样式、用户身份上下文，并可选择发送到服务器。

服务器日志告诉你后端发生了什么。客户端日志补全了整个画面：用户交互、页面浏览、前端错误，以及那些不会到达服务器的性能信号（除非你主动捕获它们）。

<client-server-beacon>



</client-server-beacon>

<prompt :actions="["copy","cursor","claude"]" description="将浏览器日志发送到我的服务器" icon="i-lucide-monitor">

使用 evlog 客户端日志将浏览器日志发送到我的服务器。

- 检测我的框架（Nuxt、Next.js、SvelteKit 等），并选择匹配的客户端入口
- 在应用启动时调用 initLog({ service: 'web' }) 一次
- 在组件、composables 和事件处理器中使用 log.info / log.warn / log.error
- 登录后使用 setIdentity({ userId, email }) 设置用户身份，退出登录时调用 clearIdentity()
- 在框架配置中启用传输，以便将日志批量 POST 到 /api/_evlog/ingest
- 在服务器端，evlog 会自动对 source: 'client' 的已传输事件运行 drain 管道

文档：[https://www.evlog.dev/use-cases/client-logging](https://www.evlog.dev/use-cases/client-logging)
HTTP transport：[https://www.evlog.dev/extend/drain-pipeline](https://www.evlog.dev/extend/drain-pipeline)

</prompt>

## 快速开始

evlog 提供了一个可在任何浏览器环境中使用的客户端日志 API：

<framework-tabs>

```typescript [Nuxt]app/plugins/logger.client.ts
import { initLog, log } from 'evlog/client'

export default defineNuxtPlugin(() => {
  initLog({ service: 'web' })

  log.info({ action: 'app_init', path: window.location.pathname })
})
```

```typescript [app/providers.tsx (React / Next.js)]
'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}</>
}
```

```typescript [src/app.ts (任意前端)]
import { initLog, log } from 'evlog/client'

initLog({ service: 'web' })
log.info({ action: 'app_init', path: window.location.pathname })
```

</framework-tabs>

`log` 对象可以在你的客户端代码中任何地方使用：组件、composables、事件处理器。

## 最低级别（`minLevel`）

使用 `initLog({ minLevel: 'warn' })` 来保持浏览器控制台安静（仅显示警告和错误）。严重性顺序为：`trace` < `debug` < `info` < `warn` < `error` < `fatal`。默认值为 `'debug'`（输出所有级别）。

如果需要**无需重新加载即可切换调试模式**，可以在用户选择开启或关闭详细日志时，从 `evlog/client` 调用 `setMinLevel('debug')` 或 `setMinLevel('warn')`。

`minLevel` 同时适用于控制台输出和[向服务器发送日志](#sending-logs-to-the-server) 的有效载荷。

## 两种调用方式

`log` API 根据上下文接受两种形式。

### 对象形式（结构化上下文）

传递一个对象以捕获结构化数据，就像服务器端的 `log.set()` 一样：

```typescript [pages/products.vue]
log.info({ action: 'page_view', path: '/products', referrer: document.referrer })
```

```bash [浏览器控制台]
[web] info  { action: 'page_view', path: '/products', referrer: 'https://google.com' }
```

### 标签 + 消息形式（快速日志）

传递标签和消息以输出快速、可读的日志：

```typescript [composables/useAuth.ts]
log.info('auth', 'User logged in')
```

```bash [浏览器控制台]
[auth] User logged in
```

消息支持 printf 风格的插值，与[服务端日志的格式化方式](https://evlog.zhcndoc.com/learn/simple-logging#interpolate-values-into-the-message)相同。当消息包含 `%s`、`%d` 或 `%j` 且后面有额外参数时，evlog 会在写入控制台前对其进行格式化：

```typescript [composables/useCart.ts]
log.info('cart', 'Item %s added, cart total %d', 'SKU-42', 9999)
```

```bash [Browser console]
[cart] Item SKU-42 added, cart total 9999
```

### 可用的级别

两种形式均支持六个级别：`log.fatal()`、`log.info()`、`log.warn()`、`log.error()`、`log.debug()` 和 `log.trace()`。

在浏览器中，`log.debug()` 会通过 `console.log`（而不是 `console.debug`）输出，以便在默认的 DevTools **Info** 过滤器下仍可见；结构化事件仍然包含 `level: 'debug'`。

## 添加日志所属用户

使用 `setIdentity()` 跟踪生成日志的用户：

```typescript [composables/useAuth.ts]
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()` 接受以下选项：

<table>
<thead>
  <tr>
    <th>
      选项
    </th>
    
    <th>
      默认值
    </th>
    
    <th>
      描述
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        enabled
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      启用或禁用所有客户端日志记录
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        console
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      输出日志到浏览器控制台
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pretty
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      使用带颜色的格式化控制台输出
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        minLevel
      </code>
    </td>
    
    <td>
      <code>
        'debug'
      </code>
    </td>
    
    <td>
      最低严重级别：<code>
        trace
      </code>
      
       < <code>
        debug
      </code>
      
       < <code>
        info
      </code>
      
       < <code>
        warn
      </code>
      
       < <code>
        error
      </code>
      
       < <code>
        fatal
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        service
      </code>
    </td>
    
    <td>
      <code>
        'client'
      </code>
    </td>
    
    <td>
      每个日志事件中包含的服务名称
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        transport
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      将日志发送到服务器端点（参见下文）
    </td>
  </tr>
</tbody>
</table>

```typescript [app/plugins/logger.client.ts]
initLog({
  service: 'web',
  transport: {
    enabled: true,
    endpoint: '/api/_evlog/ingest', // 默认端点
  },
})
```

<callout color="info" icon="i-lucide-info">

`enabled`、`console` 和 `pretty` 默认均为 `true`。仅当你希望修改默认值时才需要设置它们。

</callout>

## 向服务器发送日志

默认情况下，客户端日志只会显示在浏览器控制台中。若要持久化存储，有两种选择：

### 使用内置 drain 发送日志

最简单的方法是在 `initLog()` 中启用内置传输。每个日志都会通过 `fetch` 以 `keepalive: true` 单独发送。适合低流量应用。

<framework-tabs>

```typescript [Nuxt]app/plugins/logger.client.ts
import { initLog } from 'evlog/client'

export default defineNuxtPlugin(() => {
  initLog({
    service: 'web',
    transport: {
      enabled: true,
      endpoint: '/api/_evlog/ingest',
    },
  })
})
```

```tsx [Next.js]app/layout.tsx
import { EvlogProvider } from 'evlog/next/client'

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <EvlogProvider service="web" transport={{ enabled: true, endpoint: '/api/_evlog/ingest' }}>
          {children}
        </EvlogProvider>
      </body>
    </html>
  )
}
```

```typescript [src/app.ts (任意前端)]
import { initLog } from 'evlog/client'

initLog({
  service: 'web',
  transport: {
    enabled: true,
    endpoint: '/api/_evlog/ingest',
  },
})
```

</framework-tabs>

<callout color="info" icon="i-lucide-info">

Nuxt 中使用 evlog 模块时，服务器接收端点会自动注册。对于其他框架，你需要自行创建该端点。请参阅 [HTTP drain](https://evlog.zhcndoc.com/extend/drain-pipeline#server-endpoint) 文档中的 Express 和 Hono 示例。

</callout>

### HTTP 接收器管道

对于更高流量或需要批量、重试以及在页面关闭时刷新的场景，请使用 HTTP 接收器（`evlog/http`）。这适用于任何前端，且不依赖具体框架。

<framework-tabs>

```typescript [Nuxt]app/plugins/logger.client.ts
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' })
})
```

```typescript [src/app.ts (任意前端)]
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' })
```

</framework-tabs>

HTTP 接收器会自动：

- **批量**处理事件（按大小和时间间隔）
- **重试**失败的发送（带指数退避）
- **刷新**缓冲的事件，在页面隐藏时（标签切换、导航、关闭）通过 `sendBeacon` 发送

<callout color="neutral" icon="i-lucide-arrow-right">

请参阅 [HTTP drain](https://evlog.zhcndoc.com/extend/drain-pipeline) 适配器文档，了解完整配置参考、身份验证以及服务器端点示例。

</callout>

## 后续步骤

- [HTTP drain](https://evlog.zhcndoc.com/extend/drain-pipeline) - 批量处理、重试和 sendBeacon 回退
- [Pipeline](https://evlog.zhcndoc.com/extend/drain-pipeline) - 高级管道配置
- [Structured Errors](https://evlog.zhcndoc.com/learn/structured-errors) - 以可操作的上下文呈现客户端错误。

---

- [HTTP 接收器](https://evlog.zhcndoc.com/extend/drain-pipeline)
- [广泛事件](https://evlog.zhcndoc.com/learn/wide-events)


## Sitemap

See the full [sitemap](https://evlog.zhcndoc.com/sitemap.md) for all pages.
