From 40a930d487d72e25439297db75504f18c2bf1c68 Mon Sep 17 00:00:00 2001 From: Evaline Ju <69598118+evaline-ju@users.noreply.github.com> Date: Thu, 26 Feb 2026 08:15:22 -0700 Subject: [PATCH 1/3] :alembic: Trace to tool attempt Signed-off-by: Evaline Ju <69598118+evaline-ju@users.noreply.github.com> --- .../src/weather_service/agent.py | 13 +++++++++- .../src/weather_service/graph.py | 25 +++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/a2a/weather_service/src/weather_service/agent.py b/a2a/weather_service/src/weather_service/agent.py index 54f17736..4d2953db 100644 --- a/a2a/weather_service/src/weather_service/agent.py +++ b/a2a/weather_service/src/weather_service/agent.py @@ -119,7 +119,18 @@ async def execute(self, context: RequestContext, event_queue: EventQueue): # Test MCP connection first logger.info(f'Attempting to connect to MCP server at: {os.getenv("MCP_URL", "http://localhost:8000/sse")}') - mcpclient = get_mcpclient() + # Extract current trace context for propagation to Envoy/MCP + traceparent = None + root_span = get_root_span() + if root_span and root_span.is_recording(): + span_context = root_span.get_span_context() + if span_context.is_valid: + # Format traceparent according to W3C Trace Context spec + # Format: version-trace_id-span_id-trace_flags + traceparent = f"00-{format(span_context.trace_id, '032x')}-{format(span_context.span_id, '016x')}-{format(span_context.trace_flags, '02x')}" + logger.info(f'Propagating trace context to MCP: {traceparent}') + + mcpclient = get_mcpclient(traceparent=traceparent) # Try to get tools to verify connection try: diff --git a/a2a/weather_service/src/weather_service/graph.py b/a2a/weather_service/src/weather_service/graph.py index 3e5d671d..f73eeead 100644 --- a/a2a/weather_service/src/weather_service/graph.py +++ b/a2a/weather_service/src/weather_service/graph.py @@ -12,12 +12,27 @@ class ExtendedMessagesState(MessagesState): final_answer: str = "" -def get_mcpclient(): - return MultiServerMCPClient({ - "math": { - "url": os.getenv("MCP_URL", "http://localhost:8000/mcp"), - "transport": os.getenv("MCP_TRANSPORT", "streamable_http"), +def get_mcpclient(traceparent: str | None = None): + """ + Create an MCP client with optional trace context propagation. + + Args: + traceparent: W3C Trace Context traceparent header value + Format: "00-{trace-id}-{parent-id}-{trace-flags}" + """ + server_config = { + "url": os.getenv("MCP_URL", "http://localhost:8000/mcp"), + "transport": os.getenv("MCP_TRANSPORT", "streamable_http"), + } + + # Add traceparent header if provided for distributed tracing through Envoy + if traceparent: + server_config["headers"] = { + "traceparent": traceparent } + + return MultiServerMCPClient({ + "math": server_config }) async def get_graph(client) -> StateGraph: From 1625a4da4bfffdfb803c65f7c641aa358687cbef Mon Sep 17 00:00:00 2001 From: Evaline Ju <69598118+evaline-ju@users.noreply.github.com> Date: Thu, 26 Feb 2026 11:43:57 -0700 Subject: [PATCH 2/3] :alembic: Continue try connecting trace Signed-off-by: Evaline Ju <69598118+evaline-ju@users.noreply.github.com> --- a2a/weather_service/pyproject.toml | 2 ++ .../src/weather_service/agent.py | 16 +++-------- .../src/weather_service/graph.py | 27 +++++++------------ .../src/weather_service/observability.py | 22 ++++++++++++--- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/a2a/weather_service/pyproject.toml b/a2a/weather_service/pyproject.toml index cf23d96a..279023ee 100644 --- a/a2a/weather_service/pyproject.toml +++ b/a2a/weather_service/pyproject.toml @@ -18,6 +18,8 @@ dependencies = [ "langchain-mcp-adapters>=0.1.0", "python-keycloak>=5.5.1", "opentelemetry-exporter-otlp", + # Auto-instrument httpx so outgoing MCP tool calls propagate traceparent + "opentelemetry-instrumentation-httpx>=0.49b0", # OpenTelemetry GenAI semantic convention instrumentation # Emits spans with gen_ai.* attributes for MLflow compatibility "opentelemetry-instrumentation-openai>=0.34b0", diff --git a/a2a/weather_service/src/weather_service/agent.py b/a2a/weather_service/src/weather_service/agent.py index 4d2953db..81554be5 100644 --- a/a2a/weather_service/src/weather_service/agent.py +++ b/a2a/weather_service/src/weather_service/agent.py @@ -119,18 +119,10 @@ async def execute(self, context: RequestContext, event_queue: EventQueue): # Test MCP connection first logger.info(f'Attempting to connect to MCP server at: {os.getenv("MCP_URL", "http://localhost:8000/sse")}') - # Extract current trace context for propagation to Envoy/MCP - traceparent = None - root_span = get_root_span() - if root_span and root_span.is_recording(): - span_context = root_span.get_span_context() - if span_context.is_valid: - # Format traceparent according to W3C Trace Context spec - # Format: version-trace_id-span_id-trace_flags - traceparent = f"00-{format(span_context.trace_id, '032x')}-{format(span_context.span_id, '016x')}-{format(span_context.trace_flags, '02x')}" - logger.info(f'Propagating trace context to MCP: {traceparent}') - - mcpclient = get_mcpclient(traceparent=traceparent) + # Trace context propagation to MCP gateway is handled automatically + # by opentelemetry-instrumentation-httpx, which injects the current + # span's traceparent header on every outgoing httpx request. + mcpclient = get_mcpclient() # Try to get tools to verify connection try: diff --git a/a2a/weather_service/src/weather_service/graph.py b/a2a/weather_service/src/weather_service/graph.py index f73eeead..e12b35a5 100644 --- a/a2a/weather_service/src/weather_service/graph.py +++ b/a2a/weather_service/src/weather_service/graph.py @@ -12,27 +12,18 @@ class ExtendedMessagesState(MessagesState): final_answer: str = "" -def get_mcpclient(traceparent: str | None = None): - """ - Create an MCP client with optional trace context propagation. +def get_mcpclient(): + """Create an MCP client. - Args: - traceparent: W3C Trace Context traceparent header value - Format: "00-{trace-id}-{parent-id}-{trace-flags}" + Trace context propagation (traceparent headers) to the MCP gateway is + handled automatically by opentelemetry-instrumentation-httpx, which + injects the current span's context on every outgoing HTTP request. """ - server_config = { - "url": os.getenv("MCP_URL", "http://localhost:8000/mcp"), - "transport": os.getenv("MCP_TRANSPORT", "streamable_http"), - } - - # Add traceparent header if provided for distributed tracing through Envoy - if traceparent: - server_config["headers"] = { - "traceparent": traceparent - } - return MultiServerMCPClient({ - "math": server_config + "math": { + "url": os.getenv("MCP_URL", "http://localhost:8000/mcp"), + "transport": os.getenv("MCP_TRANSPORT", "streamable_http"), + } }) async def get_graph(client) -> StateGraph: diff --git a/a2a/weather_service/src/weather_service/observability.py b/a2a/weather_service/src/weather_service/observability.py index e713de94..45f632af 100644 --- a/a2a/weather_service/src/weather_service/observability.py +++ b/a2a/weather_service/src/weather_service/observability.py @@ -125,6 +125,18 @@ def setup_observability() -> None: W3CBaggagePropagator(), ])) + # Instrument httpx for automatic traceparent propagation on outgoing requests. + # This is critical for distributed tracing: langchain-mcp-adapters uses httpx + # for streamable_http transport, so each MCP tool call will automatically carry + # the current span's traceparent header to the MCP gateway (Envoy). + try: + from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor + HTTPXClientInstrumentor().instrument() + logger.info("httpx instrumented for automatic trace context propagation") + except ImportError: + logger.warning("opentelemetry-instrumentation-httpx not available - " + "MCP tool calls will not propagate trace context") + # Instrument OpenAI for GenAI semantic conventions try: from opentelemetry.instrumentation.openai import OpenAIInstrumentor @@ -421,10 +433,12 @@ async def tracing_middleware(request: Request, call_next): except Exception as e: logger.debug(f"Could not parse request body: {e}") - # Break parent chain to make this a true root span - # Without this, the span would inherit parent from W3C Trace Context headers - empty_ctx = context.Context() - detach_token = context.attach(empty_ctx) + # Extract incoming W3C Trace Context from request headers. + # If the request carries a traceparent (e.g., from Envoy/MCP gateway or + # an upstream orchestrator), the root span becomes a child of that trace. + # This is what connects the agent's spans to the MCP gateway's spans. + incoming_ctx = extract(dict(request.headers)) + detach_token = context.attach(incoming_ctx) try: # Create root span with correct GenAI naming convention From 0e77b2f5bd14794ff34948c0a70f4ae0415bea24 Mon Sep 17 00:00:00 2001 From: Evaline Ju <69598118+evaline-ju@users.noreply.github.com> Date: Thu, 26 Feb 2026 11:50:34 -0700 Subject: [PATCH 3/3] Update uv.lock, remove polled spans, and update comments Assisted-By: Claude Opus 4.6 Signed-off-by: Evaline Ju <69598118+evaline-ju@users.noreply.github.com> --- .../src/weather_service/agent.py | 3 -- .../src/weather_service/observability.py | 13 +++----- a2a/weather_service/uv.lock | 33 ++++++++++++++++--- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/a2a/weather_service/src/weather_service/agent.py b/a2a/weather_service/src/weather_service/agent.py index 81554be5..54f17736 100644 --- a/a2a/weather_service/src/weather_service/agent.py +++ b/a2a/weather_service/src/weather_service/agent.py @@ -119,9 +119,6 @@ async def execute(self, context: RequestContext, event_queue: EventQueue): # Test MCP connection first logger.info(f'Attempting to connect to MCP server at: {os.getenv("MCP_URL", "http://localhost:8000/sse")}') - # Trace context propagation to MCP gateway is handled automatically - # by opentelemetry-instrumentation-httpx, which injects the current - # span's traceparent header on every outgoing httpx request. mcpclient = get_mcpclient() # Try to get tools to verify connection diff --git a/a2a/weather_service/src/weather_service/observability.py b/a2a/weather_service/src/weather_service/observability.py index 45f632af..3bee7cce 100644 --- a/a2a/weather_service/src/weather_service/observability.py +++ b/a2a/weather_service/src/weather_service/observability.py @@ -126,9 +126,8 @@ def setup_observability() -> None: ])) # Instrument httpx for automatic traceparent propagation on outgoing requests. - # This is critical for distributed tracing: langchain-mcp-adapters uses httpx - # for streamable_http transport, so each MCP tool call will automatically carry - # the current span's traceparent header to the MCP gateway (Envoy). + # langchain-mcp-adapters uses httpx for streamable_http transport, so each MCP + # tool call will automatically carry the current span's traceparent header try: from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor HTTPXClientInstrumentor().instrument() @@ -408,7 +407,7 @@ def create_tracing_middleware(): async def tracing_middleware(request: Request, call_next): # Skip non-API paths (health checks, agent card, etc.) - if request.url.path in ["/health", "/ready", "/.well-known/agent-card.json"]: + if request.url.path in ["/health", "/ready", "/.well-known/agent-card.json", "/.well-known/agent.json"]: return await call_next(request) tracer = get_tracer() @@ -433,10 +432,8 @@ async def tracing_middleware(request: Request, call_next): except Exception as e: logger.debug(f"Could not parse request body: {e}") - # Extract incoming W3C Trace Context from request headers. - # If the request carries a traceparent (e.g., from Envoy/MCP gateway or - # an upstream orchestrator), the root span becomes a child of that trace. - # This is what connects the agent's spans to the MCP gateway's spans. + # Extract incoming W3C Trace Context from request headers to connect + # agent spans to MCP gateway spans incoming_ctx = extract(dict(request.headers)) detach_token = context.attach(incoming_ctx) diff --git a/a2a/weather_service/uv.lock b/a2a/weather_service/uv.lock index 26ca752a..920d1167 100644 --- a/a2a/weather_service/uv.lock +++ b/a2a/weather_service/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.13'", @@ -494,7 +494,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/26/80/a6ee52c59f75a387ec1f0c0075cf7981fb4644e4162afd3401dabeaa83ca/greenlet-3.2.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:aa30066fd6862e1153eaae9b51b449a6356dcdb505169647f69e6ce315b9468b", size = 268609, upload-time = "2025-04-22T14:26:58.208Z" }, { url = "https://files.pythonhosted.org/packages/ad/11/bd7a900629a4dd0e691dda88f8c2a7bfa44d0c4cffdb47eb5302f87a30d0/greenlet-3.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b0f3a0a67786facf3b907a25db80efe74310f9d63cc30869e49c79ee3fcef7e", size = 628776, upload-time = "2025-04-22T14:53:43.036Z" }, { url = "https://files.pythonhosted.org/packages/46/f1/686754913fcc2707addadf815c884fd49c9f00a88e6dac277a1e1a8b8086/greenlet-3.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64a4d0052de53ab3ad83ba86de5ada6aeea8f099b4e6c9ccce70fb29bc02c6a2", size = 640827, upload-time = "2025-04-22T14:54:57.409Z" }, - { url = "https://files.pythonhosted.org/packages/03/74/bef04fa04125f6bcae2c1117e52f99c5706ac6ee90b7300b49b3bc18fc7d/greenlet-3.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852ef432919830022f71a040ff7ba3f25ceb9fe8f3ab784befd747856ee58530", size = 636752, upload-time = "2025-04-22T15:04:33.707Z" }, { url = "https://files.pythonhosted.org/packages/aa/08/e8d493ab65ae1e9823638b8d0bf5d6b44f062221d424c5925f03960ba3d0/greenlet-3.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4818116e75a0dd52cdcf40ca4b419e8ce5cb6669630cb4f13a6c384307c9543f", size = 635993, upload-time = "2025-04-22T14:27:04.408Z" }, { url = "https://files.pythonhosted.org/packages/1f/9d/3a3a979f2b019fb756c9a92cd5e69055aded2862ebd0437de109cf7472a2/greenlet-3.2.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9afa05fe6557bce1642d8131f87ae9462e2a8e8c46f7ed7929360616088a3975", size = 583927, upload-time = "2025-04-22T14:25:55.896Z" }, { url = "https://files.pythonhosted.org/packages/59/21/a00d27d9abb914c1213926be56b2a2bf47999cf0baf67d9ef5b105b8eb5b/greenlet-3.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5c12f0d17a88664757e81a6e3fc7c2452568cf460a2f8fb44f90536b2614000b", size = 1112891, upload-time = "2025-04-22T14:58:55.808Z" }, @@ -503,7 +502,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f0/d1/e4777b188a04726f6cf69047830d37365b9191017f54caf2f7af336a6f18/greenlet-3.2.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:0ba2811509a30e5f943be048895a983a8daf0b9aa0ac0ead526dfb5d987d80ea", size = 270381, upload-time = "2025-04-22T14:25:43.69Z" }, { url = "https://files.pythonhosted.org/packages/59/e7/b5b738f5679247ddfcf2179c38945519668dced60c3164c20d55c1a7bb4a/greenlet-3.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4245246e72352b150a1588d43ddc8ab5e306bef924c26571aafafa5d1aaae4e8", size = 637195, upload-time = "2025-04-22T14:53:44.563Z" }, { url = "https://files.pythonhosted.org/packages/6c/9f/57968c88a5f6bc371364baf983a2e5549cca8f503bfef591b6dd81332cbc/greenlet-3.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7abc0545d8e880779f0c7ce665a1afc3f72f0ca0d5815e2b006cafc4c1cc5840", size = 651381, upload-time = "2025-04-22T14:54:59.439Z" }, - { url = "https://files.pythonhosted.org/packages/40/81/1533c9a458e9f2ebccb3ae22f1463b2093b0eb448a88aac36182f1c2cd3d/greenlet-3.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6dcc6d604a6575c6225ac0da39df9335cc0c6ac50725063fa90f104f3dbdb2c9", size = 646110, upload-time = "2025-04-22T15:04:35.739Z" }, { url = "https://files.pythonhosted.org/packages/06/66/25f7e4b1468ebe4a520757f2e41c2a36a2f49a12e963431b82e9f98df2a0/greenlet-3.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2273586879affca2d1f414709bb1f61f0770adcabf9eda8ef48fd90b36f15d12", size = 648070, upload-time = "2025-04-22T14:27:05.976Z" }, { url = "https://files.pythonhosted.org/packages/d7/4c/49d366565c4c4d29e6f666287b9e2f471a66c3a3d8d5066692e347f09e27/greenlet-3.2.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ff38c869ed30fff07f1452d9a204ece1ec6d3c0870e0ba6e478ce7c1515acf22", size = 603816, upload-time = "2025-04-22T14:25:57.224Z" }, { url = "https://files.pythonhosted.org/packages/04/15/1612bb61506f44b6b8b6bebb6488702b1fe1432547e95dda57874303a1f5/greenlet-3.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e934591a7a4084fa10ee5ef50eb9d2ac8c4075d5c9cf91128116b5dca49d43b1", size = 1119572, upload-time = "2025-04-22T14:58:58.277Z" }, @@ -512,7 +510,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/2a/581b3808afec55b2db838742527c40b4ce68b9b64feedff0fd0123f4b19a/greenlet-3.2.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:e1967882f0c42eaf42282a87579685c8673c51153b845fde1ee81be720ae27ac", size = 269119, upload-time = "2025-04-22T14:25:01.798Z" }, { url = "https://files.pythonhosted.org/packages/b0/f3/1c4e27fbdc84e13f05afc2baf605e704668ffa26e73a43eca93e1120813e/greenlet-3.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e77ae69032a95640a5fe8c857ec7bee569a0997e809570f4c92048691ce4b437", size = 637314, upload-time = "2025-04-22T14:53:46.214Z" }, { url = "https://files.pythonhosted.org/packages/fc/1a/9fc43cb0044f425f7252da9847893b6de4e3b20c0a748bce7ab3f063d5bc/greenlet-3.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3227c6ec1149d4520bc99edac3b9bc8358d0034825f3ca7572165cb502d8f29a", size = 651421, upload-time = "2025-04-22T14:55:00.852Z" }, - { url = "https://files.pythonhosted.org/packages/8a/65/d47c03cdc62c6680206b7420c4a98363ee997e87a5e9da1e83bd7eeb57a8/greenlet-3.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ddda0197c5b46eedb5628d33dad034c455ae77708c7bf192686e760e26d6a0c", size = 645789, upload-time = "2025-04-22T15:04:37.702Z" }, { url = "https://files.pythonhosted.org/packages/2f/40/0faf8bee1b106c241780f377b9951dd4564ef0972de1942ef74687aa6bba/greenlet-3.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de62b542e5dcf0b6116c310dec17b82bb06ef2ceb696156ff7bf74a7a498d982", size = 648262, upload-time = "2025-04-22T14:27:07.55Z" }, { url = "https://files.pythonhosted.org/packages/e0/a8/73305f713183c2cb08f3ddd32eaa20a6854ba9c37061d682192db9b021c3/greenlet-3.2.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c07a0c01010df42f1f058b3973decc69c4d82e036a951c3deaf89ab114054c07", size = 606770, upload-time = "2025-04-22T14:25:58.34Z" }, { url = "https://files.pythonhosted.org/packages/c3/05/7d726e1fb7f8a6ac55ff212a54238a36c57db83446523c763e20cd30b837/greenlet-3.2.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2530bfb0abcd451ea81068e6d0a1aac6dabf3f4c23c8bd8e2a8f579c2dd60d95", size = 1117960, upload-time = "2025-04-22T14:59:00.373Z" }, @@ -520,7 +517,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e4/f6/339c6e707062319546598eb9827d3ca8942a3eccc610d4a54c1da7b62527/greenlet-3.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:24a496479bc8bd01c39aa6516a43c717b4cee7196573c47b1f8e1011f7c12495", size = 295994, upload-time = "2025-04-22T14:50:44.796Z" }, { url = "https://files.pythonhosted.org/packages/f1/72/2a251d74a596af7bb1717e891ad4275a3fd5ac06152319d7ad8c77f876af/greenlet-3.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:175d583f7d5ee57845591fc30d852b75b144eb44b05f38b67966ed6df05c8526", size = 629889, upload-time = "2025-04-22T14:53:48.434Z" }, { url = "https://files.pythonhosted.org/packages/29/2e/d7ed8bf97641bf704b6a43907c0e082cdf44d5bc026eb8e1b79283e7a719/greenlet-3.2.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ecc9d33ca9428e4536ea53e79d781792cee114d2fa2695b173092bdbd8cd6d5", size = 635261, upload-time = "2025-04-22T14:55:02.258Z" }, - { url = "https://files.pythonhosted.org/packages/1e/75/802aa27848a6fcb5e566f69c64534f572e310f0f12d41e9201a81e741551/greenlet-3.2.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f56382ac4df3860ebed8ed838f268f03ddf4e459b954415534130062b16bc32", size = 632523, upload-time = "2025-04-22T15:04:39.221Z" }, { url = "https://files.pythonhosted.org/packages/56/09/f7c1c3bab9b4c589ad356503dd71be00935e9c4db4db516ed88fc80f1187/greenlet-3.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc45a7189c91c0f89aaf9d69da428ce8301b0fd66c914a499199cfb0c28420fc", size = 628816, upload-time = "2025-04-22T14:27:08.869Z" }, { url = "https://files.pythonhosted.org/packages/79/e0/1bb90d30b5450eac2dffeaac6b692857c4bd642c21883b79faa8fa056cf2/greenlet-3.2.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51a2f49da08cff79ee42eb22f1658a2aed60c72792f0a0a95f5f0ca6d101b1fb", size = 593687, upload-time = "2025-04-22T14:25:59.676Z" }, { url = "https://files.pythonhosted.org/packages/c5/b5/adbe03c8b4c178add20cc716021183ae6b0326d56ba8793d7828c94286f6/greenlet-3.2.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:0c68bbc639359493420282d2f34fa114e992a8724481d700da0b10d10a7611b8", size = 1105754, upload-time = "2025-04-22T14:59:02.585Z" }, @@ -1257,6 +1253,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/6f/f20cd1542959f43fb26a5bf9bb18cd81a1ea0700e8870c8f369bd07f5c65/opentelemetry_instrumentation-0.57b0-py3-none-any.whl", hash = "sha256:9109280f44882e07cec2850db28210b90600ae9110b42824d196de357cbddf7e", size = 32460, upload-time = "2025-07-29T15:41:40.883Z" }, ] +[[package]] +name = "opentelemetry-instrumentation-httpx" +version = "0.57b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "opentelemetry-util-http" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/28/65fea8b8e7f19502a8af1229c62384f9211c1480f5dee1776841810d6551/opentelemetry_instrumentation_httpx-0.57b0.tar.gz", hash = "sha256:ea5669cdb17185f8d247c2dbf756ae5b95b53110ca4d58424f2be5cc7223dbdd", size = 19511, upload-time = "2025-07-29T15:43:00.575Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/24/e59b319a5c6a41c6b4230f5e25651edbeb3a8d248afa1b411fd07cc3f9bf/opentelemetry_instrumentation_httpx-0.57b0-py3-none-any.whl", hash = "sha256:729fef97624016d3e5b03b71f51c9a1a2f7480b023373186d643fbed7496712a", size = 15111, upload-time = "2025-07-29T15:42:06.501Z" }, +] + [[package]] name = "opentelemetry-instrumentation-openai" version = "0.48.1" @@ -1320,6 +1332,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/35/b5/cf25da2218910f0d6cdf7f876a06bed118c4969eacaf60a887cbaef44f44/opentelemetry_semantic_conventions_ai-0.4.13-py3-none-any.whl", hash = "sha256:883a30a6bb5deaec0d646912b5f9f6dcbb9f6f72557b73d0f2560bf25d13e2d5", size = 6080, upload-time = "2025-08-22T10:14:16.477Z" }, ] +[[package]] +name = "opentelemetry-util-http" +version = "0.57b0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/1b/6229c45445e08e798fa825f5376f6d6a4211d29052a4088eed6d577fa653/opentelemetry_util_http-0.57b0.tar.gz", hash = "sha256:f7417595ead0eb42ed1863ec9b2f839fc740368cd7bbbfc1d0a47bc1ab0aba11", size = 9405, upload-time = "2025-07-29T15:43:19.916Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a6/b98d508d189b9c208f5978d0906141747d7e6df7c7cafec03657ed1ed559/opentelemetry_util_http-0.57b0-py3-none-any.whl", hash = "sha256:e54c0df5543951e471c3d694f85474977cd5765a3b7654398c83bab3d2ffb8e9", size = 7643, upload-time = "2025-07-29T15:42:41.744Z" }, +] + [[package]] name = "orjson" version = "3.10.18" @@ -2126,6 +2147,7 @@ dependencies = [ { name = "openinference-instrumentation-langchain" }, { name = "openinference-semantic-conventions" }, { name = "opentelemetry-exporter-otlp" }, + { name = "opentelemetry-instrumentation-httpx" }, { name = "opentelemetry-instrumentation-openai" }, { name = "pydantic-settings" }, { name = "python-keycloak" }, @@ -2142,6 +2164,7 @@ requires-dist = [ { name = "openinference-instrumentation-langchain", specifier = ">=0.1.27" }, { name = "openinference-semantic-conventions", specifier = ">=0.1.12" }, { name = "opentelemetry-exporter-otlp" }, + { name = "opentelemetry-instrumentation-httpx", specifier = ">=0.49b0" }, { name = "opentelemetry-instrumentation-openai", specifier = ">=0.34b0" }, { name = "pydantic-settings", specifier = ">=2.8.1" }, { name = "python-keycloak", specifier = ">=5.5.1" },