From 37479bbc6a43bbd5445e627fe16913907c9fddac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Sedl=C3=A1=C5=99?= Date: Mon, 12 May 2025 14:02:56 +0200 Subject: [PATCH] Record exceptions for top level OTel span MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there is an exception in the code, the cli_main function captures it, saves the traceback and exits the process. With the original tracing span, the instrumentation never saw the actual exception, only SystemExit. This meant the span was not recorded as failed. (Technically python-opentelemetry 1.31.0 does record it, but that change was reverted in 1.32.0.) It is somewhat tricky to structure the code so that the exception is recorded implicitly. The status update to DOOMED must happen inside the span (in order to propagate it to the trace). Thus a new function is exported from the tracing module to record the exception explicitly before it gets discarded and replaced with the exit. Signed-off-by: Lubomír Sedlář (cherry picked from commit d3630bfa6f8dc5ccf3dcef9cb4a947d82d7f09b8) --- pungi/otel.py | 14 ++++++++++++++ pungi/scripts/pungi_koji.py | 1 + 2 files changed, 15 insertions(+) diff --git a/pungi/otel.py b/pungi/otel.py index ec8e4b97..1f2d7d08 100644 --- a/pungi/otel.py +++ b/pungi/otel.py @@ -31,6 +31,9 @@ class DummyTracing: def set_context(self, traceparent): pass + def record_exception(self, exc, set_error_status=True): + pass + class OtelTracing: """This class implements the actual integration with opentelemetry.""" @@ -114,6 +117,17 @@ class OtelTracing: ) context.attach(ctx) + def record_exception(self, exc, set_error_status=True): + """Records an exception for the current span and optionally marks the + span as failed.""" + from opentelemetry import trace + + span = trace.get_current_span() + span.record_exception(exc) + + if set_error_status: + span.set_status(trace.status.StatusCode.ERROR) + class InstrumentedClientSession: """Wrapper around koji.ClientSession that creates spans for each API call. diff --git a/pungi/scripts/pungi_koji.py b/pungi/scripts/pungi_koji.py index 06fec254..f2fb772c 100644 --- a/pungi/scripts/pungi_koji.py +++ b/pungi/scripts/pungi_koji.py @@ -657,6 +657,7 @@ def cli_main(): try: main() except (Exception, KeyboardInterrupt) as ex: + tracing.record_exception(ex) if COMPOSE: COMPOSE.log_error("Compose run failed: %s" % ex) COMPOSE.traceback(show_locals=getattr(ex, "show_locals", True))