返回首页
⚙️ 后端 / 架构
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
- 链接:https://opentelemetry.io/blog/1-30
- 来源:OpenTelemetry
- 摘要:OpenTelemetry 1.30 GA 推出 AI/ML 语义约定 + LLM Span + Cost Metrics。
2. Langfuse 推出 OTel 原生集成
- 链接:https://langfuse.com/blog/otel-native
- 来源:Langfuse
- 摘要:Langfuse 推出 OpenTelemetry 原生集成,自动收集 LLM 跟踪 / 评估 / 成本。
🎨 前端 / Web
3. Highlight.io 推出 Session Replay 2.0
- 链接:https://highlight.io/blog/replay-2
- 来源:Highlight.io
- 摘要:Highlight.io 推出 Session Replay 2.0,AI 异常检测 + 自动告警。
⚙️ 后端 / 架构
4. Grafana 推出 12 GA
- 链接:https://grafana.com/blog/12-ga
- 来源:Grafana
- 摘要:Grafana 12 推出 AI 异常检测 + Pyroscope 集成 + OpenTelemetry 原生。
5. Datadog 推出 LLM Observability
- 链接:https://datadog.com/blog/llm-obs
- 来源:Datadog
- 摘要:Datadog 推出 LLM Observability,自动跟踪 LLM 应用 + 成本 / 延迟 / 质量。
🚀 独立开发 / OPC
6. 即刻"可观测性"专题
- 链接:https://m.okjike.com/observability-2026
- 来源:即刻
- 摘要:即刻 300+ 独立开发者分享可观测性实战,OpenTelemetry + Grafana + Langfuse。
数据来源:掘金 / 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 年关键:
- 标准化:CNCF + Google + AWS + Microsoft 支持
- 生态成熟:1 万+ 集成
- LLM 原生:AI/ML 语义约定
- 开源开放:完全开源,无厂商锁定
- 企业级: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 接口":
- 标准化:一个协议,所有后端
- 生态成熟:CNCF 毕业项目
- LLM 原生:AI/ML 语义约定
- 开源开放:完全开源
- 企业级:Datadog / Grafana 都支持
对独立开发者的建议:
- 新项目:OTel + Grafana Cloud 免费层
- LLM 项目:Langfuse(专用)
- 生产项目:OTel + 采样(10%)
- 错误监控:Sentry(前端 + 后端)
- 成本优先:开源 Grafana + Tempo
参考
- OpenTelemetry 官方
- Grafana
- Langfuse
- Honeycomb
- Datadog LLM
- Sentry
- GitHub Actions(7/27)
- LLMOps(8/1)
- 零信任安全(8/11)
- Stripe(8/15)
本文基于 OpenTelemetry 1.30 GA,2026 年 8 月最新可观测性方案。