---
title: "适配器概述"
description: "使用 evlog 适配器将日志发送到外部服务。内置支持流行的可观测性平台和自定义目标。"
canonical_url: "https://evlog.zhcndoc.com/integrate/adapters/overview"
---
# 适配器概述

> 使用 evlog 适配器将日志发送到外部服务。内置支持流行的可观测性平台和自定义目标。

适配器允许您将日志发送到外部可观测性平台。evlog 提供内置适配器以支持流行的服务，并且您可以为任何目标创建自定义适配器。

<drain-fan-out>



</drain-fan-out>

## 在代码中无需命名目标地发送事件

适配器在每次请求完成后接收一个 `DrainContext`，并将数据发送到外部服务。排水过程以**即发即忘**模式运行，这意味着它永远不会阻塞 HTTP 响应。

如何连接适配器取决于您使用的框架：

<framework-tabs>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```typescript [Standalone]
import { createAxiomDrain } from 'evlog/axiom'

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

</framework-tabs>

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

**无服务器支持：** 在 Cloudflare Workers 和 Vercel Edge 上，evlog 会自动使用 `waitUntil()` 来确保在运行时终止前排水完成。无需额外配置。

</callout>

## 选择目标

<card-group>
<card icon="i-custom-axiom" title="Axiom" to="https://evlog.zhcndoc.com/integrate/adapters/cloud/axiom">

将日志发送到 Axiom，Axiom 会为每个字段建立索引，因此您可以针对任意字段进行查询。

</card>

<card icon="i-simple-icons-posthog" title="PostHog" to="https://evlog.zhcndoc.com/integrate/adapters/cloud/posthog">

将日志发送到 PostHog Logs，以便进行结构化日志记录和可观测性。

</card>

<card icon="i-simple-icons-sentry" title="Sentry" to="https://evlog.zhcndoc.com/integrate/adapters/cloud/sentry">

将结构化日志发送到 Sentry Logs，以便进行高基数查询。

</card>

<card icon="i-simple-icons-betterstack" title="Better Stack" to="https://evlog.zhcndoc.com/integrate/adapters/cloud/better-stack">

将日志发送到 Better Stack，以便进行日志管理和告警。

</card>

<card icon="i-simple-icons-datadog" title="Datadog" to="https://evlog.zhcndoc.com/integrate/adapters/cloud/datadog">

通过本地 HTTP 摄入 API 将日志发送到 Datadog Logs。

</card>

<card icon="i-custom-sazabi" title="Sazabi" to="https://evlog.zhcndoc.com/integrate/adapters/cloud/sazabi">

通过日志流的 intake URL 配置，并经由 OTLP/HTTP 将日志发送到 Sazabi 日志流。

</card>

<card icon="i-simple-icons-grafana" title="Grafana Loki" to="https://evlog.zhcndoc.com/integrate/adapters/hybrid/loki">

将日志推送到自托管、多租户或 Grafana Cloud Loki。

</card>

<card icon="i-simple-icons-clickhouse" title="ClickHouse" to="https://evlog.zhcndoc.com/integrate/adapters/hybrid/clickhouse">

将日志插入 ClickHouse，以便对海量数据进行快速聚合。

</card>

<card icon="i-simple-icons-opentelemetry" title="OTLP" to="https://evlog.zhcndoc.com/integrate/adapters/hybrid/otlp">

面向 Grafana、Datadog、Honeycomb 等平台的 OpenTelemetry 协议。

</card>

<card icon="i-custom-hyperdx" title="HyperDX" to="https://evlog.zhcndoc.com/integrate/adapters/hybrid/hyperdx">

使用其文档中提供的摄入端点和 API 密钥，通过 OTLP/HTTP 将日志发送到 HyperDX。

</card>

<card icon="i-lucide-hard-drive" title="文件系统" to="https://evlog.zhcndoc.com/integrate/adapters/self-hosted/fs">

将日志写入本地 NDJSON 文件，用于调试和 AI 代理集成。

</card>

<card icon="i-simple-icons-nuxt" title="NuxtHub" to="https://evlog.zhcndoc.com/integrate/adapters/self-hosted/nuxthub">

在您的 NuxtHub 数据库中进行自托管日志存储，并带有自动保留策略。

</card>

<card icon="i-lucide-cpu" title="内存" to="https://evlog.zhcndoc.com/integrate/adapters/self-hosted/memory">

适用于任何运行时的内存环形缓冲区，包括 Cloudflare Workers。

</card>

<card icon="i-lucide-code" title="自定义" to="https://evlog.zhcndoc.com/extend/custom-drains">

为任何目标构建您自己的适配器。

</card>

<card icon="i-lucide-globe" title="HTTP" to="https://evlog.zhcndoc.com/extend/drain-pipeline">

在不耦合框架的情况下将客户端日志发送到您的服务器。

</card>

<card icon="i-lucide-workflow" title="管道" to="https://evlog.zhcndoc.com/extend/drain-pipeline">

批量处理事件、失败重试并处理缓冲区溢出。

</card>
</card-group>

## 在请求之外调用排水器

在纯 TypeScript 或 Bun 脚本（无 HTTP 框架）中使用 `initLogger` 中的 `drain` 选项。每个发出的事件都会自动被排出。

```typescript [index.ts]
import type { DrainContext } from 'evlog'
import { initLogger, log, createRequestLogger } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'
import { createDrainPipeline } from 'evlog/pipeline'

const pipeline = createDrainPipeline<DrainContext>()
const drain = pipeline(createAxiomDrain())

initLogger({
  env: { service: 'my-script' },
  drain,
})

log.info({ action: 'job_started' }) // 自动排出

const reqLog = createRequestLogger({ method: 'POST', path: '/process' })
reqLog.set({ processed: 42 })
reqLog.emit() // 自动排出

await drain.flush()
```

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

请参阅完整的 [bun-script 示例](https://github.com/evloghq/evlog/tree/main/examples/bun-script)，以了解真实的批处理脚本。

</callout>

## 同时发送到多个位置

通过组合排水器同时将日志发送到多个服务：

```typescript [src/index.ts]
import { createAxiomDrain } from 'evlog/axiom'
import { createOTLPDrain } from 'evlog/otlp'

const axiom = createAxiomDrain()
const otlp = createOTLPDrain()

const drain = async (ctx) => {
  await Promise.allSettled([axiom(ctx), otlp(ctx)])
}
```

然后将 `drain` 传递给您的框架：

<framework-tabs>

```typescript [Nuxt]server/plugins/evlog-drain.ts
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', drain)
})
```

```typescript [Nitro]server/plugins/evlog-drain.ts
import { definePlugin } from 'nitro'
export default definePlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', drain)
})
```

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

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

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

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

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

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

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

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

```typescript [Hono]src/index.ts
app.use(evlog({ drain }))
```

```typescript [Express]src/index.ts
app.use(evlog({ drain }))
```

```typescript [Fastify]src/index.ts
await app.register(evlog, { drain })
```

```typescript [Elysia]src/index.ts
app.use(evlog({ drain }))
```

```typescript [NestJS]src/app.module.ts
EvlogModule.forRoot({ drain })
```

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

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

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

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

```typescript [Standalone]
initLogger({ drain })
```

:::

## 排水器接收的内容

每个适配器都会接收一个带有以下内容的 `DrainContext`：

<table>
<thead>
  <tr>
    <th>
      字段
    </th>
    
    <th>
      类型
    </th>
    
    <th>
      描述
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        event
      </code>
    </td>
    
    <td>
      <code>
        WideEvent
      </code>
    </td>
    
    <td>
      包含所有累积上下文的完整日志事件
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        request
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      请求元数据（<code>
        method
      </code>
      
      、<code>
        path
      </code>
      
      、<code>
        requestId
      </code>
      
      ）
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        headers
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      安全的 HTTP 头（敏感头会被过滤）
    </td>
  </tr>
</tbody>
</table>

<callout color="success" icon="i-lucide-shield-check">

**安全性：** 敏感头信息（如 `authorization`、`cookie`、`x-api-key` 等）会自动被过滤，不会传递给适配器。

</callout>

## 从环境中进行配置

所有适配器都支持通过环境变量自动配置，无需更改代码即可在不同环境中部署。

每个适配器都会读取标准环境变量，并且相同的名称可在每个框架中使用：

```bash [.env]
# Axiom
AXIOM_API_KEY=xaat-xxx
AXIOM_DATASET=my-logs

# OTLP
OTLP_ENDPOINT=https://otlp.example.com

# HyperDX
HYPERDX_API_KEY=<YOUR_HYPERDX_API_KEY_HERE>

# PostHog
POSTHOG_API_KEY=phc_xxx

# Sentry
SENTRY_DSN=https://key@o0.ingest.sentry.io/123

# Better Stack
BETTER_STACK_API_KEY=your-source-token

# Datadog
DD_API_KEY=your-api-key
DD_SITE=datadoghq.eu

# Sazabi
SAZABI_INTAKE_URL=https://<key>.us-west-2.intake.sazabi.com

# Grafana Loki
LOKI_ENDPOINT=http://localhost:3100
# 仅适用于 Grafana Cloud：
LOKI_USER=123456
LOKI_API_KEY=glc_xxx

# ClickHouse
CLICKHOUSE_ENDPOINT=http://localhost:8123
CLICKHOUSE_PASSWORD=your-password
```

适配器会自动从这些变量中读取配置，因此 `create*Drain()` 工厂方法无需传入参数。

## 缺少凭据

行为取决于您调用的是哪个 API：

<table>
<thead>
  <tr>
    <th>
      API
    </th>
    
    <th>
      缺少凭据
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        create*Drain()
      </code>
      
      （工厂方法）
    </td>
    
    <td>
      <code>
        console.error
      </code>
      
       + 排水器变为无操作 —— HTTP 响应绝不会被阻塞
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sendTo*
      </code>
      
       / <code>
        sendBatchTo*
      </code>
      
      （直接调用）
    </td>
    
    <td>
      如果缺少必需凭据则抛出错误 —— 调用方必须传入完整配置
    </td>
  </tr>
</tbody>
</table>

这种拆分是有意为之：排水器在每个请求后以 fire-and-forget 方式运行；直接发送辅助函数则用于脚本和测试，在这些场景中，静默失败会掩盖配置错误。

</framework-tabs>

---

- [Axiom](https://evlog.zhcndoc.com/integrate/adapters/cloud/axiom)
- [PostHog](https://evlog.zhcndoc.com/integrate/adapters/cloud/posthog)
- [Sentry](https://evlog.zhcndoc.com/integrate/adapters/cloud/sentry)
- [Better Stack](https://evlog.zhcndoc.com/integrate/adapters/cloud/better-stack)
- [Datadog](https://evlog.zhcndoc.com/integrate/adapters/cloud/datadog)
- [Sazabi](https://evlog.zhcndoc.com/integrate/adapters/cloud/sazabi)
- [Grafana Loki](https://evlog.zhcndoc.com/integrate/adapters/hybrid/loki)
- [ClickHouse](https://evlog.zhcndoc.com/integrate/adapters/hybrid/clickhouse)
- [OTLP](https://evlog.zhcndoc.com/integrate/adapters/hybrid/otlp)
- [HyperDX](https://evlog.zhcndoc.com/integrate/adapters/hybrid/hyperdx)
- [文件系统](https://evlog.zhcndoc.com/integrate/adapters/self-hosted/fs)
- [NuxtHub](https://evlog.zhcndoc.com/integrate/adapters/self-hosted/nuxthub)
- [内存](https://evlog.zhcndoc.com/integrate/adapters/self-hosted/memory)


## Sitemap

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