mcpField
O
observability

observability

github.com/itallstartedwithaidea云与 DevOps4479 次安装29 周前更新
代码仓库

关于 observability

面向 Cloudflare Workers 和边缘应用开发者的可观测性技能,涵盖结构化日志、分布式追踪与错误监控。通过请求级追踪上下文及异步发送日志和跨度,帮助观察生产环境行为并减少响应延迟。

主要功能

  1. 01结构化 JSON 日志与关联 ID
  2. 02请求级分布式追踪
  3. 03错误捕获与上下文记录
  4. 04错误率和延迟监控
  5. 05异步发送日志与跨度

适用场景

  1. 01为 Workers 添加日志记录
  2. 02追踪生产环境中的请求
  3. 03设置错误监控和告警
  4. 04测量延迟百分位数

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/itallstartedwithaidea/agent-skills --skill observability

安装后在 Claude Code 中输入/observability确认已加载。

详细介绍

可观测性

Agent Skills™ 的一部分,由 googleadsagent.ai™ 提供

描述

可观测性为 Cloudflare Workers 和边缘应用实现结构化日志记录、分布式追踪和错误监控。Agent 会为代码添加检测机制,包括带上下文的日志条目、追踪跨度、错误边界和告警规则,从而全面掌握生产环境中的运行情况,同时不牺牲性能。

Workers 面临独特的可观测性挑战:没有可附加分析器的持久进程,没有存放日志文件的文件系统,也无法注入 APM Agent。可观测性必须在应用层实现,包括将结构化日志事件发送到外部收集器、使用请求级追踪上下文,以及通过堆栈追踪和请求元数据显式捕获错误。

此技能涵盖三大支柱:日志记录(包含关联 ID 的结构化 JSON 事件)、追踪(包含计时和元数据的请求级跨度)和监控(错误率跟踪、延迟百分位数和告警阈值)。三者结合,回答生产环境调试中的三个问题:发生了什么、耗时多久,以及失败的频率有多高。

适用场景

  • 为 Workers 或边缘应用添加日志记录
  • 使用分布式请求追踪调试生产环境问题
  • 设置错误监控和告警
  • 实现健康检查端点
  • 测量并报告延迟百分位数
  • 构建用于运维可视化的仪表板

工作原理

graph TD
    A[Incoming Request] --> B[Generate Trace ID]
    B --> C[Start Root Span]
    C --> D[Execute Handler]
    D --> E[Child Spans for Subrequests]
    E --> F{Error?}
    F -->|Yes| G[Capture Error + Context]
    F -->|No| H[Record Success Metrics]
    G --> I[Structured Log: ERROR]
    H --> J[Structured Log: INFO]
    I --> K[Ship to Collector via waitUntil]
    J --> K
    K --> L[External: Datadog / Grafana / Sentry]
    C --> M[End Root Span + Record Latency]
    M --> K

每个请求都会获得一个追踪 ID,该 ID 会在所有子请求和日志条目中传递。跨度用于测量各项操作的耗时。日志和跨度会批量处理,并通过 waitUntil() 异步发送,以避免增加响应延迟。

实现

interface LogEntry {
  timestamp: string;
  level: "debug" | "info" | "warn" | "error";
  traceId: string;
  spanId: string;
  message: string;
  data?: Record<string, unknown>;
  error?: { name: string; message: string; stack?: string };
  duration_ms?: number;
}

class RequestTracer {
  private traceId: string;
  private spans: LogEntry[] = [];
  private startTime: number;

  constructor(request: Request) {
    this.traceId = request.headers.get("x-trace-id") ?? crypto.randomUUID();
    this.startTime = performance.now();
  }

  span<T>(name: string, fn: () => Promise<T>): Promise<T> {
    const spanId = crypto.randomUUID().slice(0, 8);
    const start = performance.now();
    return fn().then(
      result => {
        this.log("info", name, { duration_ms: performance.now() - start }, spanId);
        return result;
      },
      error => {
        this.log("error", name, {
          duration_ms: performance.now() - start,
          error: { name: error.name, message: error.message, stack: error.stack },
        }, spanId);
        throw error;
      }
    );
  }

  log(level: LogEntry["level"], message: string, data?: Record<string, unknown>, spanId?: string): void {
    this.spans.push({
      timestamp: new Date().toISOString(),
      level,
      traceId: this.traceId,
      spanId: spanId ?? "root",
      message,
      ...data,
    });
  }

  async flush(env: { LOG_COLLECTOR: Fetcher }): Promise<void> {
    const rootDuration = performance.now() - this.startTime;
    this.log("info", "request_complete", { duration_ms: rootDuration });

    await env.LOG_COLLECTOR.fetch("https://collector/ingest", {
      method: "POST",
      body: JSON.stringify(this.spans),
      headers: { "Content-Type": "application/json" },
    });
  }
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const tracer = new RequestTracer(request);
    try {
      const data = await tracer.span("fetch_data", () => fetchData(env));
      const html = await tracer.span("render", () => render(data));
      return new Response(html, { status: 200 });
    } catch (error) {
      tracer.log("error", "unhandled_error", {
        error: { name: (error as Error).name, message: (error as Error).message },
        url: request.url,
        method: request.method,
      });
      return new Response("Internal Error", { status: 500 });
    } finally {
      ctx.waitUntil(tracer.flush(env));
    }
  },
} satisfies ExportedHandler<Env>;

最佳实践

  • 通过 waitUntil() 异步发送日志,避免增加响应延迟
  • 在所有错误响应中包含追踪 ID,方便用户提供该 ID 以协助调试
  • 使用结构化 JSON 日志记录,生产环境中切勿使用非结构化的 console.log
  • 为错误率(>1%)和 p99 延迟(>500ms)设置告警阈值
  • 在生产环境中对调试级别日志进行采样(1-10%),以控制日志量和成本
  • 通过 x-trace-id 标头在服务边界之间传递追踪 ID

平台兼容性

平台支持情况备注
Cursor完全支持检测代码生成
VS Code完全支持日志查看器集成
Windsurf完全支持可观测性模式
Claude Code完全支持Worker 检测
Cline完全支持日志记录和追踪设置
aider部分支持代码级检测

相关技能

关键词

observability structured-logging distributed-tracing error-monitoring cloudflare-workers alerting latency trace-id


© 2026 googleadsagent.ai™ | Agent Skills™ | MIT License

评论

支持 Markdown