mprobe_diagnostics/
error.rs

1//! Defines the `Error` types that this crate uses.
2
3use std::convert::From;
4use std::error::Error;
5use std::fmt;
6use std::fmt::Display;
7use std::fmt::Formatter;
8use std::io;
9use std::num::TryFromIntError;
10use std::sync::Arc;
11
12use bson::de;
13use bson::document::ValueAccessError;
14
15/// The error type for parsing diagnostic metrics.
16///
17/// Errors mostly originate from I/O read operations, BSON deserialization,
18/// and field value accesses.
19#[derive(Debug, Clone)]
20pub enum MetricParseError {
21    /// A [std::io::Error] encountered while reading diagnostic metrics.
22    Io(Arc<io::Error>),
23
24    /// A [bson::de::Error] encountered while deserializing BSON documents.
25    BsonDeserialzation(de::Error),
26
27    /// A [KeyAccessError] encountered while accessing BSON fields.
28    FieldAccess(KeyAccessError),
29
30    /// Unknown BSON document read from the diagnostic metrics.
31    UnknownDocumentKind(i32),
32
33    /// The amount of metrics in the reference document is different
34    /// than the amount of metric samples.
35    MetricCountMismatch,
36
37    /// The timestamp for the given metric is missing.
38    MetricTimestampNotFound {
39        /// Metric name
40        name: Arc<str>,
41    },
42
43    /// A [TryFromIntError] encountered while converting integer values from [i32] to
44    /// [usize].
45    IntConversion(TryFromIntError),
46}
47
48impl Display for MetricParseError {
49    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
50        let parse_error = "metric parse error:";
51
52        match self {
53            MetricParseError::Io(error) => write!(f, "{parse_error} I/O error: {error}"),
54            MetricParseError::BsonDeserialzation(error) => {
55                write!(f, "{parse_error} BSON deserialization error: {error}")
56            }
57            MetricParseError::FieldAccess(error) => write!(
58                f,
59                "{parse_error} could not read the document field: {error}"
60            ),
61            MetricParseError::MetricCountMismatch => write!(
62                f,
63                "{parse_error} the amount of metrics in the reference document is different than the amount of metric samples"
64            ),
65            MetricParseError::MetricTimestampNotFound { name } => write!(
66                f,
67                "{parse_error} the metric timestamps for the {name} metric could not be found",
68            ),
69            MetricParseError::IntConversion(error) => {
70                write!(f, "{parse_error} could not parse integer: {error}")
71            }
72            MetricParseError::UnknownDocumentKind(value) => {
73                write!(f, "{parse_error} unknonw document type: {value}")
74            }
75        }
76    }
77}
78
79impl Error for MetricParseError {
80    fn source(&self) -> Option<&(dyn Error + 'static)> {
81        match self {
82            MetricParseError::Io(error) => Some(error),
83            MetricParseError::BsonDeserialzation(error) => Some(error),
84            MetricParseError::FieldAccess(error) => Some(error),
85            MetricParseError::MetricCountMismatch => None,
86            MetricParseError::MetricTimestampNotFound { .. } => None,
87            MetricParseError::IntConversion(error) => Some(error),
88            MetricParseError::UnknownDocumentKind(_) => None,
89        }
90    }
91}
92
93impl From<io::Error> for MetricParseError {
94    fn from(error: io::Error) -> Self {
95        MetricParseError::Io(Arc::new(error))
96    }
97}
98
99impl From<de::Error> for MetricParseError {
100    fn from(error: de::Error) -> Self {
101        MetricParseError::BsonDeserialzation(error)
102    }
103}
104
105impl From<TryFromIntError> for MetricParseError {
106    fn from(error: TryFromIntError) -> Self {
107        MetricParseError::IntConversion(error)
108    }
109}
110
111impl From<KeyAccessError> for MetricParseError {
112    fn from(error: KeyAccessError) -> Self {
113        MetricParseError::FieldAccess(error)
114    }
115}
116
117/// The error type for accessing BSON fields.
118#[derive(Debug, Clone)]
119pub enum KeyAccessError {
120    /// Could not find the field with the specified key.
121    KeyNotFound {
122        /// Key field name.
123        key: String,
124    },
125
126    /// The field with the specified key was found, but not with the expected type.
127    UnexpectedKeyType {
128        /// Key field name.
129        key: String,
130    },
131
132    /// Could not access field value with the specified key due to an unknown error.
133    AccessError {
134        /// Key field name.
135        key: String,
136
137        /// Underlying error message.
138        error: String,
139    },
140}
141
142impl Display for KeyAccessError {
143    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
144        let key_access_error = "key access error:";
145        match *self {
146            KeyAccessError::KeyNotFound { ref key } => {
147                write!(
148                    f,
149                    "{key_access_error} could not find the field with the {key} key",
150                )
151            }
152            KeyAccessError::UnexpectedKeyType { ref key } => write!(
153                f,
154                "{key_access_error} the field with {key} key was found, but not with the expected type",
155            ),
156            KeyAccessError::AccessError { ref key, ref error } => {
157                write!(
158                    f,
159                    "{key_access_error} could not access the field value with the {key} key. {error}",
160                )
161            }
162        }
163    }
164}
165
166impl Error for KeyAccessError {}
167
168pub(crate) trait ValueAccessResultExt<T> {
169    fn map_value_access_err(self, key: &str) -> Result<T, KeyAccessError>;
170}
171
172impl<T> ValueAccessResultExt<T> for Result<T, ValueAccessError> {
173    fn map_value_access_err(self, key: &str) -> Result<T, KeyAccessError> {
174        self.map_err(|error| match error {
175            ValueAccessError::NotPresent => KeyAccessError::KeyNotFound {
176                key: key.to_owned(),
177            },
178            ValueAccessError::UnexpectedType => KeyAccessError::UnexpectedKeyType {
179                key: key.to_owned(),
180            },
181            e => KeyAccessError::AccessError {
182                key: key.to_owned(),
183                error: e.to_string(),
184            },
185        })
186    }
187}