mz_orchestrator_kubernetes/
metrics.rs1use std::error::Error;
13use std::io;
14
15use kube::error::Error as K8sError;
16use mz_ore::metric;
17use mz_ore::metrics::MetricsRegistry;
18use mz_ore::metrics::raw::IntCounterVec;
19
20#[derive(Debug, Clone)]
22pub(crate) struct OrchestratorMetrics {
23 process_metrics_fetch_failures: IntCounterVec,
24}
25
26#[derive(Debug, Clone, Copy)]
28pub(crate) enum FetchStep {
29 PodMetrics,
31 ClusterdUsage,
33}
34
35impl FetchStep {
36 fn as_str(&self) -> &'static str {
37 match self {
38 FetchStep::PodMetrics => "pod_metrics",
39 FetchStep::ClusterdUsage => "clusterd_usage",
40 }
41 }
42}
43
44impl OrchestratorMetrics {
45 pub(crate) fn register_into(registry: &MetricsRegistry) -> Self {
46 Self {
47 process_metrics_fetch_failures: registry.register(metric!(
48 name: "mz_orchestrator_kubernetes_process_metrics_fetch_failures_total",
49 help: "The number of failed per-process metrics fetches, by fetch step and error kind.",
50 var_labels: ["step", "kind"],
51 )),
52 }
53 }
54
55 pub(crate) fn record_fetch_failure(&self, step: FetchStep, kind: &str) {
57 self.process_metrics_fetch_failures
58 .with_label_values(&[step.as_str(), kind])
59 .inc();
60 }
61
62 pub(crate) fn record_fetch_error(&self, step: FetchStep, error: &(dyn Error + 'static)) {
64 self.record_fetch_failure(step, error_kind(error));
65 }
66}
67
68pub(crate) fn error_kind(error: &(dyn Error + 'static)) -> &'static str {
75 let mut kind = None;
76 let mut next = Some(error);
77 while let Some(err) = next {
78 next = err.source();
79 if let Some(e) = err.downcast_ref::<io::Error>() {
80 if e.kind() == io::ErrorKind::TimedOut {
81 return "timeout";
82 }
83 } else if let Some(e) = err.downcast_ref::<reqwest::Error>() {
84 if e.is_timeout() {
85 return "timeout";
86 }
87 kind.get_or_insert_with(|| if e.is_decode() { "decode" } else { "transport" });
88 } else if let Some(e) = err.downcast_ref::<K8sError>() {
89 kind.get_or_insert(match e {
90 K8sError::Api(_) => "api",
91 K8sError::SerdeError(_) => "decode",
92 K8sError::HyperError(_) | K8sError::Service(_) => "transport",
93 _ => "other",
94 });
95 }
96 }
97 kind.unwrap_or("other")
98}
99
100#[cfg(test)]
101mod tests;