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