---
title: "Sazabi 适配器"
description: "通过 OTLP/HTTP 将宽事件发送到 Sazabi。日志流的 intake URL 已包含密钥，因此只需设置一个环境变量。"
canonical_url: "https://evlog.zhcndoc.com/integrate/adapters/cloud/sazabi"
---
# Sazabi 适配器

> 通过 OTLP/HTTP 将宽事件发送到 Sazabi。日志流的 intake URL 已包含密钥，因此只需设置一个环境变量。

[Sazabi](https://sazabi.com) 是面向 AI 的日志搜索和事件调查平台。Sazabi 适配器通过 **OTLP/HTTP** 将宽事件发送到 Sazabi 日志流，因此你用 `log.set()` 设置的每个字段都会作为可搜索属性到达。

<prompt :actions="["copy","cursor","claude"]" description="添加 Sazabi drain 适配器" icon="i-custom-sazabi">

添加 Sazabi drain 适配器，将 evlog 宽事件发送到 Sazabi。

1. 识别我使用的框架，并遵循其 evlog 集成模式
2. 如果尚未安装，则安装 evlog
3. 从 'evlog/sazabi' 导入 createSazabiDrain
4. 将 createSazabiDrain() 接入框架的 drain 配置
5. 在 .env 中设置 SAZABI_INTAKE_URL 环境变量
6. 触发请求，并在 Sazabi 中检查日志流来验证

适配器文档：[https://www.evlog.dev/integrate/adapters/cloud/sazabi](https://www.evlog.dev/integrate/adapters/cloud/sazabi)
框架设置：[https://www.evlog.dev/integrate/frameworks/overview](https://www.evlog.dev/integrate/frameworks/overview)

</prompt>

## 安装

Sazabi 适配器已随 evlog 一起提供：

```typescript [src/index.ts]
import { createSazabiDrain } from 'evlog/sazabi'
```

## 快速开始

### 1. 复制 intake URL

1. 在 Sazabi 中打开 **Log streams**，创建或打开一个 **OpenTelemetry** 日志流
2. 复制它的 **Intake URL**。日志流的公钥已经包含在 URL 中，因此无需单独设置 API key

### 2. 设置环境变量

```bash [.env]
SAZABI_INTAKE_URL=https://<key>.us-west-2.intake.sazabi.com
```

### 3. 将 drain 接入框架

<framework-tabs>

```typescript [Nuxt]server/plugins/evlog-drain.ts
import { createSazabiDrain } from 'evlog/sazabi'

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createSazabiDrain())
})
```

```typescript [Nitro]server/plugins/evlog-drain.ts
import { definePlugin } from 'nitro'
import { createSazabiDrain } from 'evlog/sazabi'

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createSazabiDrain())
})
```

```typescript [Next.js]lib/evlog.ts
import { createEvlog } from 'evlog/next'
import { createSazabiDrain } from 'evlog/sazabi'

export const { withEvlog, useLogger, log, createError } = createEvlog({
  service: 'my-app',
  drain: createSazabiDrain(),
})
```

```typescript [SvelteKit]src/hooks.server.ts
import { createEvlogHooks } from 'evlog/sveltekit'
import { createSazabiDrain } from 'evlog/sazabi'

export const { handle, handleError } = createEvlogHooks({ drain: createSazabiDrain() })
```

```typescript [TanStack Start]server/plugins/evlog-drain.ts
import { definePlugin } from 'nitro'
import { createSazabiDrain } from 'evlog/sazabi'

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createSazabiDrain())
})
```

```typescript [React Router]app/root.tsx
import { evlog } from 'evlog/react-router'
import { createSazabiDrain } from 'evlog/sazabi'

export const middleware: Route.MiddlewareFunction[] = [
  evlog({ drain: createSazabiDrain() }),
]
```

```typescript [Hono]src/index.ts
import { createSazabiDrain } from 'evlog/sazabi'

app.use(evlog({ drain: createSazabiDrain() }))
```

```typescript [Express]src/index.ts
import { createSazabiDrain } from 'evlog/sazabi'

app.use(evlog({ drain: createSazabiDrain() }))
```

```typescript [Fastify]src/index.ts
import { createSazabiDrain } from 'evlog/sazabi'

await app.register(evlog, { drain: createSazabiDrain() })
```

```typescript [Elysia]src/index.ts
import { createSazabiDrain } from 'evlog/sazabi'

app.use(evlog({ drain: createSazabiDrain() }))
```

```typescript [NestJS]src/app.module.ts
import { createSazabiDrain } from 'evlog/sazabi'

EvlogModule.forRoot({ drain: createSazabiDrain() })
```

```typescript [oRPC]server/orpc.ts
import { withEvlog } from 'evlog/orpc'
import { createSazabiDrain } from 'evlog/sazabi'

const handler = withEvlog(new RPCHandler(router), { drain: createSazabiDrain() })
```

```typescript [Cloudflare Workers]src/worker.ts
import { withEvlog } from 'evlog/workers'
import { createSazabiDrain } from 'evlog/sazabi'

export default withEvlog(handler, { drain: createSazabiDrain() })
```

```typescript [Standalone]
import { createSazabiDrain } from 'evlog/sazabi'

initLogger({ drain: createSazabiDrain() })
```

</framework-tabs>

触发请求，几秒钟内宽事件就会出现在日志流中。

## 配置

适配器会从多个来源读取配置（优先级从高到低）：

1. 传给 `createSazabiDrain()` 的 **覆盖项**
2. `runtimeConfig.evlog.sazabi` 或 `runtimeConfig.sazabi` 中的**运行时配置**（仅 Nuxt/Nitro）
3. **环境变量**（`SAZABI_*`）

### 环境变量

<table>
<thead>
  <tr>
    <th>
      变量
    </th>
    
    <th>
      描述
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        SAZABI_INTAKE_URL
      </code>
    </td>
    
    <td>
      日志流的 intake URL。evlog 会发送到 <code>
        <intake URL>/v1/logs
      </code>
      
      ；已经以 <code>
        /v1/logs
      </code>
      
       结尾的 URL 会原样使用
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        SAZABI_SERVICE_NAME
      </code>
    </td>
    
    <td>
      覆盖 <code>
        service.name
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        OTEL_SERVICE_NAME
      </code>
    </td>
    
    <td>
      <code>
        service.name
      </code>
      
       的回退值（与 OTLP 适配器相同）
    </td>
  </tr>
</tbody>
</table>

### 运行时配置（仅 Nuxt）

```typescript [nuxt.config.ts]
export default defineNuxtConfig({
  runtimeConfig: {
    sazabi: {
      // endpoint: '', // Set via SAZABI_INTAKE_URL
    },
  },
})
```

### 覆盖选项

直接传入选项即可覆盖任何配置：

<framework-tabs>

```typescript [Nuxt]server/plugins/evlog-drain.ts
import { createSazabiDrain } from 'evlog/sazabi'

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }))
})
```

```typescript [Nitro]server/plugins/evlog-drain.ts
import { definePlugin } from 'nitro'
import { createSazabiDrain } from 'evlog/sazabi'

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }))
})
```

```typescript [Next.js]lib/evlog.ts
import { createEvlog } from 'evlog/next'
import { createSazabiDrain } from 'evlog/sazabi'

export const { withEvlog, useLogger, log, createError } = createEvlog({
  service: 'my-app',
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
})
```

```typescript [SvelteKit]src/hooks.server.ts
import { createEvlogHooks } from 'evlog/sveltekit'
import { createSazabiDrain } from 'evlog/sazabi'

export const { handle, handleError } = createEvlogHooks({
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
})
```

```typescript [TanStack Start]server/plugins/evlog-drain.ts
import { definePlugin } from 'nitro'
import { createSazabiDrain } from 'evlog/sazabi'

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }))
})
```

```typescript [React Router]app/root.tsx
import { evlog } from 'evlog/react-router'
import { createSazabiDrain } from 'evlog/sazabi'

export const middleware: Route.MiddlewareFunction[] = [
  evlog({
    drain: createSazabiDrain({
      serviceName: 'checkout-api',
      resourceAttributes: { 'deployment.region': 'us-west-2' },
    }),
  }),
]
```

```typescript [Hono]src/index.ts
import { evlog } from 'evlog/hono'
import { createSazabiDrain } from 'evlog/sazabi'

app.use(evlog({
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
}))
```

```typescript [Express]src/index.ts
import { evlog } from 'evlog/express'
import { createSazabiDrain } from 'evlog/sazabi'

app.use(evlog({
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
}))
```

```typescript [Fastify]src/index.ts
import { evlog } from 'evlog/fastify'
import { createSazabiDrain } from 'evlog/sazabi'

await app.register(evlog, {
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
})
```

```typescript [Elysia]src/index.ts
import { evlog } from 'evlog/elysia'
import { createSazabiDrain } from 'evlog/sazabi'

app.use(evlog({
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
}))
```

```typescript [NestJS]src/app.module.ts
import { EvlogModule } from 'evlog/nestjs'
import { createSazabiDrain } from 'evlog/sazabi'

EvlogModule.forRoot({
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
})
```

```typescript [oRPC]server/orpc.ts
import { withEvlog } from 'evlog/orpc'
import { createSazabiDrain } from 'evlog/sazabi'

const handler = withEvlog(new RPCHandler(router), {
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
})
```

```typescript [Cloudflare Workers]src/worker.ts
import { withEvlog } from 'evlog/workers'
import { createSazabiDrain } from 'evlog/sazabi'

export default withEvlog(handler, {
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
})
```

```typescript [Standalone]src/index.ts
import { initLogger } from 'evlog'
import { createSazabiDrain } from 'evlog/sazabi'

initLogger({
  drain: createSazabiDrain({
    serviceName: 'checkout-api',
    resourceAttributes: { 'deployment.region': 'us-west-2' },
  }),
})
```

</framework-tabs>

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

<tbody>
  <tr>
    <td>
      <code>
        endpoint
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        SAZABI_INTAKE_URL
      </code>
    </td>
    
    <td>
      日志流的 intake URL
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        serviceName
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        event.service
      </code>
    </td>
    
    <td>
      覆盖 <code>
        service.name
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        resourceAttributes
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      额外的 OTLP 资源属性
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        timeout
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        5000
      </code>
    </td>
    
    <td>
      请求超时时间，单位为毫秒
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        retries
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2
      </code>
    </td>
    
    <td>
      临时失败时的重试次数
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        recordShape
      </code>
    </td>
    
    <td>
      <code>
        'compact' | 'json'
      </code>
    </td>
    
    <td>
      <code>
        'compact'
      </code>
    </td>
    
    <td>
      日志记录形态：正文为带点号属性的一行摘要，或以序列化事件作为正文
    </td>
  </tr>
</tbody>
</table>

## 工作原理

适配器是 [OTLP 适配器](https://evlog.zhcndoc.com/integrate/adapters/hybrid/otlp) 上的一层薄封装：它规范化 intake URL，并使用相同的 OTLP/JSON 编码发送批次。

- 事件的 `service`、`environment`、`version`、`region` 和 `commitHash` 会成为资源属性
- `level` 映射为 OTLP 严重性
- 记录使用紧凑形态：正文是一行摘要，例如 `POST /api/checkout (500)`
- 宽事件的其他字段都会成为日志属性，嵌套字段会展平为点号键，因此可以在 Sazabi 中按 `user.plan` 或 `cart.total` 过滤和分组

## 在 Sazabi 中查询日志

打开日志流，用自然语言提问，例如“过去一小时有多少个结账请求失败？”，或者按宽事件携带的任意字段过滤。

## 故障排除

### 缺少 endpoint 错误

```text
[evlog/sazabi] Missing endpoint. Set SAZABI_INTAKE_URL, or pass to createSazabiDrain()
```

在服务器运行环境中设置 `SAZABI_INTAKE_URL`，或向 `createSazabiDrain()` 传入 `endpoint`。

### intake 返回 4xx

从日志流中重新复制 intake URL：被截断的主机名或旧日志流的 URL 会被拒绝。

## 直接使用 API

对于脚本和任务，可以不使用 drain 而直接发送事件：

```typescript [scripts/send.ts]
import { sendBatchToSazabi, sendToSazabi } from 'evlog/sazabi'

await sendToSazabi(event, { endpoint: process.env.SAZABI_INTAKE_URL! })
await sendBatchToSazabi(events, { endpoint: process.env.SAZABI_INTAKE_URL! })
```

## 下一步

- [OTLP 适配器](https://evlog.zhcndoc.com/integrate/adapters/hybrid/otlp)：了解此适配器复用的编码
- [Drain Pipeline](https://evlog.zhcndoc.com/extend/drain-pipeline)：了解批处理、重试和缓冲
- [适配器概览](https://evlog.zhcndoc.com/integrate/adapters/overview)：查看其他目标

---

- [Sazabi](https://sazabi.com)
- [OTLP 适配器](https://evlog.zhcndoc.com/integrate/adapters/hybrid/otlp)


## Sitemap

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