[{"data":1,"prerenderedAt":1006},["ShallowReactive",2],{"nav":3,"page-\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002F":310,"surround-\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002F":1004},[4,96,212],{"title":5,"path":6,"stem":7,"children":8},"Advanced Pydantic Validation Serialization","\u002Fadvanced-pydantic-validation-serialization","advanced-pydantic-validation-serialization",[9,12,30,42,54,66,90],{"title":10,"path":6,"stem":11},"Advanced Pydantic Validation and Serialization","advanced-pydantic-validation-serialization\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Custom Validators and Field Constraints in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Findex",[17,18,24],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Creating Reusable Custom Validators in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"Pydantic v2 Async Custom Validator: What to Do Instead","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator\u002Findex",[29],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"JSON Schema Customization in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Findex",[35,36],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Customizing OpenAPI Schema Generation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi\u002Findex",[41],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"Nested Model Serialization in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Findex",[47,48],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Handling Deeply Nested JSON Models Efficiently","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002Findex",[53],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Performance Optimization for Pydantic Models in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Findex",[59,60],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Pydantic Model Serialization Performance in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Pydantic V2 Migration Guide for FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Findex",[71,72,78,84],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Migrate @validator to @field_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator\u002Findex",[77],{"title":73,"path":74,"stem":75},{"title":79,"path":80,"stem":81,"children":82},"Migrating from Pydantic v1 to v2 Without Breaking APIs","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex",[83],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87,"children":88},"model_config vs class Config in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config\u002Findex",[89],{"title":85,"path":86,"stem":87},{"title":91,"path":92,"stem":93,"children":94},"Type Hinting and IDE Integration in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Findex",[95],{"title":91,"path":92,"stem":93},{"title":97,"path":98,"stem":99,"children":100},"Async Background Tasks Observability","\u002Fasync-background-tasks-observability","async-background-tasks-observability",[101,104,122,140,158,176,194],{"title":102,"path":98,"stem":103},"Async, Background Tasks, and Observability in FastAPI","async-background-tasks-observability\u002Findex",{"title":105,"path":106,"stem":107,"children":108},"Async Correctness and Concurrency in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Findex",[109,110,116],{"title":105,"path":106,"stem":107},{"title":111,"path":112,"stem":113,"children":114},"FastAPI async def vs def: Performance and When to Use Each","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002Findex",[115],{"title":111,"path":112,"stem":113},{"title":117,"path":118,"stem":119,"children":120},"Fixing Blocking Calls in Async FastAPI Routes","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes\u002Findex",[121],{"title":117,"path":118,"stem":119},{"title":123,"path":124,"stem":125,"children":126},"Async Database Sessions in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions","async-background-tasks-observability\u002Fasync-database-sessions\u002Findex",[127,128,134],{"title":123,"path":124,"stem":125},{"title":129,"path":130,"stem":131,"children":132},"Async SQLAlchemy Session per Request in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request","async-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request\u002Findex",[133],{"title":129,"path":130,"stem":131},{"title":135,"path":136,"stem":137,"children":138},"Fixing asyncpg Connection Pool Exhaustion in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion","async-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion\u002Findex",[139],{"title":135,"path":136,"stem":137},{"title":141,"path":142,"stem":143,"children":144},"Background Task Processing in FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing","async-background-tasks-observability\u002Fbackground-task-processing\u002Findex",[145,146,152],{"title":141,"path":142,"stem":143},{"title":147,"path":148,"stem":149,"children":150},"FastAPI BackgroundTasks vs Celery vs ARQ","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq","async-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq\u002Findex",[151],{"title":147,"path":148,"stem":149},{"title":153,"path":154,"stem":155,"children":156},"Running ARQ Workers with FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi","async-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi\u002Findex",[157],{"title":153,"path":154,"stem":155},{"title":159,"path":160,"stem":161,"children":162},"Caching Strategies in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies","async-background-tasks-observability\u002Fcaching-strategies\u002Findex",[163,164,170],{"title":159,"path":160,"stem":161},{"title":165,"path":166,"stem":167,"children":168},"Cache Invalidation Patterns in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi\u002Findex",[169],{"title":165,"path":166,"stem":167},{"title":171,"path":172,"stem":173,"children":174},"Redis Response Caching in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi\u002Findex",[175],{"title":171,"path":172,"stem":173},{"title":177,"path":178,"stem":179,"children":180},"Observability and Tracing in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing","async-background-tasks-observability\u002Fobservability-and-tracing\u002Findex",[181,182,188],{"title":177,"path":178,"stem":179},{"title":183,"path":184,"stem":185,"children":186},"Instrumenting FastAPI with OpenTelemetry","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry","async-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002Findex",[187],{"title":183,"path":184,"stem":185},{"title":189,"path":190,"stem":191,"children":192},"Structured JSON Logging with Request IDs in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002Findex",[193],{"title":189,"path":190,"stem":191},{"title":195,"path":196,"stem":197,"children":198},"Rate Limiting and Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Findex",[199,200,206],{"title":195,"path":196,"stem":197},{"title":201,"path":202,"stem":203,"children":204},"FastAPI Rate Limiting with Redis and SlowAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi","async-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi\u002Findex",[205],{"title":201,"path":202,"stem":203},{"title":207,"path":208,"stem":209,"children":210},"Per-User Token Bucket Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling\u002Findex",[211],{"title":207,"path":208,"stem":209},{"title":213,"path":214,"stem":215,"children":216},"Core Architecture Routing Patterns","\u002Fcore-architecture-routing-patterns","core-architecture-routing-patterns",[217,220,232,250,268,280,292],{"title":218,"path":214,"stem":219},"FastAPI Core Architecture and Routing Patterns","core-architecture-routing-patterns\u002Findex",{"title":221,"path":222,"stem":223,"children":224},"Application Factory Patterns in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Findex",[225,226],{"title":221,"path":222,"stem":223},{"title":227,"path":228,"stem":229,"children":230},"FastAPI App Factory Pattern for Testing and Deployment","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002Findex",[231],{"title":227,"path":228,"stem":229},{"title":233,"path":234,"stem":235,"children":236},"Configuration Management in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management","core-architecture-routing-patterns\u002Fconfiguration-management\u002Findex",[237,238,244],{"title":233,"path":234,"stem":235},{"title":239,"path":240,"stem":241,"children":242},"Managing Environment Variables with Pydantic Settings","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002Findex",[243],{"title":239,"path":240,"stem":241},{"title":245,"path":246,"stem":247,"children":248},"Pydantic Settings vs Dynaconf vs python-decouple","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple\u002Findex",[249],{"title":245,"path":246,"stem":247},{"title":251,"path":252,"stem":253,"children":254},"Dependency Injection Strategies in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Findex",[255,256,262],{"title":251,"path":252,"stem":253},{"title":257,"path":258,"stem":259,"children":260},"Best Practices for FastAPI Dependency Injection","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002Findex",[261],{"title":257,"path":258,"stem":259},{"title":263,"path":264,"stem":265,"children":266},"Fixing FastAPI Dependency Injection Circular Imports","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix\u002Findex",[267],{"title":263,"path":264,"stem":265},{"title":269,"path":270,"stem":271,"children":272},"Error Handling and Global Exceptions in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Findex",[273,274],{"title":269,"path":270,"stem":271},{"title":275,"path":276,"stem":277,"children":278},"Global Exception Handlers for Consistent API Responses","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex",[279],{"title":275,"path":276,"stem":277},{"title":281,"path":282,"stem":283,"children":284},"Middleware Implementation in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Findex",[285,286],{"title":281,"path":282,"stem":283},{"title":287,"path":288,"stem":289,"children":290},"Implementing Custom Middleware for Request Tracing","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002Findex",[291],{"title":287,"path":288,"stem":289},{"title":293,"path":294,"stem":295,"children":296},"Modular Router Organization in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Findex",[297,298,304],{"title":293,"path":294,"stem":295},{"title":299,"path":300,"stem":301,"children":302},"APIRouter Prefix vs Sub-Application Mounting in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting\u002Findex",[303],{"title":299,"path":300,"stem":301},{"title":305,"path":306,"stem":307,"children":308},"How to Structure Large FastAPI Projects for Scale","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale\u002Findex",[309],{"title":305,"path":306,"stem":307},{"id":311,"title":183,"body":312,"description":957,"extension":958,"meta":959,"navigation":487,"path":184,"seo":1002,"stem":185,"__hash__":1003},"content\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002Findex.md",{"type":313,"value":314,"toc":944},"minimark",[315,319,326,349,363,368,371,375,386,390,395,566,570,637,641,741,745,788,792,812,816,819,914,918,940],[316,317,183],"h1",{"id":318},"instrumenting-fastapi-with-opentelemetry",[320,321,322],"p",{},[323,324,325],"strong",{},"Key takeaways:",[327,328,329,333,336,343,346],"ul",{},[330,331,332],"li",{},"A tracer provider with a service-name resource and a batch processor is the foundation.",[330,334,335],{},"An OTLP exporter sends spans to a collector, which forwards to your backend.",[330,337,338,342],{},[339,340,341],"code",{},"FastAPIInstrumentor"," auto-creates a span per request.",[330,344,345],{},"Database and HTTP client instrumentations add child spans automatically.",[330,347,348],{},"Manual spans time the business operations you care about.",[320,350,351,352,357,358,362],{},"This guide implements the tracing half of ",[353,354,356],"a",{"href":355},"\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002F","Observability and Tracing",". Pair it with the correlation ID from ",[353,359,361],{"href":360},"\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002F","request-tracing middleware",".",[364,365,367],"h2",{"id":366},"the-problem-this-solves","The Problem This Solves",[320,369,370],{},"Across services, a single slow request is invisible in logs alone — you cannot see which downstream call cost the time. Distributed tracing stitches the request's path into one timeline, so a latency spike points directly at the responsible span.",[364,372,374],{"id":373},"prerequisites","Prerequisites",[327,376,377,383],{},[330,378,379,382],{},[339,380,381],{},"opentelemetry-sdk",", the FastAPI instrumentation, and an OTLP exporter installed.",[330,384,385],{},"An OpenTelemetry collector (or a backend that accepts OTLP) reachable from the app.",[364,387,389],{"id":388},"step-by-step-implementation","Step-by-Step Implementation",[391,392,394],"h3",{"id":393},"_1-configure-the-tracer-provider-and-exporter","1. Configure the tracer provider and exporter",[396,397,402],"pre",{"className":398,"code":399,"language":400,"meta":401,"style":401},"language-python shiki shiki-themes github-light","# app\u002Ftelemetry.py\nfrom opentelemetry import trace\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\nfrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter\n\n\ndef configure_tracing() -> None:\n    provider = TracerProvider(resource=Resource.create({\"service.name\": \"orders-api\"}))\n    # Batch processor exports in the background — no per-request latency.\n    provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))\n    trace.set_tracer_provider(provider)\n","python","",[339,403,404,413,430,443,456,469,482,489,494,514,548,554,560],{"__ignoreMap":401},[405,406,409],"span",{"class":407,"line":408},"line",1,[405,410,412],{"class":411},"sAwPA","# app\u002Ftelemetry.py\n",[405,414,416,420,424,427],{"class":407,"line":415},2,[405,417,419],{"class":418},"sD7c4","from",[405,421,423],{"class":422},"sgsFI"," opentelemetry ",[405,425,426],{"class":418},"import",[405,428,429],{"class":422}," trace\n",[405,431,433,435,438,440],{"class":407,"line":432},3,[405,434,419],{"class":418},[405,436,437],{"class":422}," opentelemetry.sdk.resources ",[405,439,426],{"class":418},[405,441,442],{"class":422}," Resource\n",[405,444,446,448,451,453],{"class":407,"line":445},4,[405,447,419],{"class":418},[405,449,450],{"class":422}," opentelemetry.sdk.trace ",[405,452,426],{"class":418},[405,454,455],{"class":422}," TracerProvider\n",[405,457,459,461,464,466],{"class":407,"line":458},5,[405,460,419],{"class":418},[405,462,463],{"class":422}," opentelemetry.sdk.trace.export ",[405,465,426],{"class":418},[405,467,468],{"class":422}," BatchSpanProcessor\n",[405,470,472,474,477,479],{"class":407,"line":471},6,[405,473,419],{"class":418},[405,475,476],{"class":422}," opentelemetry.exporter.otlp.proto.grpc.trace_exporter ",[405,478,426],{"class":418},[405,480,481],{"class":422}," OTLPSpanExporter\n",[405,483,485],{"class":407,"line":484},7,[405,486,488],{"emptyLinePlaceholder":487},true,"\n",[405,490,492],{"class":407,"line":491},8,[405,493,488],{"emptyLinePlaceholder":487},[405,495,497,500,504,507,511],{"class":407,"line":496},9,[405,498,499],{"class":418},"def",[405,501,503],{"class":502},"s7eDp"," configure_tracing",[405,505,506],{"class":422},"() -> ",[405,508,510],{"class":509},"sYu0t","None",[405,512,513],{"class":422},":\n",[405,515,517,520,523,526,530,532,535,539,542,545],{"class":407,"line":516},10,[405,518,519],{"class":422},"    provider ",[405,521,522],{"class":418},"=",[405,524,525],{"class":422}," TracerProvider(",[405,527,529],{"class":528},"sqxcx","resource",[405,531,522],{"class":418},[405,533,534],{"class":422},"Resource.create({",[405,536,538],{"class":537},"sYBdl","\"service.name\"",[405,540,541],{"class":422},": ",[405,543,544],{"class":537},"\"orders-api\"",[405,546,547],{"class":422},"}))\n",[405,549,551],{"class":407,"line":550},11,[405,552,553],{"class":411},"    # Batch processor exports in the background — no per-request latency.\n",[405,555,557],{"class":407,"line":556},12,[405,558,559],{"class":422},"    provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))\n",[405,561,563],{"class":407,"line":562},13,[405,564,565],{"class":422},"    trace.set_tracer_provider(provider)\n",[391,567,569],{"id":568},"_2-auto-instrument-the-app-and-clients","2. Auto-instrument the app and clients",[396,571,573],{"className":398,"code":572,"language":400,"meta":401,"style":401},"from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor\nfrom opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor\n\n\ndef instrument(app) -> None:\n    FastAPIInstrumentor.instrument_app(app)   # One span per request.\n    HTTPXClientInstrumentor().instrument()    # Child spans for outbound calls.\n",[339,574,575,587,599,603,607,621,629],{"__ignoreMap":401},[405,576,577,579,582,584],{"class":407,"line":408},[405,578,419],{"class":418},[405,580,581],{"class":422}," opentelemetry.instrumentation.fastapi ",[405,583,426],{"class":418},[405,585,586],{"class":422}," FastAPIInstrumentor\n",[405,588,589,591,594,596],{"class":407,"line":415},[405,590,419],{"class":418},[405,592,593],{"class":422}," opentelemetry.instrumentation.httpx ",[405,595,426],{"class":418},[405,597,598],{"class":422}," HTTPXClientInstrumentor\n",[405,600,601],{"class":407,"line":432},[405,602,488],{"emptyLinePlaceholder":487},[405,604,605],{"class":407,"line":445},[405,606,488],{"emptyLinePlaceholder":487},[405,608,609,611,614,617,619],{"class":407,"line":458},[405,610,499],{"class":418},[405,612,613],{"class":502}," instrument",[405,615,616],{"class":422},"(app) -> ",[405,618,510],{"class":509},[405,620,513],{"class":422},[405,622,623,626],{"class":407,"line":471},[405,624,625],{"class":422},"    FastAPIInstrumentor.instrument_app(app)   ",[405,627,628],{"class":411},"# One span per request.\n",[405,630,631,634],{"class":407,"line":484},[405,632,633],{"class":422},"    HTTPXClientInstrumentor().instrument()    ",[405,635,636],{"class":411},"# Child spans for outbound calls.\n",[391,638,640],{"id":639},"_3-add-manual-spans-for-business-operations","3. Add manual spans for business operations",[396,642,644],{"className":398,"code":643,"language":400,"meta":401,"style":401},"from opentelemetry import trace\n\ntracer = trace.get_tracer(\"orders\")\n\n\nasync def place_order(order) -> None:\n    with tracer.start_as_current_span(\"place_order\", attributes={\"order.id\": order.id}):\n        await persist(order)                  # Timed as a child of the request span.\n",[339,645,646,656,660,676,680,684,702,730],{"__ignoreMap":401},[405,647,648,650,652,654],{"class":407,"line":408},[405,649,419],{"class":418},[405,651,423],{"class":422},[405,653,426],{"class":418},[405,655,429],{"class":422},[405,657,658],{"class":407,"line":415},[405,659,488],{"emptyLinePlaceholder":487},[405,661,662,665,667,670,673],{"class":407,"line":432},[405,663,664],{"class":422},"tracer ",[405,666,522],{"class":418},[405,668,669],{"class":422}," trace.get_tracer(",[405,671,672],{"class":537},"\"orders\"",[405,674,675],{"class":422},")\n",[405,677,678],{"class":407,"line":445},[405,679,488],{"emptyLinePlaceholder":487},[405,681,682],{"class":407,"line":458},[405,683,488],{"emptyLinePlaceholder":487},[405,685,686,689,692,695,698,700],{"class":407,"line":471},[405,687,688],{"class":418},"async",[405,690,691],{"class":418}," def",[405,693,694],{"class":502}," place_order",[405,696,697],{"class":422},"(order) -> ",[405,699,510],{"class":509},[405,701,513],{"class":422},[405,703,704,707,710,713,716,719,721,724,727],{"class":407,"line":484},[405,705,706],{"class":418},"    with",[405,708,709],{"class":422}," tracer.start_as_current_span(",[405,711,712],{"class":537},"\"place_order\"",[405,714,715],{"class":422},", ",[405,717,718],{"class":528},"attributes",[405,720,522],{"class":418},[405,722,723],{"class":422},"{",[405,725,726],{"class":537},"\"order.id\"",[405,728,729],{"class":422},": order.id}):\n",[405,731,732,735,738],{"class":407,"line":491},[405,733,734],{"class":418},"        await",[405,736,737],{"class":422}," persist(order)                  ",[405,739,740],{"class":411},"# Timed as a child of the request span.\n",[391,742,744],{"id":743},"_4-wire-it-into-the-factory","4. Wire it into the factory",[396,746,748],{"className":398,"code":747,"language":400,"meta":401,"style":401},"def create_app():\n    configure_tracing()\n    app = FastAPI()\n    instrument(app)\n    return app\n",[339,749,750,760,765,775,780],{"__ignoreMap":401},[405,751,752,754,757],{"class":407,"line":408},[405,753,499],{"class":418},[405,755,756],{"class":502}," create_app",[405,758,759],{"class":422},"():\n",[405,761,762],{"class":407,"line":415},[405,763,764],{"class":422},"    configure_tracing()\n",[405,766,767,770,772],{"class":407,"line":432},[405,768,769],{"class":422},"    app ",[405,771,522],{"class":418},[405,773,774],{"class":422}," FastAPI()\n",[405,776,777],{"class":407,"line":445},[405,778,779],{"class":422},"    instrument(app)\n",[405,781,782,785],{"class":407,"line":458},[405,783,784],{"class":418},"    return",[405,786,787],{"class":422}," app\n",[364,789,791],{"id":790},"edge-cases-and-gotchas","Edge Cases and Gotchas",[327,793,794,800,806],{},[330,795,796,799],{},[323,797,798],{},"Context across tasks."," Background jobs start a new context; propagate the trace context explicitly into queued work.",[330,801,802,805],{},[323,803,804],{},"Cardinality."," Avoid high-cardinality span attributes such as raw user input; they explode storage.",[330,807,808,811],{},[323,809,810],{},"Sampling."," Under heavy load, configure a sampler so you record a representative fraction, not every request.",[364,813,815],{"id":814},"verification","Verification",[320,817,818],{},"Use an in-memory span exporter in tests to assert spans are produced:",[396,820,822],{"className":398,"code":821,"language":400,"meta":401,"style":401},"from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter\n\n\ndef test_request_creates_span(client, span_exporter: InMemorySpanExporter):\n    client.get(\"\u002Forders\u002F1\")\n    names = [s.name for s in span_exporter.get_finished_spans()]\n    assert any(\"place_order\" in n for n in names)\n",[339,823,824,836,840,844,854,864,886],{"__ignoreMap":401},[405,825,826,828,831,833],{"class":407,"line":408},[405,827,419],{"class":418},[405,829,830],{"class":422}," opentelemetry.sdk.trace.export.in_memory_span_exporter ",[405,832,426],{"class":418},[405,834,835],{"class":422}," InMemorySpanExporter\n",[405,837,838],{"class":407,"line":415},[405,839,488],{"emptyLinePlaceholder":487},[405,841,842],{"class":407,"line":432},[405,843,488],{"emptyLinePlaceholder":487},[405,845,846,848,851],{"class":407,"line":445},[405,847,499],{"class":418},[405,849,850],{"class":502}," test_request_creates_span",[405,852,853],{"class":422},"(client, span_exporter: InMemorySpanExporter):\n",[405,855,856,859,862],{"class":407,"line":458},[405,857,858],{"class":422},"    client.get(",[405,860,861],{"class":537},"\"\u002Forders\u002F1\"",[405,863,675],{"class":422},[405,865,866,869,871,874,877,880,883],{"class":407,"line":471},[405,867,868],{"class":422},"    names ",[405,870,522],{"class":418},[405,872,873],{"class":422}," [s.name ",[405,875,876],{"class":418},"for",[405,878,879],{"class":422}," s ",[405,881,882],{"class":418},"in",[405,884,885],{"class":422}," span_exporter.get_finished_spans()]\n",[405,887,888,891,894,897,899,902,905,907,909,911],{"class":407,"line":484},[405,889,890],{"class":418},"    assert",[405,892,893],{"class":509}," any",[405,895,896],{"class":422},"(",[405,898,712],{"class":537},[405,900,901],{"class":418}," in",[405,903,904],{"class":422}," n ",[405,906,876],{"class":418},[405,908,904],{"class":422},[405,910,882],{"class":418},[405,912,913],{"class":422}," names)\n",[364,915,917],{"id":916},"related-reading","Related Reading",[327,919,920,928],{},[330,921,922,925,926,362],{},[323,923,924],{},"Up to the topic:"," ",[353,927,356],{"href":355},[330,929,930,925,933,937,938,362],{},[323,931,932],{},"Related guides:",[353,934,936],{"href":935},"\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002F","Structured JSON Logging with Request IDs"," and ",[353,939,287],{"href":360},[941,942,943],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":401,"searchDepth":415,"depth":415,"links":945},[946,947,948,954,955,956],{"id":366,"depth":415,"text":367},{"id":373,"depth":415,"text":374},{"id":388,"depth":415,"text":389,"children":949},[950,951,952,953],{"id":393,"depth":432,"text":394},{"id":568,"depth":432,"text":569},{"id":639,"depth":432,"text":640},{"id":743,"depth":432,"text":744},{"id":790,"depth":415,"text":791},{"id":814,"depth":415,"text":815},{"id":916,"depth":415,"text":917},"Add OpenTelemetry tracing to FastAPI: auto-instrument requests, database, and HTTP clients, add manual spans, export to a collector via OTLP, and correlate traces with logs.","md",{"slug":318,"type":960,"breadcrumb":961,"datePublished":972,"dateModified":973,"howto":974,"faq":992},"long_tail",[962,965,968,970],{"label":963,"path":964},"Home","\u002F",{"label":966,"path":967},"Async, Background Tasks & Observability","\u002Fasync-background-tasks-observability\u002F",{"label":969,"path":355},"Observability & Tracing",{"label":183,"path":971},"\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002F","2026-02-21","2026-06-18",{"name":975,"steps":976},"Instrument FastAPI with OpenTelemetry",[977,980,983,986,989],{"name":978,"text":979},"Configure a tracer provider","Set up a TracerProvider with a service name resource and a batch span processor.",{"name":981,"text":982},"Add an OTLP exporter","Export spans to a collector over OTLP so they reach your tracing backend.",{"name":984,"text":985},"Auto-instrument FastAPI","Call FastAPIInstrumentor.instrument_app to create spans for every request.",{"name":987,"text":988},"Instrument the database and HTTP clients","Add the SQLAlchemy and httpx instrumentations so those calls become child spans.",{"name":990,"text":991},"Add manual spans","Wrap key business operations in start_as_current_span to time them.",[993,996,999],{"q":994,"a":995},"Does OpenTelemetry auto-instrumentation cover database and HTTP calls?","Yes, with the matching instrumentation packages. The FastAPI instrumentation creates a span per request, and the SQLAlchemy and httpx instrumentations add child spans for queries and outbound calls. Together they produce a trace that shows where a request spent its time without manual span code.",{"q":997,"a":998},"How do I export traces to my backend?","Configure an OTLP exporter pointed at an OpenTelemetry collector, and let the collector forward to your backend such as Jaeger, Tempo, or a vendor. Using the collector decouples your app from any specific backend and lets you batch and sample centrally.",{"q":1000,"a":1001},"Will tracing slow down my API?","Negligibly when configured correctly. Use a batch span processor so spans are buffered and exported in the background rather than synchronously per request, and apply sampling under heavy load so only a representative fraction of traces is recorded.",{"title":183,"description":957},"h5_n2B-_YFeddeJ3bLixizz8TYHFvj5cisgqIJ8ay3A",[1005,1005],null,1781809863644]