diff --git a/lib/charms/tempo_k8s/v1/charm_tracing.py b/lib/charms/tempo_k8s/v1/charm_tracing.py index ebe022e0..913b20bb 100644 --- a/lib/charms/tempo_k8s/v1/charm_tracing.py +++ b/lib/charms/tempo_k8s/v1/charm_tracing.py @@ -176,8 +176,10 @@ def my_tracing_endpoint(self) -> Optional[str]: import inspect import logging import os +import shutil from contextlib import contextmanager from contextvars import Context, ContextVar, copy_context +from importlib.metadata import distributions from pathlib import Path from typing import ( Any, @@ -217,7 +219,7 @@ def my_tracing_endpoint(self) -> Optional[str]: # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 11 +LIBPATCH = 12 PYDEPS = ["opentelemetry-exporter-otlp-proto-http==1.21.0"] @@ -359,6 +361,30 @@ def _get_server_cert( return server_cert +def _remove_stale_otel_sdk_packages(): + """Hack to remove stale opentelemetry sdk packages from the charm's python venv. + + See https://github.com/canonical/grafana-agent-operator/issues/146 and + https://bugs.launchpad.net/juju/+bug/2058335 for more context. This patch can be removed after + this juju issue is resolved and sufficient time has passed to expect most users of this library + have migrated to the patched version of juju. + + This only does something if executed on an upgrade-charm event. + """ + if os.getenv("JUJU_DISPATCH_PATH") == "hooks/upgrade-charm": + logger.debug("Executing _remove_stale_otel_sdk_packages patch on charm upgrade") + # Find any opentelemetry_sdk distributions + otel_sdk_distributions = list(distributions(name="opentelemetry_sdk")) + # If there is more than 1, inspect each and if it has 0 entrypoints, infer that it is stale + if len(otel_sdk_distributions) > 1: + for distribution in otel_sdk_distributions: + if len(distribution.entry_points) == 0: + # Distribution appears to be empty. Remove it + path = distribution._path # type: ignore + logger.debug(f"Removing empty opentelemetry_sdk distribution at: {path}") + shutil.rmtree(path) + + def _setup_root_span_initializer( charm_type: _CharmType, tracing_endpoint_attr: str, @@ -391,6 +417,10 @@ def wrap_init(self: CharmBase, framework: Framework, *args, **kwargs): _service_name = service_name or f"{self.app.name}-charm" unit_name = self.unit.name + # apply hacky patch to remove stale opentelemetry sdk packages on upgrade-charm. + # it could be trouble if someone ever decides to implement their own tracer parallel to + # ours and before the charm has inited. We assume they won't. + _remove_stale_otel_sdk_packages() resource = Resource.create( attributes={ "service.name": _service_name,