1. 项目概述为Claude Code构建可观测性基础设施最近在折腾一个挺有意思的项目起因是团队里用Claude Code一个基于Claude模型的代码生成工具的人越来越多但每次它“卡壳”或者生成的结果不太对劲时排查起来特别费劲。你只知道它“慢了”或者“错了”但具体是哪个环节耗时、内部处理逻辑是怎样的、资源消耗如何基本是两眼一抹黑。这感觉就像开一辆没有仪表盘的车油门踩下去不知道转速方向盘打了不知道轮胎角度全凭感觉。于是我决定给我们的Claude Code部署一套完整的OpenTelemetry简称OTel可观测性方案。这个项目仓库flysloughofdespond447/claude-code-opentelemetry-setup就是整个实践的结晶。简单说它的目标就是把Claude Code这个“黑盒”变成一个“透明盒”让我们能清晰地看到每一次代码生成请求的完整生命周期从请求发起到模型推理再到最终响应期间的延迟、错误、内部函数调用链路、资源指标全部一目了然。这不仅仅是加个日志那么简单。OpenTelemetry是一套云原生基金会CNCF孵化的标准它统一了追踪Traces、指标Metrics、日志Logs这三大可观测性支柱的数据采集和导出。通过它我们可以用标准化的方式在Claude Code的代码关键位置插入“探针”Instrumentation自动收集细粒度的性能数据并发送到我们喜欢的后端分析平台比如Jaeger、Prometheus或者商业化的Datadog、New Relic。对于任何在生产环境或重度使用场景下依赖Claude Code的开发者或团队来说这套 setup 的价值是巨大的。它能帮你精准定位性能瓶颈是网络延迟是模型加载慢还是某个后处理函数效率低下追踪链路会告诉你答案。快速诊断错误根源当Claude Code返回意外结果或抛出异常时完整的追踪上下文能帮你重现问题现场而不是靠猜。量化资源消耗与成本监控每次调用的Token消耗、内存使用、CPU时间为资源规划和成本优化提供数据支撑。提升团队协作与调试效率拥有统一的、可视化的数据视图不同角色的成员开发、运维、算法能用同一种“语言”讨论问题。接下来我会详细拆解整个方案的架构设计、核心组件的选型与配置、具体的代码插桩实践以及在实际部署中踩过的坑和总结出的技巧。无论你是想为自己使用的代码生成工具增加可观测性还是对OpenTelemetry如何接入AI应用感兴趣这份经验分享都应该能给你提供一条清晰的路径。2. 架构设计与核心组件选型给Claude Code套上OpenTelemetry听起来简单但做之前得先想清楚整个数据流怎么走。你不能胡乱插几个日志点就完事需要一个清晰、可扩展、且对原应用侵入性最小的架构。我的核心思路是“插桩采集 - 统一处理 - 导出可视化”。2.1 整体架构视图整个可观测性栈可以分成三层应用层Claude Code这是被观测的对象。我们需要在它的Python代码中通过OpenTelemetry的API和SDK在关键的业务逻辑处如接收请求、调用模型、处理响应添加追踪Span和记录指标。采集与处理层OpenTelemetry Collector这是中枢神经。我强烈推荐使用OpenTelemetry Collector作为一个独立的守护进程。它的好处是解耦。应用Claude Code只负责把数据用一种标准格式OTLP/gRPC或HTTP发送给本地的Collector而不需要关心后端是什么。Collector负责接收、处理过滤、采样、添加属性、批量发送数据到不同的后端。这样当你需要更换可视化工具比如从Jaeger换成Tempo时只需修改Collector的配置无需触动Claude Code的代码。后端存储与可视化层这是观察数据的窗口。根据团队习惯和基础设施可以选择开源组合或商业方案。我这次实践用的是经典的开源组合追踪TracesJaeger。它专为分布式追踪设计界面直观能清晰展示调用链和时序关系。指标MetricsPrometheusGrafana。Prometheus拉取Collector暴露的指标Grafana则用于制作丰富的监控仪表盘。日志Logs虽然OTel也支持日志但考虑到Claude Code本身可能已有日志框架如logging我采用了将日志关联到追踪的模式。即在打印日志时注入当前追踪的Trace ID和Span ID这样在Grafana Loki或Elasticsearch中查日志时能一键跳转到对应的追踪链路实现联动分析。这个架构的灵活性很高。如果你在Kubernetes环境中Collector可以以DaemonSet或Sidecar形式部署如果是单机或虚拟机作为一个系统服务运行即可。2.2 关键组件选型与考量OpenTelemetry Python SDK vs. 自动插桩Instrumentation库这是第一个决策点。OpenTelemetry提供了两种主要方式来为Python应用添加可观测性手动插桩使用opentelemetry-api和opentelemetry-sdk在代码中显式地创建Span、记录属性。这种方式控制力最强可以精确地在你认为重要的业务逻辑处埋点。自动插桩使用opentelemetry-instrumentation系列包。它们通过Python的“猴子补丁”Monkey-patching机制自动为流行的框架和库如Flask、Django、requests、httpx等注入追踪逻辑。你几乎不需要修改代码。对于Claude Code我选择了结合使用。原因在于Claude Code很可能基于某个Web框架如FastAPI或Flask来提供HTTP API也可能使用httpx或requests来调用Claude的模型API。对于这些通用组件使用自动插桩如opentelemetry-instrumentation-fastapi,opentelemetry-instrumentation-httpx能事半功倍自动捕获HTTP请求的入站和出站链路。但是Claude Code核心的“代码生成逻辑”——比如提示词组装、模型参数设置、响应解析、后处理代码格式化、安全检查——这些是独特的业务逻辑。自动插桩无法覆盖。这就需要我们手动创建Span来描绘这些内部细节这样才能形成有业务意义的完整追踪链路。因此依赖项会包括opentelemetry-sdk,opentelemetry-exporter-otlp-proto-grpc用于向Collector发送数据以及若干个opentelemetry-instrumentation-*包。OpenTelemetry Collector 配置模式Collector的配置是其强大功能的体现。主要配置在otel-collector-config.yaml文件中核心包括接收器Receivers配置如何接收数据。我们通常启用otlp接收器支持gRPC和HTTP两种协议并指定监听端口。receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318处理器Processors定义数据管道。常用的有batch将数据批量发送显著提升后端存储效率和网络利用率。memory_limiter防止内存溢出是生产环境的必备安全阀。attributes可以插入或删除Span/指标上的属性键值对比如添加一个deployment.environmentproduction的标签。导出器Exporters配置数据发往何处。我们需要为追踪和指标分别配置。exporters: debug: # 用于本地调试将数据打印到控制台 verbosity: detailed jaeger: # 将追踪发送到Jaeger endpoint: jaeger:14250 tls: insecure: true prometheus: # 将指标暴露给Prometheus拉取 endpoint: 0.0.0.0:8889 logging: # 将数据也打印到日志便于调试 verbosity: detailed服务Service将上述组件连接成数据流水线Pipeline。service: pipelines: traces: receivers: [otlp] processors: [batch, memory_limiter] exporters: [jaeger, logging] # 可以同时导出到多个地方 metrics: receivers: [otlp] processors: [batch, memory_limiter] exporters: [prometheus, logging]注意处理器batch和memory_limiter的顺序很重要。通常memory_limiter应在batch之前以便在数据进入批处理队列前就进行内存限制检查避免OOM内存溢出。batch处理器中的send_batch_size和timeout参数需要根据实际流量调整在延迟和吞吐量之间取得平衡。3. 核心细节Claude Code的插桩实践架构搭好了现在进入最核心的部分如何对Claude Code的代码进行“手术”植入OpenTelemetry的探针。我们的目标是既要获取有价值的洞察又要保持代码的整洁和可维护性。3.1 环境初始化与自动插桩首先需要在Claude Code应用启动的最早期初始化OpenTelemetry SDK。这通常在主程序入口如main.py或app.py中完成。我创建了一个单独的模块otel_setup.py来管理这部分配置保持主业务代码的纯净。# otel_setup.py import os from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import Resource, SERVICE_NAME, SERVICE_VERSION def setup_tracing(service_nameclaude-code-service, service_version1.0.0): 初始化OpenTelemetry追踪。 环境变量 OTEL_EXPORTER_OTLP_ENDPOINT 可用于指定Collector地址 例如OTEL_EXPORTER_OTLP_ENDPOINThttp://localhost:4317 # 1. 创建资源标识这些信息会附加到所有的Span上 resource Resource.create({ SERVICE_NAME: service_name, SERVICE_VERSION: service_version, deployment.environment: os.getenv(DEPLOYMENT_ENV, development), }) # 2. 设置全局的TracerProvider tracer_provider TracerProvider(resourceresource) trace.set_tracer_provider(tracer_provider) # 3. 创建OTLP导出器指向Collector和批处理处理器 otlp_exporter OTLPSpanExporter() span_processor BatchSpanProcessor(otlp_exporter) tracer_provider.add_span_processor(span_processor) # 4. 可选同时添加一个控制台导出器用于本地调试 if os.getenv(OTEL_DEBUG, false).lower() true: from opentelemetry.sdk.trace.export import ConsoleSpanExporter console_processor BatchSpanProcessor(ConsoleSpanExporter()) tracer_provider.add_span_processor(console_processor) print(fOpenTelemetry tracing initialized for service: {service_name}) return tracer_provider接下来是自动插桩。假设Claude Code使用FastAPI作为Web框架并使用httpx调用Claude API。我们可以在应用启动时通过环境变量或代码调用来自动启用这些插桩。方式一通过opentelemetry-instrument命令行包装器推荐用于简单启动这是最简单的方式你不需要修改任何代码。只需在启动命令前加上opentelemetry-instrument。opentelemetry-instrument \ --traces_exporter otlp \ --metrics_exporter otlp \ --service_name claude-code \ python -m uvicorn main:app --host 0.0.0.0 --port 8000这个命令会自动检测并插桩支持的库。但它的灵活性稍差对于复杂的手动埋点支持不够。方式二在代码中显式初始化自动插桩库更灵活我更倾向于这种方式因为它可以和上面的手动setup_tracing函数更好地集成。# 在 otel_setup.py 中补充 from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor # ... 其他可能用到的库如 logging, sqlalchemy 等 def instrument_applications(appNone): 初始化自动插桩 # 插桩 httpx HTTPXClientInstrumentor().instrument() # 如果传入了FastAPI app实例则插桩它 if app: FastAPIInstrumentor().instrument_app(app) # 还可以插桩标准库logging将日志与追踪关联 from opentelemetry.instrumentation.logging import LoggingInstrumentor LoggingInstrumentor().instrument() print(Auto-instrumentation for FastAPI and HTTPX has been enabled.)然后在你的FastAPI应用主文件中# main.py from fastapi import FastAPI from . import otel_setup app FastAPI(titleClaude Code API) # 初始化追踪和自动插桩 otel_setup.setup_tracing() otel_setup.instrument_applications(app) # ... 你的路由和业务逻辑这样一来所有进入FastAPI的HTTP请求都会自动创建一个根Span所有通过httpx发起的对外部服务如Claude API的调用都会自动创建子Span并建立父子关系。分布式追踪的骨架就自动搭建好了。3.2 手动业务埋点照亮“黑盒”内部自动插桩解决了框架层面的追踪但Claude Code的核心价值——代码生成逻辑——仍然是“黑盒”。我们需要手动埋点来照亮它。关键在于识别核心的业务函数并在其中创建有意义的Span。假设Claude Code处理请求的核心函数是generate_code(prompt: str, context: dict)。我们可以这样改造它from opentelemetry import trace from opentelemetry.trace import Status, StatusCode tracer trace.get_tracer(__name__) # 获取这个模块的Tracer def generate_code(prompt: str, context: dict): 生成代码的核心函数。 # 为整个代码生成过程创建一个Span with tracer.start_as_current_span(generate_code) as span: # 在Span上记录业务相关的属性Attributes这些是后续筛选和查询的关键 span.set_attribute(claude.prompt_length, len(prompt)) span.set_attribute(claude.model, context.get(model, claude-3-opus)) span.set_attribute(claude.temperature, context.get(temperature, 0.7)) try: # 1. 构建最终提示词 with tracer.start_as_current_span(build_final_prompt): final_prompt _build_prompt_with_context(prompt, context) span.set_attribute(claude.final_prompt_snippet, final_prompt[:100]) # 记录前100字符 # 2. 调用Claude API with tracer.start_as_current_span(call_claude_api) as api_span: # 注意由于我们已经插桩了httpx这个对外调用会自动生成一个子Span。 # 但我们可以在这个手动Span上记录一些额外的业务信息。 response _call_claude_api(final_prompt, context) api_span.set_attribute(claude.api.response_id, response.id) api_span.set_attribute(claude.api.usage.prompt_tokens, response.usage.prompt_tokens) api_span.set_attribute(claude.api.usage.completion_tokens, response.usage.completion_tokens) # 将自动生成的HTTP Span的Trace ID记录下来实现更强的关联如果API返回的话 # 3. 解析和清理响应 with tracer.start_as_current_span(parse_and_clean_response): generated_code _extract_code_from_response(response) span.set_attribute(claude.generated_code_length, len(generated_code)) # 4. 可选后处理安全检查、格式化 with tracer.start_as_current_span(post_processing): safe_code _security_check(generated_code) formatted_code _format_code(safe_code) # 标记整个Span为成功 span.set_status(Status(StatusCode.OK)) return formatted_code except Exception as e: # 记录异常信息到当前Span span.record_exception(e) # 将Span状态标记为错误 span.set_status(Status(StatusCode.ERROR, str(e))) # 重新抛出异常 raise手动埋点的核心技巧Span的命名要有意义使用动词或动宾结构如call_claude_api、parse_response而不是step1、step2。属性Attributes是黄金记录所有有助于事后分析的上下文信息。例如提示词长度、模型名称、温度参数、Token用量、生成的代码长度、用户ID需脱敏、任务类型等。OpenTelemetry对属性数量没有硬性限制但应避免记录过大的数据如完整的提示词。合理设置Status成功时设为OK失败时设为ERROR并附上错误描述。这能让你在Jaeger等UI中快速过滤出所有失败的请求。记录异常使用span.record_exception(e)可以将异常的堆栈信息记录到Span事件中这对于调试至关重要。利用上下文传播start_as_current_span会自动管理Span的上下文确保在异步或并发环境中子Span能正确关联到父Span。这是构建正确调用链的关键。通过这种“自动插桩打骨架手动埋点填血肉”的方式我们就能得到一条极其详细的追踪链路。在Jaeger中你将看到一次/generate的HTTP请求如何展开为generate_code-build_final_prompt-call_claude_api其下还有自动生成的HTTP Span-parse_and_clean_response-post_processing的完整视图每个步骤的耗时、属性都清晰可见。4. 指标Metrics收集与业务监控追踪让我们看到了请求的“纵剖面”而指标Metrics则提供了系统的“横截面”视图比如每秒请求数RPS、平均响应时间、错误率、Token消耗速率等。这些指标对于容量规划、告警和健康度评估必不可少。OpenTelemetry Metrics API 的使用方式与Tracing类似。我们需要在代码中定义和记录指标。针对Claude Code我定义了以下几个核心业务指标# metrics.py from opentelemetry import metrics from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter # 创建MeterProvider通常与TracerProvider一起初始化 metric_reader PeriodicExportingMetricReader( exporterOTLPMetricExporter(), export_interval_millis60000 # 每60秒导出一次指标 ) meter_provider MeterProvider(metric_readers[metric_reader]) metrics.set_meter_provider(meter_provider) # 获取一个Meter来创建指标 meter metrics.get_meter(claude.code.service) # 定义指标 # 1. 计数器Counter用于记录只会增加的值如总请求数、总Token数。 request_counter meter.create_counter( nameclaude.code.requests.total, descriptionTotal number of code generation requests, unit1 ) prompt_token_counter meter.create_counter( nameclaude.code.tokens.prompt.total, descriptionTotal prompt tokens consumed, unit1 ) completion_token_counter meter.create_counter( nameclaude.code.tokens.completion.total, descriptionTotal completion tokens consumed, unit1 ) # 2. 直方图Histogram用于记录值的分布如响应延迟、生成代码长度。 # 它自动计算平均值、分位数如p95, p99等。 generation_duration_histogram meter.create_histogram( nameclaude.code.generation.duration, descriptionDuration of code generation in milliseconds, unitms ) generated_code_length_histogram meter.create_histogram( nameclaude.code.generated.length, descriptionLength of generated code in characters, unit1 ) # 3. 可观察仪表ObservableGauge用于记录当前瞬间的值如内存使用率、队列长度。 # 需要提供一个回调函数来获取值。 # 例如监控待处理请求队列长度假设有个全局变量 pending_queue def get_pending_queue_size(): return len(pending_queue) meter.create_observable_gauge( nameclaude.code.queue.pending, callbacks[get_pending_queue_size], descriptionCurrent size of pending request queue, unit1 )定义好指标后在业务代码中记录它们# 在 generate_code 函数中 def generate_code(prompt: str, context: dict): start_time time.time() # 增加请求计数并添加属性以便按维度聚合如按模型、环境 request_counter.add(1, attributes{model: context.get(model), env: os.getenv(DEPLOYMENT_ENV)}) try: # ... 原有的生成逻辑 ... response _call_claude_api(final_prompt, context) # 记录Token消耗 prompt_token_counter.add(response.usage.prompt_tokens) completion_token_counter.add(response.usage.completion_tokens) generated_code _extract_code_from_response(response) # 记录生成代码长度 generated_code_length_histogram.record(len(generated_code)) return formatted_code finally: # 记录请求耗时 duration_ms (time.time() - start_time) * 1000 generation_duration_histogram.record(duration_ms)指标设计的经验为指标添加有意义的属性Attributes/Tags这是指标分析威力的来源。例如给request_counter加上model和status_code属性你就能轻松分析不同模型的请求分布和成功率。给耗时直方图加上model属性就能对比不同模型的性能。注意基数爆炸避免使用可能取值无限多的属性比如user_id或request_id。这会导致指标后端如Prometheus产生海量的时间序列拖垮系统。属性应该用于有意义的、取值有限的维度划分如model,env,error_type。单位要明确unit参数虽然可选但最好加上如ms、s、1无量纲、By字节避免混淆。配置好Collector的Prometheus导出器后这些指标就会被Prometheus抓取。你可以在Grafana中创建仪表盘监控诸如“各模型每分钟请求量”、“平均响应时间与P99延迟”、“Token消耗速率”、“错误率”等关键业务图表实现对Claude Code服务健康状况和资源消耗的实时掌控。5. 部署、集成与问题排查实录将这套可观测性方案部署到实际环境无论是开发机、测试环境还是生产环境时会遇到一些具体问题。下面是我在实践过程中记录的关键步骤和踩过的坑。5.1 部署OpenTelemetry CollectorCollector是数据枢纽其部署的稳定性和配置正确性至关重要。1. 使用Docker Compose开发/测试环境首选这是最快捷的方式。创建一个docker-compose.yaml文件定义Collector、Jaeger、Prometheus和Grafana服务。version: 3.8 services: # OpenTelemetry Collector otel-collector: image: otel/opentelemetry-collector-contrib:latest command: [--config/etc/otel-collector-config.yaml] volumes: - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml ports: - 4317:4317 # OTLP gRPC 接收端口 - 4318:4318 # OTLP HTTP 接收端口 - 8889:8889 # Prometheus 指标暴露端口 networks: - observability-net # Jaeger (用于追踪) jaeger: image: jaegertracing/all-in-one:latest ports: - 16686:16686 # Jaeger UI - 14250:14250 # Jaeger gRPC接收端口Collector使用 environment: - COLLECTOR_OTLP_ENABLEDtrue networks: - observability-net # Prometheus (用于指标) prometheus: image: prom/prometheus:latest volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml ports: - 9090:9090 networks: - observability-net # Grafana (用于可视化) grafana: image: grafana/grafana-enterprise:latest ports: - 3000:3000 environment: - GF_SECURITY_ADMIN_PASSWORDadmin volumes: - grafana-storage:/var/lib/grafana networks: - observability-net volumes: grafana-storage: networks: observability-net: driver: bridge对应的prometheus.yml需要配置抓取Collector暴露的指标scrape_configs: - job_name: otel-collector static_configs: - targets: [otel-collector:8889]2. Collector配置的常见陷阱内存限制一定要配置memory_limiter处理器。生产环境流量不可预测没有内存限制的Collector可能因突发流量而崩溃。配置示例processors: memory_limiter: check_interval: 1s limit_mib: 512 # 根据容器内存限制调整例如设置为容器内存的80% spike_limit_mib: 128 batch: send_batch_size: 10000 timeout: 10s数据丢失在batch处理器中timeout参数决定了数据在内存中停留的最长时间。如果设置过长如1小时在Collector重启时内存中未发送的数据会丢失。需要根据后端存储的可靠性和你对数据丢失的容忍度来权衡。对于关键业务可以考虑启用Collector的file_storage扩展将队列中的数据持久化到磁盘。网络连通性确保Collector容器能访问Jaeger、Prometheus等后端服务。在Docker Compose中使用自定义网络如observability-net并确保服务名可解析。5.2 集成到Claude Code应用环境变量配置为了让Claude Code应用知道将数据发送到哪里最佳实践是通过环境变量配置。OpenTelemetry SDK会自动读取一系列标准环境变量。在你的Claude Code应用的Dockerfile或启动脚本中设置export OTEL_EXPORTER_OTLP_ENDPOINThttp://otel-collector:4317 export OTEL_SERVICE_NAMEclaude-code-production export OTEL_RESOURCE_ATTRIBUTESdeployment.environmentproduction,service.version1.2.0 # 启用自动检测如果使用opentelemetry-instrument命令 export OTEL_PYTHON_LOG_LEVELDEBUG # 可选用于调试依赖管理在Claude Code的requirements.txt或pyproject.toml中添加必要的依赖opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc # 或 opentelemetry-exporter-otlp-proto-http opentelemetry-instrumentation-fastapi opentelemetry-instrumentation-httpx opentelemetry-instrumentation-logging # 根据你使用的其他库添加对应的instrumentation包5.3 常见问题排查技巧在实际部署中你可能会遇到数据看不到、链路不完整等问题。以下是我总结的排查清单问题1Jaeger UI中看不到任何追踪数据。检查链路应用端是否成功发送在Claude Code应用启动时设置OTEL_PYTHON_LOG_LEVELDEBUG查看日志中是否有关于Span导出成功或失败的信息。或者在Collector配置中启用debug或logging导出器将接收到的数据打印到Collector日志中这是最直接的验证方式。Collector是否收到查看Collector容器的日志。确保其配置的接收器otlp端口与应用发送的端口一致默认gRPC是4317HTTP是4318。Collector是否成功导出检查Collector日志中是否有连接到Jaeger后端失败的错误如网络不通、TLS证书问题。确保Jaeger服务地址如jaeger:14250在Collector容器内可访问。快速调试工具在开发初期可以在Collector配置中临时添加logging导出器并设置verbosity: detailed这样所有经过Collector的数据都会以JSON格式打印到日志非常直观。问题2追踪链路不完整缺少手动创建的Span。检查Tracer作用域确保你在函数中使用的tracer是通过trace.get_tracer(__name__)在同一个模块中获取的或者确保全局TracerProvider已正确设置。检查上下文传播在异步函数或使用线程池/进程池时OpenTelemetry的上下文可能不会自动传递。你需要使用opentelemetry.context模块来手动附着attach和提取extract上下文。对于asyncio通常SDK能较好处理但对于concurrent.futures.ThreadPoolExecutor则需要额外处理。验证Span是否被记录在手动创建Span的代码块中添加简单的日志输出确认代码执行路径确实经过了那里。问题3Prometheus抓不到指标。检查指标导出器配置Collector配置中prometheus导出器的endpoint是否正确如:8889并且该端口是否已映射到主机。检查Prometheus配置prometheus.yml中的targets地址是否正确如果是Docker Compose使用服务名otel-collector:8889。检查指标是否有数据直接访问Collector暴露的指标端点如http://localhost:8889/metrics看是否有claude_code_开头的指标输出。如果没有说明应用端没有成功记录或导出指标。问题4性能开销是否可接受这是引入任何可观测性方案都必须考虑的问题。OpenTelemetry的设计目标之一就是低开销。采样Sampling是关键在生产环境对所有请求进行100%追踪头部采样可能开销巨大且不必要。通常采用尾部采样或概率采样。可以在Collector端配置probabilistic_sampler处理器例如只对1%的请求进行全量追踪。对于错误请求可以配置基于属性的采样确保所有错误都被记录。processors: probabilistic_sampler: sampling_percentage: 1.0 # 1%的采样率批处理Batching确保使用了batch处理器它能大幅减少网络往返次数。异步导出OpenTelemetry SDK默认使用异步模式导出数据不会阻塞主业务线程。经过这些步骤你应该能拥有一个运行稳定、数据全面的Claude Code可观测性系统。当再次遇到生成慢或出错时打开Jaeger输入相关的服务名或Trace ID请求的完整旅程和所有细节都将展现在你面前。结合Grafana仪表盘上的实时指标你不仅能快速定位问题还能提前发现潜在的性能退化趋势从被动的“救火”转向主动的“预防”。这套 setup 的价值会在每一次高效的问题排查和每一次有数据支撑的架构决策中体现出来。