saluki_core/data_model/event/service_check/
mod.rs1use saluki_common::iter::ReusableDeduplicator;
4use serde::{ser::SerializeMap as _, Serialize, Serializer};
5use stringtheory::MetaString;
6
7use crate::data_model::tags::TagSet;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum CheckStatus {
12 Ok,
14
15 Warning,
17
18 Critical,
20
21 Unknown,
23}
24
25#[derive(Clone, Debug, PartialEq)]
30pub struct ServiceCheck {
31 name: MetaString,
32 status: CheckStatus,
33 timestamp: Option<u64>,
34 hostname: MetaString,
35 message: MetaString,
36 tags: TagSet,
37 origin_tags: TagSet,
38}
39
40impl ServiceCheck {
41 pub fn name(&self) -> &str {
43 &self.name
44 }
45
46 pub fn status(&self) -> CheckStatus {
48 self.status
49 }
50
51 pub fn timestamp(&self) -> Option<u64> {
55 self.timestamp
56 }
57
58 pub fn hostname(&self) -> Option<&str> {
60 if self.hostname.is_empty() {
61 None
62 } else {
63 Some(&self.hostname)
64 }
65 }
66
67 pub fn message(&self) -> Option<&str> {
69 if self.message.is_empty() {
70 None
71 } else {
72 Some(&self.message)
73 }
74 }
75
76 pub fn tags(&self) -> &TagSet {
78 &self.tags
79 }
80
81 pub fn origin_tags(&self) -> &TagSet {
83 &self.origin_tags
84 }
85
86 pub fn new(name: impl Into<MetaString>, status: CheckStatus) -> Self {
88 Self {
89 name: name.into(),
90 status,
91 timestamp: None,
92 hostname: MetaString::empty(),
93 message: MetaString::empty(),
94 tags: TagSet::default(),
95 origin_tags: TagSet::default(),
96 }
97 }
98
99 pub fn with_timestamp(mut self, timestamp: impl Into<Option<u64>>) -> Self {
105 self.timestamp = timestamp.into();
106 self
107 }
108
109 pub fn with_hostname(mut self, hostname: impl Into<Option<MetaString>>) -> Self {
113 self.hostname = match hostname.into() {
114 Some(hostname) => hostname,
115 None => MetaString::empty(),
116 };
117 self
118 }
119
120 pub fn set_hostname(&mut self, hostname: impl Into<Option<MetaString>>) {
122 self.hostname = match hostname.into() {
123 Some(hostname) => hostname,
124 None => MetaString::empty(),
125 };
126 }
127
128 pub fn with_tags(mut self, tags: impl Into<TagSet>) -> Self {
132 self.tags = tags.into();
133 self
134 }
135
136 pub fn with_message(mut self, message: impl Into<Option<MetaString>>) -> Self {
140 self.message = match message.into() {
141 Some(message) => message,
142 None => MetaString::empty(),
143 };
144 self
145 }
146
147 pub fn with_origin_tags(mut self, origin_tags: impl Into<TagSet>) -> Self {
151 self.origin_tags = origin_tags.into();
152 self
153 }
154}
155
156impl Serialize for ServiceCheck {
157 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
158 where
159 S: Serializer,
160 {
161 let mut map = serializer.serialize_map(None)?;
162 map.serialize_entry("check", &self.name)?;
163 if !self.hostname.is_empty() {
164 map.serialize_entry("host_name", &self.hostname)?;
165 }
166 if !self.message.is_empty() {
167 map.serialize_entry("message", &self.message)?;
168 }
169 map.serialize_entry("status", &self.status)?;
170
171 let tags = DeduplicatedTagsSerializable {
172 tags: &self.tags,
173 origin_tags: &self.origin_tags,
174 };
175 map.serialize_entry("tags", &tags)?;
176
177 if let Some(timestamp) = self.timestamp.as_ref() {
178 map.serialize_entry("timestamp", timestamp)?;
179 }
180 map.end()
181 }
182}
183
184impl CheckStatus {
185 pub const fn as_u8(&self) -> u8 {
187 match self {
188 Self::Ok => 0,
189 Self::Warning => 1,
190 Self::Critical => 2,
191 Self::Unknown => 3,
192 }
193 }
194}
195
196impl Serialize for CheckStatus {
197 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
198 where
199 S: Serializer,
200 {
201 serializer.serialize_u8(self.as_u8())
202 }
203}
204
205#[derive(Debug, Clone)]
207pub struct ParseCheckStatusError;
208
209impl std::fmt::Display for ParseCheckStatusError {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 write!(f, "invalid check status")
212 }
213}
214
215impl std::error::Error for ParseCheckStatusError {}
216
217impl TryFrom<u8> for CheckStatus {
218 type Error = ParseCheckStatusError;
219
220 fn try_from(value: u8) -> Result<Self, Self::Error> {
221 match value {
222 0 => Ok(Self::Ok),
223 1 => Ok(Self::Warning),
224 2 => Ok(Self::Critical),
225 3 => Ok(Self::Unknown),
226 _ => Err(ParseCheckStatusError),
227 }
228 }
229}
230
231struct DeduplicatedTagsSerializable<'a> {
233 tags: &'a TagSet,
234 origin_tags: &'a TagSet,
235}
236
237impl<'a> Serialize for DeduplicatedTagsSerializable<'a> {
238 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
239 where
240 S: Serializer,
241 {
242 let chained_tags = self.tags.into_iter().chain(self.origin_tags);
243
244 let mut tags_deduplicator = ReusableDeduplicator::new();
245 let deduplicated_tags = tags_deduplicator.deduplicated(chained_tags);
246 serializer.collect_seq(deduplicated_tags)
247 }
248}