From a862efaa478b4846dea35a35b4d182aba65cf5b8 Mon Sep 17 00:00:00 2001 From: yukaty <254470+yukaty@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:54:27 -0600 Subject: [PATCH] Add materials for FastAPI OpenTelemetry tutorial --- fastapi-opentelemetry/README.md | 3 ++ fastapi-opentelemetry/main.py | 54 ++++++++++++++++++++++++++ fastapi-opentelemetry/requirements.txt | 36 +++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 fastapi-opentelemetry/README.md create mode 100644 fastapi-opentelemetry/main.py create mode 100644 fastapi-opentelemetry/requirements.txt diff --git a/fastapi-opentelemetry/README.md b/fastapi-opentelemetry/README.md new file mode 100644 index 0000000000..4fb290aad9 --- /dev/null +++ b/fastapi-opentelemetry/README.md @@ -0,0 +1,3 @@ +# How to Integrate OpenTelemetry With FastAPI App + +This folder contains sample code for the Real Python tutorial [How to Integrate OpenTelemetry With FastAPI App](https://realpython.com/). diff --git a/fastapi-opentelemetry/main.py b/fastapi-opentelemetry/main.py new file mode 100644 index 0000000000..a7b08a0aff --- /dev/null +++ b/fastapi-opentelemetry/main.py @@ -0,0 +1,54 @@ +import logging + +from opentelemetry import trace +from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor + +from fastapi import FastAPI + +app = FastAPI() +FastAPIInstrumentor.instrument_app(app) + +tracer = trace.get_tracer(__name__) + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +def simulate_db_query(user_id: int): + with tracer.start_as_current_span("db_query") as span: + span.set_attribute("db.system", "postgresql") + span.set_attribute("user.id", user_id) + + trace_id = format(span.get_span_context().trace_id, "032x") + span_id = format(span.get_span_context().span_id, "016x") + + if user_id == 999: + span.record_exception(Exception("Database connection lost!")) + span.set_status(trace.status.Status(trace.status.StatusCode.ERROR)) + logger.error( + "Database connection lost! " + f"trace_id={trace_id}, span_id={span_id}" + ) + raise ValueError("DB Error") + + logger.info( + f"Executing DB query for user {user_id}. " + f"trace_id={trace_id}, span_id={span_id}" + ) + return {"name": "Demo User", "role": "admin"} + + +@app.get("/users/{user_id}") +def get_user(user_id: int): + logger.info(f"Received request for user {user_id}") + + try: + data = simulate_db_query(user_id) + return {"status": "success", "data": data} + except ValueError: + return {"status": "error", "message": "Failed to fetch user"} + + +@app.get("/") +def read_root(): + return {"message": "Hello, OpenTelemetry!"} diff --git a/fastapi-opentelemetry/requirements.txt b/fastapi-opentelemetry/requirements.txt new file mode 100644 index 0000000000..0a9c0b1045 --- /dev/null +++ b/fastapi-opentelemetry/requirements.txt @@ -0,0 +1,36 @@ +annotated-doc==0.0.4 +annotated-types==0.7.0 +anyio==4.14.0 +asgiref==3.11.1 +certifi==2026.6.17 +charset-normalizer==3.4.7 +click==8.4.1 +fastapi==0.138.0 +googleapis-common-protos==1.75.0 +grpcio==1.81.1 +h11==0.16.0 +idna==3.18 +opentelemetry-api==1.42.1 +opentelemetry-distro==0.63b1 +opentelemetry-exporter-otlp==1.42.1 +opentelemetry-exporter-otlp-proto-common==1.42.1 +opentelemetry-exporter-otlp-proto-grpc==1.42.1 +opentelemetry-exporter-otlp-proto-http==1.42.1 +opentelemetry-instrumentation==0.63b1 +opentelemetry-instrumentation-asgi==0.63b1 +opentelemetry-instrumentation-fastapi==0.63b1 +opentelemetry-proto==1.42.1 +opentelemetry-sdk==1.42.1 +opentelemetry-semantic-conventions==0.63b1 +opentelemetry-util-http==0.63b1 +packaging==26.2 +protobuf==6.33.6 +pydantic==2.13.4 +pydantic_core==2.46.4 +requests==2.34.2 +starlette==1.3.1 +typing-inspection==0.4.2 +typing_extensions==4.15.0 +urllib3==2.7.0 +uvicorn==0.49.0 +wrapt==2.2.2