Propagate traces over HTTP and add Redis spans
setup_telemetry now instruments httpx and redis process-wide. Both patch the client classes, so clients created at import time (gateway's _proxy_client, common.redis_client) are covered too. httpx CLIENT spans inject traceparent, so the downstream FastAPI SERVER spans join the caller's trace. gateway and fraud get setup_telemetry, the FastAPI span, and the OTLP auth header. All seven services now export traces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ec6ddb6a26
commit
14938ab36b
@@ -3,6 +3,8 @@ from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|||||||
from opentelemetry.sdk.trace import TracerProvider
|
from opentelemetry.sdk.trace import TracerProvider
|
||||||
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
||||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
||||||
|
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
|
||||||
|
from opentelemetry.instrumentation.redis import RedisInstrumentor
|
||||||
|
|
||||||
|
|
||||||
def setup_telemetry(service_name: str):
|
def setup_telemetry(service_name: str):
|
||||||
@@ -11,3 +13,8 @@ def setup_telemetry(service_name: str):
|
|||||||
provider = TracerProvider(resource=resource)
|
provider = TracerProvider(resource=resource)
|
||||||
provider.add_span_processor(processor)
|
provider.add_span_processor(processor)
|
||||||
trace.set_tracer_provider(provider)
|
trace.set_tracer_provider(provider)
|
||||||
|
|
||||||
|
# Process-wide patches on the client classes, so they also cover clients
|
||||||
|
# created at import time (gateway's _proxy_client, common.redis_client).
|
||||||
|
HTTPXClientInstrumentor().instrument()
|
||||||
|
RedisInstrumentor().instrument()
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
<<: *app-env
|
<<: *app-env
|
||||||
SERVICE_NAME: gateway
|
SERVICE_NAME: gateway
|
||||||
|
env_file:
|
||||||
|
- .env.observability
|
||||||
command: uvicorn services.gateway.app:app --host 0.0.0.0 --port 8000 --reload --no-access-log
|
command: uvicorn services.gateway.app:app --host 0.0.0.0 --port 8000 --reload --no-access-log
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
@@ -128,6 +130,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
<<: *app-env
|
<<: *app-env
|
||||||
SERVICE_NAME: fraud
|
SERVICE_NAME: fraud
|
||||||
|
env_file:
|
||||||
|
- .env.observability
|
||||||
command: uvicorn services.fraud.app:app --host 0.0.0.0 --port 8002 --reload --no-access-log
|
command: uvicorn services.fraud.app:app --host 0.0.0.0 --port 8002 --reload --no-access-log
|
||||||
ports:
|
ports:
|
||||||
- "8002:8002"
|
- "8002:8002"
|
||||||
|
|||||||
@@ -2,19 +2,28 @@ import httpx
|
|||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
||||||
|
|
||||||
from common.http import downstream_client
|
from common.http import downstream_client
|
||||||
from common.logging_config import configure_logging
|
from common.logging_config import configure_logging
|
||||||
from common.redis_client import redis_client
|
from common.redis_client import redis_client
|
||||||
from common.settings import settings
|
from common.settings import settings
|
||||||
|
from common.telemetry import setup_telemetry
|
||||||
|
|
||||||
from . import chaos
|
from . import chaos
|
||||||
from .scoring import score
|
from .scoring import score
|
||||||
|
|
||||||
SERVICE_NAME = "fraud"
|
SERVICE_NAME = "fraud"
|
||||||
logger = configure_logging(SERVICE_NAME)
|
logger = configure_logging(SERVICE_NAME)
|
||||||
|
setup_telemetry(service_name=SERVICE_NAME)
|
||||||
app = FastAPI(title=SERVICE_NAME)
|
app = FastAPI(title=SERVICE_NAME)
|
||||||
|
|
||||||
|
FastAPIInstrumentor.instrument_app(
|
||||||
|
app,
|
||||||
|
excluded_urls="/healthz",
|
||||||
|
exclude_spans=["receive", "send"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ScoreRequest(BaseModel):
|
class ScoreRequest(BaseModel):
|
||||||
account_id: str
|
account_id: str
|
||||||
|
|||||||
@@ -7,18 +7,27 @@ from fastapi import FastAPI, Request
|
|||||||
from fastapi.responses import FileResponse, JSONResponse
|
from fastapi.responses import FileResponse, JSONResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from pydantic import BaseModel, field_validator
|
from pydantic import BaseModel, field_validator
|
||||||
|
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
||||||
|
|
||||||
from common.chaos_flags import ALL_FLAGS, get_flags, set_flag, set_profile
|
from common.chaos_flags import ALL_FLAGS, get_flags, set_flag, set_profile
|
||||||
from common.logging_config import configure_logging
|
from common.logging_config import configure_logging
|
||||||
from common.settings import settings
|
from common.settings import settings
|
||||||
|
from common.telemetry import setup_telemetry
|
||||||
|
|
||||||
from . import orchestrator
|
from . import orchestrator
|
||||||
from .orchestrator import UpstreamFailure
|
from .orchestrator import UpstreamFailure
|
||||||
|
|
||||||
SERVICE_NAME = "gateway"
|
SERVICE_NAME = "gateway"
|
||||||
logger = configure_logging(SERVICE_NAME)
|
logger = configure_logging(SERVICE_NAME)
|
||||||
|
setup_telemetry(service_name=SERVICE_NAME)
|
||||||
app = FastAPI(title=SERVICE_NAME)
|
app = FastAPI(title=SERVICE_NAME)
|
||||||
|
|
||||||
|
FastAPIInstrumentor.instrument_app(
|
||||||
|
app,
|
||||||
|
excluded_urls="/healthz",
|
||||||
|
exclude_spans=["receive", "send"],
|
||||||
|
)
|
||||||
|
|
||||||
STATIC_DIR = Path(__file__).parent / "static"
|
STATIC_DIR = Path(__file__).parent / "static"
|
||||||
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user