-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtelemetry.py
More file actions
107 lines (83 loc) · 3.41 KB
/
Copy pathtelemetry.py
File metadata and controls
107 lines (83 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
from collections.abc import Awaitable, Callable
from contextlib import AbstractContextManager
from enum import StrEnum
from typing import Any
from opentelemetry import context, propagate, trace
from opentelemetry.propagators.composite import CompositePropagator
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response
from .config import Settings
from .identity import build_credential
tracer = trace.get_tracer(__name__)
class LoopStage(StrEnum):
CONTROL_PLANE = "control_plane"
WORKER = "worker"
TOOL = "tool"
VERIFIER = "verifier"
FOUNDRY = "foundry"
def start_loop_span(
stage: LoopStage,
correlation_id: str,
*,
goal_id: str | None = None,
work_item_id: str | None = None,
) -> AbstractContextManager[Any]:
attributes = {
"cas.stage": stage.value,
"cas.correlation_id": correlation_id,
}
if goal_id is not None:
attributes["cas.goal_id"] = goal_id
if work_item_id is not None:
attributes["cas.work_item_id"] = work_item_id
return tracer.start_as_current_span(f"cas.loop.{stage.value}", attributes=attributes)
# ---------------------------------------------------------------------------
# W3C trace-context propagation middleware
# ---------------------------------------------------------------------------
class W3CTraceContextMiddleware(BaseHTTPMiddleware):
"""Extract W3C traceparent/tracestate headers from every inbound request."""
async def dispatch(
self,
request: Request,
call_next: Callable[[Request], Awaitable[Response]],
) -> Response:
ctx = propagate.extract(dict(request.headers))
token = context.attach(ctx)
try:
return await call_next(request)
finally:
context.detach(token)
def install_propagator() -> None:
"""Set the global propagator to W3C TraceContext (traceparent / tracestate)."""
propagate.set_global_textmap(
CompositePropagator([TraceContextTextMapPropagator()])
)
# ---------------------------------------------------------------------------
# Application Insights exporter
# ---------------------------------------------------------------------------
def configure_telemetry(settings: Settings) -> None:
install_propagator()
if settings.applicationinsights_connection_string:
from azure.monitor.opentelemetry import configure_azure_monitor
configure_azure_monitor(
connection_string=settings.applicationinsights_connection_string,
credential=build_credential(settings.environment),
disable_offline_storage=True,
instrumentation_options={
"azure_sdk": {"enabled": False},
"requests": {"enabled": False},
"urllib": {"enabled": False},
"urllib3": {"enabled": False},
},
service_name=settings.app_name,
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def current_traceparent(fallback: str) -> str:
context = trace.get_current_span().get_span_context()
if context.is_valid:
return f"00-{context.trace_id:032x}-{context.span_id:016x}-01"
return fallback