框架

Astro

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

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

在我的 Astro 应用中设置 evlog

这是一个指南级别的集成。它使用通用的 createRequestLogger API,而不是框架特定的模块。
Cloudflare Workers 上(包括使用 @astrojs/cloudflare 的 Astro),请将 waitUntil 设置到 createRequestLogger,并传入你的 ExecutionContext#waitUntil(需正确绑定),或者在 Worker fetch 入口 中使用带有 { executionCtx }defineWorkerFetch / createWorkersLogger。否则,在响应返回后,异步排水可能永远不会完成。对于 Astro 中间件(不是原始 Worker 处理程序),没有 defineWorkerFetch;你仍然需要从适配器暴露的上下文中传入 waitUntil。从 Astro 中间件读取 ctx 的具体方式取决于你的适配器版本——请查看 Cloudflare 适配器文档

快速开始

1. 安装

pnpm add evlog

2. 创建中间件

src/middleware.ts
import { defineMiddleware } from 'astro:middleware'
import { initLogger, createRequestLogger } from 'evlog'

initLogger({
  env: { service: 'my-astro-app' },
})

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
  }
})

3. 定义 locals 类型

src/env.d.ts
/// <reference types="astro/client" />

import type { RequestLogger } from 'evlog'

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

广泛事件

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

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' },
  })
}
终端输出
14:58:15 INFO [my-astro-app] GET /api/users/usr_123
  ├─ user: id=usr_123 name=Alice plan=pro
  └─ requestId: 4a8ff3a8-...

错误处理

使用 createError 创建结构化错误:

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 }))
}

配置

请参阅 配置参考 获取所有可用选项(initLogger、中间件选项、采样、静默模式等)。

排水处理

initLogger 中配置排水处理:

src/middleware.ts
import { initLogger, createRequestLogger } from 'evlog'
import { createAxiomDrain } from 'evlog/axiom'
import { createDrainPipeline } from 'evlog/pipeline'
import type { DrainContext } from 'evlog'

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

initLogger({
  env: { service: 'my-astro-app' },
  drain,
})
请参阅 Adapters 文档,了解所有可用的排水适配器。

下一步

  • Wide Events: 设计带有上下文分层的完整事件
  • Adapters: 将日志发送到 Axiom、Sentry、PostHog 等
  • Sampling: 通过头部和尾部采样控制日志量
  • Structured Errors: 抛出带有 whyfixlink 字段的错误