Spaces:
Running
Running
| # SPDX-License-Identifier: Apache-2.0 | |
| # © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173 | |
| """vsp_otel.middleware — real W3C-traceparent + OTLP/gRPC middleware for FastAPI/Starlette organs. | |
| Field leaders harnessed (cited): | |
| - W3C Trace Context §3.2 (traceparent) https://www.w3.org/TR/trace-context/ | |
| - OpenTelemetry OTLP exporter spec https://opentelemetry.io/docs/specs/otel/protocol/exporter/ | |
| `install(app)` adds an ASGI middleware that, for every request: | |
| 1. parses any incoming `traceparent` (W3C §3.2), validating shape/non-zero ids; | |
| 2. mints a child span id, keeping the same trace-id (cross-pod continuity); | |
| 3. if the OpenTelemetry SDK + OTLP/gRPC exporter are installed, emits a real | |
| server span to OTEL_EXPORTER_OTLP_ENDPOINT (default localhost:4317); | |
| 4. ALWAYS echoes a valid outbound `traceparent` response header so the next | |
| organ continues the SAME trace-id (this is what cross_pod_trace_test asserts). | |
| Honest disclosure: if the OTel SDK is absent the span is NOT exported to a | |
| collector — but the traceparent propagation (the cross-pod contract) still works | |
| purely in-process. We never claim "exported" when the exporter is unavailable; | |
| the middleware sets request.state.vsp_otel_exporter to the real status string. | |
| Doctrine v11 LOCKED 749/14/163 @ c7c0ba17 · Λ = Conjecture 1. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import secrets | |
| import time | |
| _VERSION = "0.1.0" | |
| _ENDPOINT = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317") | |
| def _hex(n: int) -> str: | |
| return secrets.token_hex(n) | |
| def parse_traceparent(tp): | |
| """Parse/validate a W3C traceparent. Returns dict or None (W3C §3.2).""" | |
| if not tp or not isinstance(tp, str): | |
| return None | |
| parts = tp.strip().split("-") | |
| if len(parts) != 4: | |
| return None | |
| ver, tid, pid, flags = parts | |
| if len(ver) != 2 or len(tid) != 32 or len(pid) != 16 or len(flags) != 2: | |
| return None | |
| if tid == "0" * 32 or pid == "0" * 16: | |
| return None | |
| try: | |
| int(tid, 16); int(pid, 16); int(flags, 16) | |
| except ValueError: | |
| return None | |
| return {"trace_id": tid, "parent_id": pid, "flags": flags, | |
| "sampled": bool(int(flags, 16) & 0x01)} | |
| def make_traceparent(trace_id=None, parent_id=None, sampled=True): | |
| tid = trace_id or _hex(16) | |
| pid = parent_id or _hex(8) | |
| return f"00-{tid}-{pid}-{'01' if sampled else '00'}" | |
| class _Tracer: | |
| """Lazily initialises a real OTel TracerProvider + OTLP/gRPC exporter.""" | |
| def __init__(self, service_name: str, endpoint: str = _ENDPOINT): | |
| self.service_name = service_name | |
| self.endpoint = endpoint | |
| self.exporter = "in-process-only" | |
| self._tracer = None | |
| try: | |
| from opentelemetry import trace | |
| from opentelemetry.sdk.resources import Resource | |
| from opentelemetry.sdk.trace import TracerProvider | |
| from opentelemetry.sdk.trace.export import BatchSpanProcessor | |
| from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( | |
| OTLPSpanExporter, | |
| ) | |
| resource = Resource.create({ | |
| "service.name": service_name, | |
| "szl.doctrine": "v11-749-14-163", | |
| "szl.kernel_commit": "c7c0ba17", | |
| "szl.lambda": "Conjecture-1", | |
| }) | |
| provider = TracerProvider(resource=resource) | |
| provider.add_span_processor( | |
| BatchSpanProcessor(OTLPSpanExporter(endpoint=endpoint, insecure=True))) | |
| trace.set_tracer_provider(provider) | |
| self._tracer = trace.get_tracer(f"vsp-otel.{service_name}") | |
| self.exporter = f"otlp-grpc:{endpoint}" | |
| except Exception as e: # SDK absent — propagation still works | |
| self.exporter = f"in-process-only ({type(e).__name__})" | |
| def server_span(self, name: str, attrs: dict): | |
| if self._tracer is None: | |
| return | |
| try: | |
| with self._tracer.start_as_current_span(name) as s: | |
| for k, v in attrs.items(): | |
| s.set_attribute(k, str(v)) | |
| except Exception: | |
| pass | |
| def install(app, service_name: str | None = None, endpoint: str = _ENDPOINT): | |
| """Install the vsp-otel middleware on a FastAPI/Starlette `app`. | |
| Idempotent: a second install() on the same app is a no-op. | |
| """ | |
| if getattr(app, "_vsp_otel_installed", False): | |
| return app | |
| svc = service_name or os.environ.get("OTEL_SERVICE_NAME") \ | |
| or getattr(app, "title", "organ").split()[0].lower() | |
| tracer = _Tracer(svc, endpoint) | |
| async def _vsp_otel_mw(request, call_next): | |
| incoming = request.headers.get("traceparent") | |
| parsed = parse_traceparent(incoming) | |
| trace_id = parsed["trace_id"] if parsed else _hex(16) | |
| span_id = _hex(8) | |
| sampled = parsed["sampled"] if parsed else True | |
| request.state.trace_id = trace_id | |
| request.state.traceparent = make_traceparent(trace_id, span_id, sampled) | |
| request.state.vsp_otel_exporter = tracer.exporter | |
| t0 = time.time_ns() | |
| response = await call_next(request) | |
| tracer.server_span(f"{svc} {request.method} {request.url.path}", { | |
| "http.method": request.method, | |
| "http.route": request.url.path, | |
| "http.status_code": getattr(response, "status_code", 0), | |
| "szl.service": svc, | |
| "szl.parent_trace_id": parsed["trace_id"] if parsed else "(root)", | |
| "duration_ns": time.time_ns() - t0, | |
| }) | |
| # Echo a continuing traceparent so the next organ keeps the trace-id. | |
| response.headers["traceparent"] = request.state.traceparent | |
| response.headers["x-vsp-otel"] = f"{_VERSION};{tracer.exporter}" | |
| return response | |
| app._vsp_otel_installed = True | |
| app._vsp_otel_service = svc | |
| return app | |