From 07fe1c2855f36f58d392faa88f13bc767923c9d4 Mon Sep 17 00:00:00 2001 From: philipph-askui Date: Wed, 1 Apr 2026 16:34:41 +0200 Subject: [PATCH] fix: clean up otel tracing and add workspace ID to trace resource --- docs/09_observability_telemetry_tracing.md | 4 +- pdm.lock | 61 ++++++++++++++++++++-- pyproject.toml | 1 - src/askui/models/shared/conversation.py | 17 +++--- src/askui/telemetry/otel.py | 27 +++++----- 5 files changed, 82 insertions(+), 28 deletions(-) diff --git a/docs/09_observability_telemetry_tracing.md b/docs/09_observability_telemetry_tracing.md index 6e339f5e..2d29d0db 100644 --- a/docs/09_observability_telemetry_tracing.md +++ b/docs/09_observability_telemetry_tracing.md @@ -92,7 +92,6 @@ Set the following environment variables to configure tracing. All variables use | `ASKUI__OTEL_ENDPOINT` | OTLP HTTP endpoint URL | — | | `ASKUI__OTEL_SERVICE_NAME` | Service name reported in traces | `askui-python-sdk` | | `ASKUI__OTEL_SERVICE_VERSION` | Service version reported in traces | Current package version | -| `ASKUI__OTEL_CLUSTER_NAME` | Cluster name reported in traces | `askui-dev` | #### Linux & MacOS ```bash @@ -132,7 +131,6 @@ from askui.telemetry.otel import OtelSettings settings = OtelSettings( enabled=True, - service_name="my-custom-service", - cluster_name="production", + service_name="my-custom-service" ) ``` diff --git a/pdm.lock b/pdm.lock index 08157c53..0d95206e 100644 --- a/pdm.lock +++ b/pdm.lock @@ -1528,7 +1528,7 @@ name = "importlib-metadata" version = "8.7.1" requires_python = ">=3.9" summary = "Read metadata from Python packages" -groups = ["default"] +groups = ["default", "all", "otel"] dependencies = [ "zipp>=3.20", ] @@ -2454,7 +2454,7 @@ name = "opentelemetry-api" version = "1.40.0" requires_python = ">=3.9" summary = "OpenTelemetry Python API" -groups = ["default"] +groups = ["default", "all", "otel"] dependencies = [ "importlib-metadata<8.8.0,>=6.0", "typing-extensions>=4.5.0", @@ -2469,7 +2469,7 @@ name = "opentelemetry-sdk" version = "1.40.0" requires_python = ">=3.9" summary = "OpenTelemetry Python SDK" -groups = ["default"] +groups = ["default", "all", "otel"] dependencies = [ "opentelemetry-api==1.40.0", "opentelemetry-semantic-conventions==0.61b0", @@ -2485,7 +2485,7 @@ name = "opentelemetry-semantic-conventions" version = "0.61b0" requires_python = ">=3.9" summary = "OpenTelemetry Semantic Conventions" -groups = ["default"] +groups = ["default", "all", "otel"] dependencies = [ "opentelemetry-api==1.40.0", "typing-extensions>=4.5.0", @@ -4317,6 +4317,57 @@ files = [ {file = "winregistry-2.1.4.tar.gz", hash = "sha256:c557e6ec26a2827625451bbcee394b2d4c1fbccb6d7dca066335f397c0be1f89"}, ] +[[package]] +name = "wrapt" +version = "1.17.3" +requires_python = ">=3.8" +summary = "Module for decorators, wrappers and monkey patching." +groups = ["all", "otel"] +files = [ + {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c"}, + {file = "wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775"}, + {file = "wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd"}, + {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05"}, + {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418"}, + {file = "wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390"}, + {file = "wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6"}, + {file = "wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f"}, + {file = "wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311"}, + {file = "wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1"}, + {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5"}, + {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2"}, + {file = "wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89"}, + {file = "wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77"}, + {file = "wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd"}, + {file = "wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828"}, + {file = "wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9"}, + {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396"}, + {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc"}, + {file = "wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe"}, + {file = "wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c"}, + {file = "wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7"}, + {file = "wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277"}, + {file = "wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d"}, + {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa"}, + {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050"}, + {file = "wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8"}, + {file = "wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb"}, + {file = "wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16"}, + {file = "wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22"}, + {file = "wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0"}, +] + [[package]] name = "xlrd" version = "2.0.2" @@ -4333,7 +4384,7 @@ name = "zipp" version = "3.23.0" requires_python = ">=3.9" summary = "Backport of pathlib-compatible object wrapper for zip files" -groups = ["default"] +groups = ["default", "all", "otel"] files = [ {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, diff --git a/pyproject.toml b/pyproject.toml index 77c07a67..318fc04e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -228,7 +228,6 @@ otel = [ "opentelemetry-api>=1.38.0", "opentelemetry-exporter-otlp-proto-http>=1.38.0", "opentelemetry-instrumentation-httpx>=0.59b0", - "opentelemetry-instrumentation-sqlalchemy>=0.59b0", ] vertex = [ "google-cloud-aiplatform>=1.122.0", diff --git a/src/askui/models/shared/conversation.py b/src/askui/models/shared/conversation.py index 3afcf105..0cab136c 100644 --- a/src/askui/models/shared/conversation.py +++ b/src/askui/models/shared/conversation.py @@ -291,12 +291,7 @@ def _execute_step(self) -> bool: self._switch_speaker_if_needed() # 2. Get next message(s) from speaker and add to history - logger.debug("Executing step with speaker: %s", self.current_speaker.name) - result: SpeakerResult = self.current_speaker.handle_step( - self, self.cache_manager - ) - for message in result.messages_to_add: - self._add_message(message) + result = self._get_next_message() # 3. Execute tool calls if applicable continue_loop = False @@ -318,6 +313,16 @@ def _execute_step(self) -> bool: return continue_loop + @tracer.start_as_current_span("_get_next_message") + def _get_next_message(self) -> SpeakerResult: + logger.debug("Executing step with speaker: %s", self.current_speaker.name) + result: SpeakerResult = self.current_speaker.handle_step( + self, self.cache_manager + ) + for message in result.messages_to_add: + self._add_message(message) + return result + @tracer.start_as_current_span("_execute_tools_if_present") def _execute_tools_if_present(self, message: MessageParam) -> MessageParam | None: """Execute tools if the message contains tool use blocks. diff --git a/src/askui/telemetry/otel.py b/src/askui/telemetry/otel.py index 297d9e17..2d01d445 100644 --- a/src/askui/telemetry/otel.py +++ b/src/askui/telemetry/otel.py @@ -5,7 +5,7 @@ from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor -from pydantic import Field, SecretStr, model_validator +from pydantic import AliasChoices, Field, SecretStr, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict from typing_extensions import Self @@ -21,6 +21,7 @@ class OtelSettings(BaseSettings): env_prefix="ASKUI__OTEL_", case_sensitive=False, extra="ignore", + validate_by_name=True, ) enabled: bool = Field(default=False) @@ -38,7 +39,11 @@ class OtelSettings(BaseSettings): default=None, description="OTLP endpoint URL.", ) - cluster_name: str = Field(default="askui-dev") + workspace_id: str | None = Field( + default=None, + validation_alias=AliasChoices("ASKUI_WORKSPACE_ID", "askui_workspace_id"), + description="AskUI workspace ID. Read from ASKUI_WORKSPACE_ID env var.", + ) @model_validator(mode="after") def validate_secret_when_enabled(self) -> Self: @@ -71,9 +76,6 @@ def setup_opentelemetry_tracing(settings: OtelSettings) -> None: from opentelemetry.instrumentation.httpx import ( HTTPXClientInstrumentor, ) - from opentelemetry.instrumentation.sqlalchemy import ( - SQLAlchemyInstrumentor, - ) except ImportError: logger.exception("Failed to set up OpenTelemetry Tracing.") return @@ -81,13 +83,13 @@ def setup_opentelemetry_tracing(settings: OtelSettings) -> None: if not settings.enabled: return - resource = Resource.create( - { - "service.name": settings.service_name, - "service.version": settings.service_version, - "cluster.name": settings.cluster_name, - } - ) + resource_attributes: dict[str, str] = { + "service.name": settings.service_name, + "service.version": settings.service_version, + } + if settings.workspace_id: + resource_attributes["askui.workspace.id"] = settings.workspace_id + resource = Resource.create(resource_attributes) provider = TracerProvider(resource=resource) base: str = settings.user + ":" + settings.secret.get_secret_value() # type: ignore @@ -104,4 +106,3 @@ def setup_opentelemetry_tracing(settings: OtelSettings) -> None: trace.set_tracer_provider(provider) HTTPXClientInstrumentor().instrument() - SQLAlchemyInstrumentor().instrument()