Skip to main content

orbit_runtime/
metrics.rs

1//! Prometheus-style counters derived from committed events.
2
3use crate::model::Event;
4
5#[derive(Debug, Default, Clone)]
6pub struct Metrics {
7    pub executions_started: u64,
8    pub executions_completed: u64,
9    pub executions_failed: u64,
10    pub executions_cancelled: u64,
11    pub executions_timed_out: u64,
12    pub tasks_dispatched: u64,
13    pub tasks_succeeded: u64,
14    pub task_attempts_failed: u64,
15    pub task_attempts_uncertain: u64,
16    pub retries_scheduled: u64,
17    pub steps_skipped: u64,
18    pub stale_results: u64,
19    pub compensations_started: u64,
20    pub compensations_failed: u64,
21    pub events_committed: u64,
22}
23
24impl Metrics {
25    pub fn observe(&mut self, e: &Event) {
26        self.events_committed += 1;
27        match e {
28            Event::WorkflowCreated { .. } => self.executions_started += 1,
29            Event::WorkflowCompleted { .. } => self.executions_completed += 1,
30            Event::WorkflowFailed { .. } => self.executions_failed += 1,
31            Event::WorkflowCancelled { .. } => self.executions_cancelled += 1,
32            Event::WorkflowTimedOut { .. } => self.executions_timed_out += 1,
33            Event::StepDispatched { .. } => self.tasks_dispatched += 1,
34            Event::StepSucceeded { .. } => self.tasks_succeeded += 1,
35            Event::StepAttemptFailed { .. } => self.task_attempts_failed += 1,
36            Event::StepAttemptUncertain { .. } => self.task_attempts_uncertain += 1,
37            Event::RetryScheduled { .. } => self.retries_scheduled += 1,
38            Event::StepSkipped { .. } => self.steps_skipped += 1,
39            Event::StaleResultIgnored { .. } => self.stale_results += 1,
40            Event::CompensationStarted { .. } => self.compensations_started += 1,
41            Event::CompensationFailed { .. } => self.compensations_failed += 1,
42            _ => {}
43        }
44    }
45
46    pub fn render(&self, active: usize, sessions: usize) -> String {
47        let counters = [
48            (
49                "orbit_executions_started_total",
50                "Executions started",
51                self.executions_started,
52            ),
53            (
54                "orbit_executions_completed_total",
55                "Executions completed",
56                self.executions_completed,
57            ),
58            (
59                "orbit_executions_failed_total",
60                "Executions failed",
61                self.executions_failed,
62            ),
63            (
64                "orbit_executions_cancelled_total",
65                "Executions cancelled",
66                self.executions_cancelled,
67            ),
68            (
69                "orbit_executions_timed_out_total",
70                "Executions timed out",
71                self.executions_timed_out,
72            ),
73            (
74                "orbit_tasks_dispatched_total",
75                "Task attempts dispatched",
76                self.tasks_dispatched,
77            ),
78            (
79                "orbit_tasks_succeeded_total",
80                "Task attempts succeeded",
81                self.tasks_succeeded,
82            ),
83            (
84                "orbit_task_attempts_failed_total",
85                "Task attempts failed",
86                self.task_attempts_failed,
87            ),
88            (
89                "orbit_task_attempts_uncertain_total",
90                "Task attempts with unknown outcome",
91                self.task_attempts_uncertain,
92            ),
93            (
94                "orbit_retries_scheduled_total",
95                "Retries scheduled",
96                self.retries_scheduled,
97            ),
98            (
99                "orbit_steps_skipped_total",
100                "Steps skipped by conditions",
101                self.steps_skipped,
102            ),
103            (
104                "orbit_stale_results_total",
105                "Duplicate or late results ignored",
106                self.stale_results,
107            ),
108            (
109                "orbit_compensations_started_total",
110                "Compensations started",
111                self.compensations_started,
112            ),
113            (
114                "orbit_compensations_failed_total",
115                "Compensations failed",
116                self.compensations_failed,
117            ),
118            (
119                "orbit_events_committed_total",
120                "History events committed",
121                self.events_committed,
122            ),
123        ];
124        let mut out = String::new();
125        for (name, help, value) in counters {
126            out.push_str(&format!(
127                "# HELP {name} {help}\n# TYPE {name} counter\n{name} {value}\n"
128            ));
129        }
130        out.push_str(&format!(
131            "# HELP orbit_active_executions Executions not yet finished\n# TYPE orbit_active_executions gauge\norbit_active_executions {active}\n"
132        ));
133        out.push_str(&format!(
134            "# HELP orbit_worker_sessions Registered worker sessions\n# TYPE orbit_worker_sessions gauge\norbit_worker_sessions {sessions}\n"
135        ));
136        out
137    }
138}