
FastAPI链路追踪别写满手工埋点:先自动接入OpenTelemetry

为FastAPI配置链路追踪,先让OpenTelemetry自动记录HTTP请求,再通过OTLP导出到Jaeger;无需逐个路由手写Span。OpenTelemetry的FastAPI埋点组件支持命令行自动埋点,也支持通过FastAPIInstrumentor.instrument_app(app)显式接入。
先确认服务是否已经产生请求Span,再选择一种请求埋点方式。数据库访问和HTTP客户端请求应优先使用与实际库匹配的现成组件;手工Span留给计价、规则判断、降级处理等需要单独观察的业务步骤。本地查到链路后,再处理生产接收端、探针排除、采样、日志关联和敏感字段。
用本地Jaeger跑通请求链路

FastAPI与Jaeger的端到端示例使用all-in-one容器:16686提供查询界面,4317接收OTLP gRPC,4318接收OTLP HTTP。该容器默认使用内存存储,重启后链路不会保留,适合验证应用到接收端的连接。
- 启动Jaeger:docker run -d --name jaeger -p 16686:16686 -p 4317:4317 -p 4318:4318 jaegertracing/all-in-one:latest。若端口或容器名已被占用,调整本机映射或名称。
- 对于已提供内置OpenTelemetry请求遥测的FastAPI项目,在虚拟环境中安装发送遥测所需的依赖,例如pip install "fastapi[standard]"。设置FASTAPI_OTEL_AUTO_CONFIGURE=true、OTEL_SERVICE_NAME=fastapi-api、OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318、OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf、OTEL_METRICS_EXPORTER=none和OTEL_LOGS_EXPORTER=none,再用python -m uvicorn main:app启动服务;main:app应替换为项目入口。
- 如果项目使用尚未产生请求Span的接入方式,可安装opentelemetry-distro、opentelemetry-instrumentation-fastapi和opentelemetry-exporter-otlp,再用opentelemetry-instrument python -m uvicorn main:app启动。此时同样设置服务名和OTLP导出参数,并只保留一个请求埋点入口。
访问一个业务路由,然后到http://localhost:16686按服务名fastapi-api查询。Span通常批量导出,刚发出请求时可能需要稍等;若始终没有结果,依次核对应用导出错误、协议、接收端口和服务名。Jaeger查询界面的地址不能作为OTLP接收地址。
在查到的请求中核对下游操作是否出现,并留意是否有含义重复的入口Span。若同一请求已有内置遥测,再叠加框架埋点组件会增加难以解释的层级;确定由哪一层负责记录入口请求后,再补缺失的边界。
手工Span只补业务边界
数据库驱动和HTTP客户端的下游Span取决于对应组件是否安装、与所用库是否适配,以及组件是否在进程启动时启用。某次操作没有出现时,先检查这些条件;给同一次调用再包一层同义的手工Span,通常只会重复记录耗时。
手工埋点更适合有明确起止点、又无法由通用组件命名的业务操作。以假设的订单计价流程为例,可以用trace.get_tracer(__name__)取得tracer,再以tracer.start_as_current_span("order.calculate_price")包住计价步骤。Span名称表达稳定的操作,不写入订单号、用户输入或计价结果。
属性只保留排障所需且经过审查的分类信息,不放入令牌、完整请求体或订单原文。异常从Span作用域抛出时,埋点库可能记录异常详情;若异常已在作用域内被捕获并转为降级结果,应按实际业务语义决定是否显式记录失败,同时审查异常消息与堆栈。
排除探针请求,再设采样比例
健康检查和就绪探针反复访问固定路径,通常无需为每次访问保留链路。使用FastAPI埋点组件时,可将OTEL_PYTHON_FASTAPI_EXCLUDED_URLS设为逗号分隔的正则表达式,例如healthz$,readyz$;显式接入时,也可向instrument_app(app, excluded_urls="healthz$,readyz$")传入规则。上线前用实际路径核对匹配范围,避免误排除同样以后缀结尾的业务URL。
如果使用FastAPI内置遥测,则通过telemetry配置中的exclude函数按ASGI scope筛选路径,而不是把上述组件变量当作内置功能。两种排除方法对应不同的请求埋点入口;应在Jaeger中核对探针消失,同时确认正常业务路由仍有链路。
本地验证可先保留完整链路;生产采样比例则由流量、存储预算和排障需求决定。一个示例配置是OTEL_TRACES_SAMPLER=parentbased_traceidratio、OTEL_TRACES_SAMPLER_ARG=0.1:没有上游父Span的新链路按示例比例取样,有父Span时沿用上游决定。这里的比例只用于展示配置方式,不是所有服务的生产默认值。
入口采样在请求开始时决定,后续才出现的错误可能落在未采样链路中。评估比例时要考虑跨服务链路的连续性和低频故障所需的样本;错误日志应有独立的保留与过滤策略。调低追踪采样率不会自动保留全部失败请求,也不会清理日志中的敏感内容。
用trace ID关联日志

日志关联的关键是让同一次请求的日志记录带上trace ID,必要时再带span ID。使用标准Python日志时,可以从trace.get_current_span().get_span_context()取得当前上下文,并以固定长度的十六进制格式写入现有日志字段;记录发生在有效Span作用域内,才有可用于查询的标识。
应用也可以使用OpenTelemetry的日志埋点组件向LogRecord注入关联字段,但仍须检查现有formatter是否实际输出这些字段。尤其是应用已先配置日志格式时,字段存在于记录对象中,不代表终端或日志平台一定能看见。用同一请求的trace ID核对日志和Jaeger链路,比只检查HTTP响应更可靠。
日志关联与OTLP日志导出是两项设置。本地将OTEL_LOGS_EXPORTER设为none时,仍可在终端或原有日志管道检查关联字段;若要把日志送往生产后端,还需单独配置接收、导出和保留规则。被采样丢弃的链路也可能留下错误日志,因此不能把trace ID的存在误当作链路一定可查。
迁移生产时核对导出器和敏感信息
FastAPI的OpenTelemetry配置说明指出,应用可使用已配置的provider;启用FASTAPI_OTEL_AUTO_CONFIGURE后,会按环境配置额外导出器,若同一目的地已有导出器,遥测可能重复发送。因此应核对内置遥测、命令行埋点和应用代码各自承担的工作,避免重复配置请求Span或导出器。
将本地OTLP地址换成应用实际可达的Collector或追踪后端地址。容器中的localhost通常指该容器自身;接收端使用gRPC还是HTTP/protobuf,也决定协议和端点写法。按接收端要求配置TLS与认证、核对数据保留期限,并用一条可辨认的业务请求确认链路已到达生产后端。
未处理异常的日志可能包含异常类型、消息和堆栈;即使相应链路未被采样,错误日志仍可能产生。应在日志处理环节过滤或脱敏;业务不需要这类日志时,可在相应telemetry设置中关闭。自行编写的异常日志也须单独审查,不能依赖Trace采样保护其中的数据。
敏感字段检查应覆盖请求头、查询参数、异常消息、堆栈和手工Span属性。确需把HTTP头部写入Span时,只采集允许的字段,并用OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS处理令牌或会话类头部;该设置只作用于采集到Span的头部,不会自动清理业务日志、请求体或开发者另加的属性。完成接入后,应能查到所需的调用边界,同时确认探针请求与敏感值没有进入遥测数据。
相关阅读:
相关文章
订阅我们的新闻通讯
将最新 Web3、AI 和加密货币新闻直接发送到您的邮箱。




