diff --git a/changelog/4325.fixed.md b/changelog/4325.fixed.md new file mode 100644 index 000000000..b87a97bfb --- /dev/null +++ b/changelog/4325.fixed.md @@ -0,0 +1 @@ +- Fixed `SentryMetrics` silently dropping `MetricsFrame`s from `stop_ttfb_metrics` and `stop_processing_metrics`. `SentryMetrics` called the base `FrameProcessorMetrics` implementation but discarded its return value, so `FrameProcessor` never pushed the `MetricsFrame` downstream. This prevented observers (e.g. `UserBotLatencyObserver`, `MetricsLogObserver`) from seeing TTFB and processing metrics for any service using `metrics=SentryMetrics()`. The metrics were still calculated and Sentry transactions still completed — only the downstream frame push was affected. diff --git a/src/pipecat/processors/metrics/sentry.py b/src/pipecat/processors/metrics/sentry.py index b043b9058..0484995db 100644 --- a/src/pipecat/processors/metrics/sentry.py +++ b/src/pipecat/processors/metrics/sentry.py @@ -97,13 +97,20 @@ class SentryMetrics(FrameProcessorMetrics): Args: end_time: Optional end timestamp override. + + Returns: + MetricsFrame produced by the base class, or None if not measuring. + Returning the frame is required so ``FrameProcessor.stop_ttfb_metrics`` + can push it downstream to observers. """ - await super().stop_ttfb_metrics(end_time=end_time) + frame = await super().stop_ttfb_metrics(end_time=end_time) if self._sentry_available and self._ttfb_metrics_tx: await self._sentry_queue.put(self._ttfb_metrics_tx) self._ttfb_metrics_tx = None + return frame + async def start_processing_metrics(self, *, start_time: float | None = None): """Start tracking frame processing metrics. @@ -126,13 +133,20 @@ class SentryMetrics(FrameProcessorMetrics): Args: end_time: Optional end timestamp override. + + Returns: + MetricsFrame produced by the base class, or None if not measuring. + Returning the frame is required so ``FrameProcessor.stop_processing_metrics`` + can push it downstream to observers. """ - await super().stop_processing_metrics(end_time=end_time) + frame = await super().stop_processing_metrics(end_time=end_time) if self._sentry_available and self._processing_metrics_tx: await self._sentry_queue.put(self._processing_metrics_tx) self._processing_metrics_tx = None + return frame + async def _sentry_task_handler(self): """Background task handler for completing Sentry transactions.""" running = True