Lines 100.00% 45 / 45
Methods 100.00% 1 / 1
Classes 100.00% 1 / 1
Name Lines Methods CRAP
 collectMetrics 100.00% 45 / 45 100.00% 1 / 1 9
17final readonly class AppMetricSource implements RuntimeMetricSource
18{
19    /** @return list<MetricFamily> */
20    public function collectMetrics(RuntimeSnapshot $snapshot): array
21    {
22        $info = new MetricFamily('stewart_app_info', 'App class per app; always 1.', MetricType::Gauge);
23        $states = new MetricFamily('stewart_app_state', 'App lifecycle state; 1 for the current one.', MetricType::Gauge);
24        $paused = new MetricFamily('stewart_app_paused', 'Whether the app is paused; 1 or 0.', MetricType::Gauge);
25        $subscriptions = new MetricFamily('stewart_app_subscriptions', 'Subscriptions the app holds.', MetricType::Gauge);
26        $schedules = new MetricFamily('stewart_app_schedules', 'Schedules the app holds.', MetricType::Gauge);
27        $exposedEntities = new MetricFamily('stewart_app_exposed_entities', 'Home Assistant entities the app exposes, unavailable ones included.', MetricType::Gauge);
28        $delivered = new MetricFamily('stewart_app_events_delivered_total', 'Events delivered to the app handlers.', MetricType::Counter);
29        $subscriptionDropped = new MetricFamily('stewart_app_subscription_dropped_total', 'Events dropped because a subscription queue was full.', MetricType::Counter);
30        $scheduleRuns = new MetricFamily('stewart_app_schedule_runs_total', 'Scheduled handler runs.', MetricType::Counter);
31        $publishes = new MetricFamily('stewart_app_publishes_total', 'Messages the app published.', MetricType::Counter);
32        $failures = new MetricFamily('stewart_app_failures_total', 'Handler failures of the app.', MetricType::Counter);
33        $suppressed = new MetricFamily('stewart_app_suppressed_total', 'Work skipped while the app was paused.', MetricType::Counter);
34        $lastFailure = new MetricFamily('stewart_app_last_failure_timestamp_seconds', 'Unix time of the last app failure.', MetricType::Gauge);
35        $serviceCalls = new MetricFamily('stewart_app_service_calls_total', 'Home Assistant calls of the app by outcome.', MetricType::Counter);
36        $exposedCommands = new MetricFamily('stewart_app_exposed_commands_total', 'Home Assistant commands on the app\'s exposed entities by outcome.', MetricType::Counter);
37        $serviceCallDuration = new MetricFamily('stewart_app_service_call_duration_seconds', 'Home Assistant call latency of the app by outcome.', MetricType::Histogram);
38
39        foreach ($snapshot->apps as $app) {
40            $labels = MetricLabels::fromLabel('app', $app->id)->withLabel('worker', $app->workerId === null ? '' : (string) $app->workerId);
41
42            if (ResourceScope::tryFromWireValue($app->id)?->isShared() !== true) {
43                $info->recordSample($labels->withLabel('class', $app->class), 1);
44
45                foreach (AppState::cases() as $state) {
46                    $states->recordSample($labels->withLabel('state', $state->value), $state === $app->state);
47                }
48
49                $paused->recordSample($labels, $app->pause !== null);
50            }
51
52            $subscriptions->recordSample($labels, $app->subscriptions);
53            $schedules->recordSample($labels, $app->schedules);
54            $exposedEntities->recordSample($labels, $app->exposedEntities);
55            $delivered->recordSample($labels, $app->counters->delivered);
56            $subscriptionDropped->recordSample($labels, $app->counters->subscriptionDropped);
57            $scheduleRuns->recordSample($labels, $app->counters->scheduleRuns);
58            $publishes->recordSample($labels, $app->counters->publishes);
59            $failures->recordSample($labels, $app->counters->failures);
60            $suppressed->recordSample($labels, $app->counters->suppressed);
61
62            if ($app->lastFailure !== null) {
63                $lastFailure->recordSample($labels, PrometheusNumber::convertToEpochSeconds($app->lastFailure->at));
64            }
65
66            foreach ($app->exposedCommands as $commands) {
67                $exposedCommands->recordSample($labels->withLabel('outcome', $commands->outcome->value), $commands->count);
68            }
69
70            foreach ($app->serviceCalls as $calls) {
71                $outcomeLabels = $labels->withLabel('outcome', $calls->outcome->value);
72                $serviceCalls->recordSample($outcomeLabels, $calls->count);
73
74                if ($calls->latency !== null) {
75                    $serviceCallDuration->recordHistogram($outcomeLabels, Histogram::fromLatencyHistogram($calls->latency));
76                }
77            }
78        }
79
80        return [
81            $info, $states, $paused, $subscriptions, $schedules, $exposedEntities, $delivered, $subscriptionDropped, $scheduleRuns, $publishes,
82            $failures, $suppressed, $lastFailure, $serviceCalls, $serviceCallDuration, $exposedCommands,
83        ];
84    }
85}