1use 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}