otel-fastapi-style

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OTel FastAPI Style

OTel FastAPI 实践风格

Use native FastAPI instrumentation. Do not replace request handling with manual middleware just to create spans.
python
from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

def init_observability(app: FastAPI) -> bool:
    ...
    FastAPIInstrumentor.instrument_app(app)
    return True
Keep
FastAPIInstrumentor.instrument_app(app)
with the rest of the observability setup so the bootstrap is easy to reason about. If OTLP credentials are absent, it is still okay to instrument the app with no-op providers, but keep that choice explicit in
init_observability(app)
.
使用原生FastAPI工具库进行埋点。不要为了创建追踪跨度(span)而用手动中间件替换请求处理逻辑。
python
from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

def init_observability(app: FastAPI) -> bool:
    ...
    FastAPIInstrumentor.instrument_app(app)
    return True
FastAPIInstrumentor.instrument_app(app)
与其他可观测性配置放在一起,以便于理解启动流程。如果缺少OTLP凭证,使用空操作(no-op)提供者进行埋点也是可行的,但需在
init_observability(app)
中明确该选择。

Entrypoint

入口点

Initialize before serving user traffic.
python
app = FastAPI(title="Mugline API")
init_observability(app)
在处理用户流量之前完成初始化。
python
app = FastAPI(title="Mugline API")
init_observability(app)

Bounded Work

限定范围的工作

Use module-scope OTel objects and decorators for helpers that auto-instrumented HTTP spans cannot see.
python
tracer = trace.get_tracer("mugline.api")
meter = metrics.get_meter("mugline.api")

@tracer.start_as_current_span("mug.recommend")
async def recommend_mug(*, tenant_id: str, preference: str) -> dict[str, str]:
    span = trace.get_current_span()
    span.set_attribute("tenant.id", tenant_id)
    ...
对于自动埋点的HTTP跨度无法捕获的辅助函数,使用模块级别的OTel对象和装饰器。
python
tracer = trace.get_tracer("mugline.api")
meter = metrics.get_meter("mugline.api")

@tracer.start_as_current_span("mug.recommend")
async def recommend_mug(*, tenant_id: str, preference: str) -> dict[str, str]:
    span = trace.get_current_span()
    span.set_attribute("tenant.id", tenant_id)
    ...

Logs

日志

For OTLP-forwarded stdlib logs, configure all of these:
  • LoggerProvider
  • set_logger_provider(logger_provider)
  • OTLPLogExporter
  • LoggingHandler
  • LoggingInstrumentor().instrument(...)
对于通过OTLP转发的标准库日志,需配置以下所有内容:
  • LoggerProvider
  • set_logger_provider(logger_provider)
  • OTLPLogExporter
  • LoggingHandler
  • LoggingInstrumentor().instrument(...)

LLM Calls

LLM调用

LLM routes need token coverage:
  • llm.tokens.input
  • llm.tokens.output
Tag explicit token counters with tenant, provider, model, use case, call site, and outcome only when provider instrumentation cannot capture token usage. Do not add app-side LLM cost metrics or pricing tables; Superlog estimates cost centrally from provider/model/token data.
LLM路由需要统计令牌使用情况:
  • llm.tokens.input
  • llm.tokens.output
仅当提供者工具库无法捕获令牌使用情况时,才为显式令牌计数器添加租户、提供者、模型、用例、调用位置和结果标签。不要在应用端添加LLM成本指标或定价表;Superlog会基于提供者/模型/令牌数据集中估算成本。