返回首页
⚙️ 后端 / 架构

OpenTelemetry 2026:从指标到日志追踪的可观测性实战完整指南

OpenTelemetry 是 2026 年可观测性标准。本文 6 大核心组件 + 4 个实战项目 + 与 Grafana / Datadog / Langfuse 对比 + LLM 应用集成。

OpenTelemetry · OTel · 可观测性 · Observability · Metrics · Traces · Logs · Grafana · Langfuse
��

今日技术简讯

📰 技术简讯 · 2026-08-18

今日聚合 6 条热门技术内容(中文素材优先)。

🤖 AI / LLM

1. OpenTelemetry 推出 1.30 GA

2. Langfuse 推出 OTel 原生集成

🎨 前端 / Web

3. Highlight.io 推出 Session Replay 2.0

⚙️ 后端 / 架构

4. Grafana 推出 12 GA

5. Datadog 推出 LLM Observability

🚀 独立开发 / OPC

6. 即刻"可观测性"专题


数据来源:掘金 / InfoQ 中文 / 即刻 / 少数派 / HN 采集日期:2026-08-18 (UTC+8)

��

今日深度文

OpenTelemetry 2026:从指标到日志追踪的可观测性实战完整指南

一句话结论:OpenTelemetry = 可观测性的"USB-C 接口"。统一 Metrics / Logs / Traces,一个标准,所有后端可用。本文从 0 到完整可观测性体系。

背景

2026 年可观测性的痛点:

传统监控(各自为政):
- Prometheus(指标)
- Jaeger(追踪)
- ELK(日志)
- Datadog(全包)

→ 多套 SDK / 多套协议 / 多份配置

OpenTelemetry 出现,一统江湖

OpenTelemetry(OTel):
- CNCF 毕业项目
- 统一协议(OTLP)
- 多语言 SDK
- 所有后端兼容(Jaeger / Tempo / Grafana / Datadog / Sentry)
- LLM 应用原生支持

为什么 OpenTelemetry 是 2026 年关键:

  1. 标准化:CNCF + Google + AWS + Microsoft 支持
  2. 生态成熟:1 万+ 集成
  3. LLM 原生:AI/ML 语义约定
  4. 开源开放:完全开源,无厂商锁定
  5. 企业级:Datadog / Grafana / Honeycomb 都支持

6 大核心组件

组件 1:Metrics(指标)

// lib/metrics.ts
import { metrics } from "@opentelemetry/api";

const meter = metrics.getMeter("my-app");

// 1. Counter(计数)
const requestCounter = meter.createCounter("http.requests", {
  description: "Total HTTP requests",
});

requestCounter.add(1, { method: "GET", status: 200 });

// 2. Histogram(直方图)
const latencyHistogram = meter.createHistogram("http.duration", {
  description: "HTTP request duration",
  unit: "ms",
});

const start = Date.now();
// ... 处理请求 ...
latencyHistogram.record(Date.now() - start, { endpoint: "/api/users" });

// 3. UpDownCounter(增减)
const activeConnections = meter.createUpDownCounter("ws.connections");
activeConnections.add(1);  // 新连接
activeConnections.add(-1); // 断开

// 4. Gauge(瞬时值)
const memoryGauge = meter.createObservableGauge("memory.usage");
memoryGauge.addCallback((result) => {
  const usage = process.memoryUsage().heapUsed;
  result.observe(usage, { type: "heap" });
});

组件 2:Traces(追踪)

// lib/tracing.ts
import { trace, SpanStatusCode } from "@opentelemetry/api";

const tracer = trace.getTracer("my-app");

// 1. 手动 Span
async function processOrder(orderId: string) {
  return tracer.startActiveSpan("process_order", async (span) => {
    try {
      span.setAttribute("order.id", orderId);

      // 子 Span
      await tracer.startActiveSpan("validate_order", async (validateSpan) => {
        await validateOrder(orderId);
        validateSpan.end();
      });

      await tracer.startActiveSpan("charge_payment", async (chargeSpan) => {
        await chargePayment(orderId);
        chargeSpan.end();
      });

      span.setStatus({ code: SpanStatusCode.OK });
    } catch (error) {
      span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
      span.recordException(error);
      throw error;
    } finally {
      span.end();
    }
  });
}

// 2. 自动 Span(用装饰器)
import { trace } from "@opentelemetry/api";

export function Trace(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = async function (...args: any[]) {
    return tracer.startActiveSpan(propertyKey, async (span) => {
      try {
        const result = await originalMethod.apply(this, args);
        span.setStatus({ code: SpanStatusCode.OK });
        return result;
      } catch (err) {
        span.recordException(err);
        throw err;
      } finally {
        span.end();
      }
    });
  };
}

class UserService {
  @Trace
  async getUser(id: string) { /* ... */ }
}

组件 3:Logs(日志)

// lib/logger.ts
import { logs, SeverityNumber } from "@opentelemetry/api-logs";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";

const logger = logs.getLogger("my-app");

// 结构化日志
logger.emit({
  severityNumber: SeverityNumber.INFO,
  severityText: "INFO",
  body: "User logged in",
  attributes: {
    "user.id": "user_123",
    "user.email": "user@example.com",
    "session.id": "sess_456",
  },
});

// 错误日志
logger.emit({
  severityNumber: SeverityNumber.ERROR,
  severityText: "ERROR",
  body: "Database query failed",
  attributes: {
    "db.statement": "SELECT * FROM users",
    "error.type": "TimeoutError",
    "error.message": "Connection timeout after 5s",
  },
});

组件 4:LLM 语义约定(AI 专用)

// lib/llm-tracing.ts
import { trace } from "@opentelemetry/api";

const tracer = trace.getTracer("llm-app");

// 跟踪 LLM 调用(OpenTelemetry AI 语义约定)
async function callLLM(prompt: string) {
  return tracer.startActiveSpan("llm.completion", async (span) => {
    span.setAttribute("gen_ai.system", "openai");
    span.setAttribute("gen_ai.request.model", "gpt-4");
    span.setAttribute("gen_ai.request.max_tokens", 1024);
    span.setAttribute("gen_ai.request.temperature", 0.7);

    // Prompt
    span.setAttribute("gen_ai.prompt", prompt);

    const start = Date.now();

    const response = await openai.chat.completions.create({
      model: "gpt-4",
      messages: [{ role: "user", content: prompt }],
      max_tokens: 1024,
      temperature: 0.7,
      stream: true,
    });

    let content = "";
    let promptTokens = 0;
    let completionTokens = 0;

    for await (const chunk of response) {
      content += chunk.choices[0]?.delta?.content || "";
      promptTokens = chunk.usage?.prompt_tokens || promptTokens;
      completionTokens = chunk.usage?.completion_tokens || completionTokens;
    }

    // 响应
    span.setAttribute("gen_ai.completion", content);
    span.setAttribute("gen_ai.usage.prompt_tokens", promptTokens);
    span.setAttribute("gen_ai.usage.completion_tokens", completionTokens);

    // 成本
    const cost = calculateCost("gpt-4", promptTokens, completionTokens);
    span.setAttribute("gen_ai.usage.cost_usd", cost);

    span.setAttribute("duration_ms", Date.now() - start);
    span.setStatus({ code: SpanStatusCode.OK });
    span.end();

    return content;
  });
}

function calculateCost(model: string, prompt: number, completion: number): number {
  const rates: Record<string, { prompt: number; completion: number }> = {
    "gpt-4": { prompt: 0.03 / 1000, completion: 0.06 / 1000 },
    "claude-sonnet": { prompt: 0.003 / 1000, completion: 0.015 / 1000 },
  };
  const rate = rates[model];
  return prompt * rate.prompt + completion * rate.completion;
}

组件 5:OTLP 导出(统一协议)

// instrumentation.ts
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-traces-otlp-http";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";

const sdk = new NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: "my-app",
    [SemanticResourceAttributes.SERVICE_VERSION]: "1.0.0",
    [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: "production",
  }),

  // Trace 导出
  traceExporter: new OTLPTraceExporter({
    url: "https://api.honeycomb.io/v1/traces",
    headers: { "x-honeycomb-team": process.env.HONEYCOMB_API_KEY! },
  }),

  // Metric 导出
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({
      url: "https://api.honeycomb.io/v1/metrics",
    }),
    exportIntervalMillis: 10000,
  }),

  // 自动检测
  instrumentations: [
    new HttpInstrumentation(),
    new ExpressInstrumentation(),
    new PrismaInstrumentation(),
    new IORedisInstrumentation(),
  ],
});

sdk.start();

组件 6:可视化(Grafana)

# docker-compose.yml
version: "3.8"
services:
  grafana:
    image: grafana/grafana:12.0.0
    ports: ["3000:3000"]
    environment:
      GF_INSTALL_PLUGINS: grafana-pyroscope-datasource
    volumes:
      - ./grafana/provisioning:/etc/grafana/provisioning

  tempo:  # 追踪后端
    image: grafana/tempo:2.5.0
    command: ["-config.file=/etc/tempo.yml"]
    volumes:
      - ./tempo.yml:/etc/tempo.yml

  prometheus:  # 指标
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  loki:  # 日志
    image: grafana/loki:3.0.0
# grafana/provisioning/datasources/datasource.yml
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    url: http://prometheus:9090
  - name: Tempo
    type: tempo
    url: http://tempo:3200
  - name: Loki
    type: loki
    url: http://loki:3100

4 个实战项目

项目 1:HTTP API 自动追踪

// 自动检测 Express / Fastify / Hono
// lib/instrumentation.ts
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";

// 自动为每个 HTTP 请求创建 Span
// 自动为每个数据库查询创建 Span
// 自动捕获错误

// 业务代码无需任何修改,自动收集:
// - 请求路径 / 方法 / 状态码
// - 响应时间
// - 错误堆栈
// - 链路追踪(DB → API → 第三方)

项目 2:LLM 应用可观测性

# llm_app.py
from opentelemetry import trace
from opentelemetry.instrumentation.openai import OpenAIInstrumentation

# 自动检测 OpenAI / Anthropic / Cohere
OpenAIInstrumentation().instrument()

# 自动收集:
# - Prompt + Response
# - Token 用量
# - 成本估算
# - 延迟
# - 错误

tracer = trace.get_tracer(__name__)

@tracer.start_as_current_span("agent_workflow")
async def run_agent(query: str):
    # 1. RAG
    with tracer.start_as_current_span("rag_retrieval"):
        context = await retrieve_context(query)

    # 2. LLM
    with tracer.start_as_current_span("llm_generation"):
        response = await llm.generate(query, context)

    # 3. Tool call
    if needs_tool(response):
        with tracer.start_as_current_span("tool_call"):
            result = await execute_tool(response)

    return result

项目 3:自定义业务指标

// 业务 KPI 监控
const ordersCounter = meter.createCounter("orders.created");
const revenueCounter = meter.createCounter("revenue.usd");
const activeUsers = meter.createObservableGauge("users.active");

// 用户下单
ordersCounter.add(1, { plan: "pro", region: "us" });

// 收入
const revenue = calculateRevenue(order);
revenueCounter.add(revenue, { currency: "USD", plan: "pro" });

// 活跃用户
activeUsers.addCallback(async (result) => {
  const count = await db.users.count({ where: { lastActiveAt: { gt: fiveMinutesAgo } } });
  result.observe(count);
});

// Grafana 仪表板
// - QPS / 延迟 / 错误率(RED 指标)
// - 订单数 / 收入 / 转化率(业务 KPI)
// - LLM 成本 / Token 用量(AI 专属)

项目 4:告警 + SLO

# grafana/slo.yml
apiVersion: grafana/v1
kind: SLO
metadata:
  name: api-availability
spec:
  description: HTTP API 99.9% 可用性
  service: my-app
  indicator:
    type: availability
    query:
      success-criteria: |
        sum(rate(http_requests_total{status=~"2.."}[30d]))
        /
        sum(rate(http_requests_total[30d]))
    target: 0.999
  timeWindow:
    type: rolling
    period: 30d
  alerting:
    name: api-availability-alert
    annotations:
      summary: API 可用性低于 99.9%
    labels:
      severity: critical

# Grafana Alert Rule
# expr: success_rate < 0.999
# for: 5m
# annotations:
#   summary: "API 成功率 {{ $value | humanizePercentage }}"

可观测性平台对比

平台 类型 价格 LLM 支持 OTLP
Grafana Cloud 开源 + 云 免费 / $8/月 ⭐⭐⭐⭐⭐
Honeycomb SaaS $0/130M events ⭐⭐⭐⭐⭐
Datadog SaaS $15/host/月 ⭐⭐⭐⭐⭐
Langfuse 开源 + 云 免费 / $29/月 ⭐⭐⭐⭐⭐
Sentry SaaS $26/月 ⭐⭐⭐
New Relic SaaS $25/月 ⭐⭐⭐⭐
Highlight.io 开源 + 云 免费 / $22/月 ⭐⭐⭐
选型建议:
- 开源 + 全栈 → Grafana + Tempo + Prometheus + Loki
- LLM 优先 → Langfuse(专用)
- 全托管 → Datadog(贵但完整)
- 预算有限 → Grafana Cloud 免费层
- 错误优先 → Sentry

5 个常见坑

坑 1:采样率过高

// ❌ 100% 采样(成本爆炸)
TraceIdRatioBased(1.0);

// ✅ 生产环境 10% 采样
new ParentBasedTraceIdRatioSampler(0.1);

// ✅ 错误全采样
new ParentBased({
  root: new TraceIdRatioBased(0.1),
  localParentSampled: new AlwaysOnSampler(),
  remoteParentSampled: new AlwaysOnSampler(),
  remoteParentNotSampled: new AlwaysOffSampler(),
}),

坑 2:PII 泄露到追踪

// ❌ 把用户邮箱 / token 写入 span
span.setAttribute("user.email", "alice@example.com");
span.setAttribute("authorization", "Bearer xxx");

// ✅ 脱敏
span.setAttribute("user.id", hash("alice@example.com"));
// Authorization 自动从 URL/Header 排除
new HttpInstrumentation({
  ignoreIncomingRequestHook: (req) => req.url.includes("/health"),
}),

坑 3:Span 太多

// ❌ 每个循环迭代一个 Span
for (const item of items) {
  await tracer.startActiveSpan("process_item", async (span) => {
    await process(item);
    span.end();
  });
}

// ✅ 批量一个 Span
await tracer.startActiveSpan("batch_process", async (span) => {
  span.setAttribute("batch.size", items.length);
  for (const item of items) {
    await process(item);
  }
  span.end();
});

坑 4:异步上下文丢失

// ❌ async 回调中 span 失效
tracer.startActiveSpan("outer", async (span) => {
  setTimeout(() => {
    tracer.startActiveSpan("inner", () => {});  // 错误的父 span
  }, 100);
});

// ✅ 用 context.with
import { context, trace } from "@opentelemetry/api";

tracer.startActiveSpan("outer", async (span) => {
  const ctx = trace.setSpan(context.active(), span);

  setTimeout(() => {
    context.with(ctx, () => {
      tracer.startActiveSpan("inner", () => {});
    });
  }, 100);
});

坑 5:未关联 LLM Span

// ❌ 没有 LLM 语义约定
span.setAttribute("model", "gpt-4");
span.setAttribute("tokens", 100);

// ✅ OTel AI 语义约定
span.setAttribute("gen_ai.system", "openai");
span.setAttribute("gen_ai.request.model", "gpt-4");
span.setAttribute("gen_ai.usage.prompt_tokens", 50);
span.setAttribute("gen_ai.usage.completion_tokens", 50);

与之前内容的关系

7/27 GitHub Actions       → CI/CD
8/1  LLM 工程化          → LLM 测试 / 评估
8/11 零信任安全          → 安全
8/15 Stripe               → 支付
8/18 OpenTelemetry        → 可观测性  ← 今天
→ "CI → 测试 → 安全 → 支付 → 监控"完整生产闭环

7 天落地路径

Day 1:基础追踪

// 启动 OTel SDK

Day 2:自动检测

// HTTP / DB / Redis

Day 3:业务指标

// 订单 / 收入 / 用户

Day 4:LLM 追踪

// OpenAI / Anthropic

Day 5:可视化

# Grafana 仪表板

Day 6:告警

# SLO / Alert

Day 7:成本优化

# 采样率 / 存储

我的看法

OpenTelemetry 是 2026 年可观测性的"USB-C 接口"

  1. 标准化:一个协议,所有后端
  2. 生态成熟:CNCF 毕业项目
  3. LLM 原生:AI/ML 语义约定
  4. 开源开放:完全开源
  5. 企业级:Datadog / Grafana 都支持

对独立开发者的建议:

  • 新项目:OTel + Grafana Cloud 免费层
  • LLM 项目:Langfuse(专用)
  • 生产项目:OTel + 采样(10%)
  • 错误监控:Sentry(前端 + 后端)
  • 成本优先:开源 Grafana + Tempo

参考


本文基于 OpenTelemetry 1.30 GA,2026 年 8 月最新可观测性方案。

�� 同主题文章

⚙️ 后端 / 架构 分类更多