---
title: "Better Stack 适配器"
description: "将广泛事件发送到 Better Stack（以前称为 Logtail）进行日志管理、告警和仪表板。通过环境变量实现零配置设置。"
canonical_url: "https://evlog.zhcndoc.com/integrate/adapters/cloud/better-stack"
---
# Better Stack 适配器

> 将广泛事件发送到 Better Stack（以前称为 Logtail）进行日志管理、告警和仪表板。通过环境变量实现零配置设置。

[Better Stack](https://betterstack.com) 是一个提供搜索、告警和仪表板功能的日志管理平台。evlog Better Stack 适配器将你的广泛事件发送到 Better Stack HTTP 摄取 API。

<prompt :actions="["copy","cursor","claude"]" description="添加 Better Stack 排水器适配器" icon="i-simple-icons-betterstack">

添加 Better Stack 排水器适配器，以将 evlog 广泛事件发送到 Better Stack。

1. 确定我正在使用哪个框架，并遵循其 evlog 集成模式
2. 如果尚未安装，则安装 evlog
3. 从 'evlog/better-stack' 导入 createBetterStackDrain
4. 将 createBetterStackDrain() 接入我的框架的排水器配置
5. 设置 BETTER_STACK_API_KEY 环境变量
6. 通过触发一个请求并检查 Better Stack 日志仪表板进行测试

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

::三分彩

## 安装

Better Stack 适配器随 evlog 一起捆绑提供：

```typescript [src/index.ts]
import { createBetterStackDrain } from 'evlog/better-stack'
```

## 快速开始

### 1. 获取源令牌

1. 创建一个 [Better Stack 账户](https://betterstack.com)
2. 转到 **遥测 > 数据源** 并创建一个新源
3. 复制 **源令牌**

### 2. 设置环境变量

```bash [.env]
BETTER_STACK_API_KEY=your-source-token-here
```

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

在 Better Stack 的控制面板中，这个凭据称为 **源令牌**。为保持与各适配器一致，evlog 将配置字段命名为 `apiKey`。旧版 `sourceToken` 字段在下一个大版本发布前仍然可用。

</callout>
</prompt>

### 3. 将排水器接入你的框架

<framework-tabs>

```typescript [Nuxt]server/plugins/evlog-drain.ts
import { createBetterStackDrain } from 'evlog/better-stack'

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

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

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

```typescript [Next.js]lib/evlog.ts
import { createEvlog } from 'evlog/next'
import { createBetterStackDrain } from 'evlog/better-stack'

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

```typescript [SvelteKit]src/hooks.server.ts
import { createEvlogHooks } from 'evlog/sveltekit'
import { createBetterStackDrain } from 'evlog/better-stack'

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

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

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

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

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

```typescript [Hono]src/index.ts
import { createBetterStackDrain } from 'evlog/better-stack'

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

```typescript [Express]src/index.ts
import { createBetterStackDrain } from 'evlog/better-stack'

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

```typescript [Fastify]src/index.ts
import { createBetterStackDrain } from 'evlog/better-stack'

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

```typescript [Elysia]src/index.ts
import { createBetterStackDrain } from 'evlog/better-stack'

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

```typescript [NestJS]src/app.module.ts
import { createBetterStackDrain } from 'evlog/better-stack'

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

```typescript [oRPC]server/orpc.ts
import { withEvlog } from 'evlog/orpc'
import { createBetterStackDrain } from 'evlog/better-stack'

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

```typescript [Cloudflare Workers]src/worker.ts
import { withEvlog } from 'evlog/workers'
import { createBetterStackDrain } from 'evlog/better-stack'

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

```typescript [Standalone]
import { createBetterStackDrain } from 'evlog/better-stack'

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

</framework-tabs>

就是这样！你的日志现在会显示在 Better Stack 中。

## 配置

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

1. **覆盖项** 传递给 `createBetterStackDrain()`
2. **运行时配置** 位于 `runtimeConfig.betterStack`（仅限 Nuxt/Nitro）
3. **环境变量**（`BETTER_STACK_*`）

### 环境变量

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

<tbody>
  <tr>
    <td>
      <code>
        BETTER_STACK_API_KEY
      </code>
    </td>
    
    <td>
      Better Stack 源令牌（必需）
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        BETTER_STACK_ENDPOINT
      </code>
    </td>
    
    <td>
      自定义摄取端点
    </td>
  </tr>
</tbody>
</table>

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

在 `nuxt.config.ts` 中进行类型安全的配置：

```typescript [nuxt.config.ts]
export default defineNuxtConfig({
  runtimeConfig: {
    betterStack: {
      apiKey: '', // 通过 BETTER_STACK_API_KEY 设置
    },
  },
})
```

### 覆盖选项

直接传递选项以覆盖任何配置：

<framework-tabs>

```typescript [Nuxt]server/plugins/evlog-drain.ts
import { createBetterStackDrain } from 'evlog/better-stack'

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }))
})
```

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

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }))
})
```

```typescript [Next.js]lib/evlog.ts
import { createEvlog } from 'evlog/next'
import { createBetterStackDrain } from 'evlog/better-stack'

export const { withEvlog, useLogger, log, createError } = createEvlog({
  service: 'my-app',
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
})
```

```typescript [SvelteKit]src/hooks.server.ts
import { createEvlogHooks } from 'evlog/sveltekit'
import { createBetterStackDrain } from 'evlog/better-stack'

export const { handle, handleError } = createEvlogHooks({
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
})
```

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

export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }))
})
```

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

export const middleware: Route.MiddlewareFunction[] = [
  evlog({
      drain: createBetterStackDrain({
        apiKey: 'my-key',
        timeout: 10000,
      }),
    }),
]
```

```typescript [Hono]src/index.ts
import { evlog } from 'evlog/hono'
import { createBetterStackDrain } from 'evlog/better-stack'

app.use(evlog({
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
}))
```

```typescript [Express]src/index.ts
import { evlog } from 'evlog/express'
import { createBetterStackDrain } from 'evlog/better-stack'

app.use(evlog({
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
}))
```

```typescript [Fastify]src/index.ts
import { evlog } from 'evlog/fastify'
import { createBetterStackDrain } from 'evlog/better-stack'

await app.register(evlog, {
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
})
```

```typescript [Elysia]src/index.ts
import { evlog } from 'evlog/elysia'
import { createBetterStackDrain } from 'evlog/better-stack'

app.use(evlog({
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
}))
```

```typescript [NestJS]src/app.module.ts
import { EvlogModule } from 'evlog/nestjs'
import { createBetterStackDrain } from 'evlog/better-stack'

EvlogModule.forRoot({
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
})
```

```typescript [oRPC]server/orpc.ts
import { withEvlog } from 'evlog/orpc'
import { createBetterStackDrain } from 'evlog/better-stack'

const handler = withEvlog(new RPCHandler(router), {
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
})
```

```typescript [Cloudflare Workers]src/worker.ts
import { withEvlog } from 'evlog/workers'
import { createBetterStackDrain } from 'evlog/better-stack'

export default withEvlog(handler, {
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
})
```

```typescript [Standalone]src/index.ts
import { initLogger } from 'evlog'
import { createBetterStackDrain } from 'evlog/better-stack'

initLogger({
  drain: createBetterStackDrain({
    apiKey: 'my-key',
    timeout: 10000,
  }),
})
```

</framework-tabs>

### 完整配置参考

<table>
<thead>
  <tr>
    <th>
      选项
    </th>
    
    <th>
      类型
    </th>
    
    <th>
      默认值
    </th>
    
    <th>
      说明
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        apiKey
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Better Stack 源令牌（必需）
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sourceToken
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      <strong>
        已弃用。
      </strong>
      
       请改用 <code>
        apiKey
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        endpoint
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        https://in.logs.betterstack.com
      </code>
    </td>
    
    <td>
      摄取端点
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        timeout
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        5000
      </code>
    </td>
    
    <td>
      请求超时时间（毫秒）
    </td>
  </tr>
</tbody>
</table>

## 日志转换

evlog 广泛事件通过 `toBetterStackEvent()` 进行转换：

- **时间戳**：`timestamp` 映射为 `dt`（Better Stack 期望的 ISO-8601 时间戳字段）
- **所有其他字段**：原样展开到事件正文中

Better Stack 接受任意 JSON 字段，因此你所有的广泛事件上下文（level、service、action、用户数据等）都会自动可搜索。

## 在 Better Stack 中查询日志

Better Stack 的日志搜索可对任意字段执行查询：

- **实时追踪**：实时流式传输日志
- **全文搜索**：跨所有字段进行搜索
- **结构化查询**：按 `level:error`、`service:my-app` 或任何广泛事件字段过滤
- **仪表板**：从你的广泛事件数据创建自定义仪表板
- **告警**：基于日志模式或阈值设置告警。

## 故障排除

### 缺少 apiKey 错误

```text [Console]
[evlog/better-stack] Missing apiKey. Set BETTER_STACK_API_KEY env var or pass to createBetterStackDrain()
```

请确保已设置环境变量并在添加后重启服务器。

### 401 未授权

你的源令牌可能无效或已被吊销。请在 Better Stack 仪表板的 **Telemetry > Sources** 中生成新的源令牌。

### 403 禁止访问

该源可能已被归档或删除。请在 Better Stack 中创建一个新源。

## 直接 API 使用

对于高级用例，你可以使用更低层的函数：

```typescript [server/utils/better-stack.ts]
import { sendToBetterStack, sendBatchToBetterStack } from 'evlog/better-stack'

// 发送单个事件
await sendToBetterStack(event, {
  apiKey: process.env.BETTER_STACK_API_KEY!,
})

// 批量发送多个事件
await sendBatchToBetterStack(events, {
  apiKey: process.env.BETTER_STACK_API_KEY!,
})
```

## 下一步

- [Axiom 适配器](https://evlog.zhcndoc.com/integrate/adapters/cloud/axiom) - 将日志发送到 Axiom，以便查询和创建仪表板
- [OTLP 适配器](https://evlog.zhcndoc.com/integrate/adapters/hybrid/otlp) - 通过 OpenTelemetry 协议发送日志
- [自定义适配器](https://evlog.zhcndoc.com/extend/custom-drains) - 构建您自己的适配器。

---

- [Better Stack 仪表板](https://logs.betterstack.com)
- [Axiom 适配器](https://evlog.zhcndoc.com/integrate/adapters/cloud/axiom)


## Sitemap

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