---
title: "Astro"
description: "在 Astro 服务器中间件中实现广泛的事件和结构化错误。"
canonical_url: "https://evlog.zhcndoc.com/integrate/frameworks/astro"
---
# Astro

> 在 Astro 服务器中间件中实现广泛的事件和结构化错误。

Astro 没有专门的 evlog 集成。相反，可以在 Astro 中间件中使用核心 `evlog` 包手动创建请求作用域的日志记录器。

<prompt :actions="["copy","cursor","claude"]" description="在我的 Astro 应用中设置 evlog" icon="i-simple-icons-astro">

在我的 Astro 应用中设置 evlog。

- 安装 evlog：pnpm add evlog
- 从 'evlog' 导入 initLogger 和 createRequestLogger
- 创建 evlog.config.ts，其中包含 export default defineEvlog({ service: 'my-astro-app' })
- 在 Astro 中间件中调用 initLogger(toLoggerConfig(config))
- 为每个请求使用 createRequestLogger({ method, path }) 创建请求日志记录器
- 在 API 路由和中间件中使用 log.set() 来累积上下文
- 在返回响应前调用 log.emit()（没有自动的 emit 生命周期）

文档：[https://www.evlog.dev/integrate/frameworks/astro](https://www.evlog.dev/integrate/frameworks/astro)
适配器：[https://www.evlog.dev/integrate/adapters/overview](https://www.evlog.dev/integrate/adapters/overview)

</prompt>

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

这是一个指南级别的集成。它使用通用的 `createRequestLogger` API，而不是框架特定的模块。

</callout>

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

在 **Cloudflare Workers** 上（包括使用 `@astrojs/cloudflare` 的 Astro），请将 `waitUntil` 设置到 `createRequestLogger`，并传入你的 `ExecutionContext#waitUntil`（需正确绑定），或者在 **Worker fetch 入口** 中使用带有 `{ executionCtx }` 的 [`defineWorkerFetch`](https://evlog.zhcndoc.com/integrate/frameworks/cloudflare-workers) / [`createWorkersLogger`](https://evlog.zhcndoc.com/integrate/frameworks/cloudflare-workers)。否则，在响应返回后，异步排水可能永远不会完成。

对于 Astro **中间件**（不是原始 Worker 处理程序），没有 `defineWorkerFetch`；你仍然需要从适配器暴露的上下文中传入 `waitUntil`。

从 Astro 中间件读取 `ctx` 的确切方式取决于你的适配器版本，因此请查阅 [Cloudflare 适配器文档](https://docs.astro.build/en/guides/integrations-guide/cloudflare/)。

</callout>

## 快速开始

### 1. 安装

<code-group>

```bash [pnpm]
pnpm add evlog
```

```bash [bun]
bun add evlog
```

```bash [yarn]
yarn add evlog
```

```bash [npm]
npm install evlog
```

</code-group>

### 2. 创建 evlog.config.ts

```typescript [evlog.config.ts]
import { defineEvlog } from 'evlog'

export default defineEvlog({
  service: 'my-astro-app',
})
```

所有选项都位于此文件中：采样、drain、`enrich` 和路由过滤器。`npx evlog init` 会为你写入它，以及下方的接入代码。请参阅[配置](https://evlog.zhcndoc.com/reference/configuration)。

### 3. 创建中间件

```typescript [src/middleware.ts]
import { defineMiddleware } from 'astro:middleware'
import { initLogger, createRequestLogger, toLoggerConfig } from 'evlog'
import config from '../evlog.config'

initLogger(toLoggerConfig(config))

export const onRequest = defineMiddleware(async ({ request, locals }, next) => {
  const url = new URL(request.url)

  const log = createRequestLogger({
    method: request.method,
    path: url.pathname,
  })

  locals.log = log

  try {
    const response = await next()
    log.emit()
    return response
  } catch (error) {
    log.error(error instanceof Error ? error : new Error(String(error)))
    log.emit()
    throw error
  }
})
```

### 4. 为 locals 添加类型

```typescript [src/env.d.ts]
/// <reference types="astro/client" />

import type { RequestLogger } from 'evlog'

declare namespace App {
  interface Locals {
    log: RequestLogger
  }
}
```

## 广泛事件

在页面和 API 路由中从 `Astro.locals` 访问日志记录器：

```typescript [src/pages/api/users/[id].ts]
import type { APIRoute } from 'astro'

export const GET: APIRoute = async ({ params, locals }) => {
  locals.log.set({ user: { id: params.id } })

  const user = await db.findUser(params.id)
  locals.log.set({ user: { name: user.name, plan: user.plan } })

  return new Response(JSON.stringify(user), {
    headers: { 'Content-Type': 'application/json' },
  })
}
```

```bash [终端输出]
14:58:15 INFO [my-astro-app] GET /api/users/usr_123
  ├─ user: id=usr_123 name=Alice plan=pro
  └─ requestId: 4a8ff3a8-...
```

## 错误处理

使用 `createError` 创建结构化错误：

```typescript [src/pages/api/checkout.ts]
import type { APIRoute } from 'astro'
import { createError, parseError } from 'evlog'

export const POST: APIRoute = async ({ request, locals }) => {
  const body = await request.json()
  locals.log.set({ cart: { items: body.items } })

  if (!body.paymentMethod) {
    const error = createError({
      status: 400,
      message: '缺少支付方式',
      why: '未提供支付方式',
      fix: '在请求体中包含 paymentMethod 字段',
    })
    locals.log.error(error)
    const parsed = parseError(error)
    return new Response(JSON.stringify(parsed), { status: parsed.status })
  }

  return new Response(JSON.stringify({ success: true }))
}
```

## 配置

请参阅 [配置参考](https://evlog.zhcndoc.com/reference/configuration) 获取所有可用选项（`initLogger`、中间件选项、采样、静默模式等）。本指南使用 `createRequestLogger` 构建请求日志记录器，而不是使用 evlog 中间件，因此文件中的 `enrich`、`keep`、`include`、`exclude` 和 `routes` 不适用。

## 排水处理

在文件中设置 drain；`toLoggerConfig(config)` 会将它传给 `initLogger`：

```typescript [evlog.config.ts]
import { defineEvlog, type DrainContext } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'
import { createDrainPipeline } from 'evlog/pipeline'

const pipeline = createDrainPipeline<DrainContext>({
  batch: { size: 50, intervalMs: 5000 },
})

export default defineEvlog({
  service: 'my-astro-app',
  drain: pipeline(createAxiomDrain()),
})
```

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

请参阅 [适配器](https://evlog.zhcndoc.com/integrate/adapters/overview) 文档，了解所有可用的排水适配器。

</callout>

## 下一步

- [广泛事件](https://evlog.zhcndoc.com/learn/wide-events)：设计带有上下文分层的完整事件
- [适配器](https://evlog.zhcndoc.com/integrate/adapters/overview)：将日志发送到 Axiom、Sentry、PostHog 等
- [采样](https://evlog.zhcndoc.com/learn/sampling)：通过头部和尾部采样控制日志量
- [结构化错误](https://evlog.zhcndoc.com/learn/structured-errors)：抛出带有 `why`、`fix` 和 `link` 字段的错误


## Sitemap

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