saluki_core/data_model/event/service_check/
mod.rs1use saluki_common::iter::ReusableDeduplicator;
4use saluki_context::tags::SharedTagSet;
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: SharedTagSet,
36 origin_tags: SharedTagSet,
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) -> &SharedTagSet {
77 &self.tags
78 }
79
80 pub fn origin_tags(&self) -> &SharedTagSet {
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: SharedTagSet::default(),
94 origin_tags: SharedTagSet::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 with_tags(mut self, tags: impl Into<SharedTagSet>) -> Self {
123 self.tags = tags.into();
124 self
125 }
126
127 pub fn with_message(mut self, message: impl Into<Option<MetaString>>) -> Self {
131 self.message = match message.into() {
132 Some(message) => message,
133 None => MetaString::empty(),
134 };
135 self
136 }
137
138 pub fn with_origin_tags(mut self, origin_tags: SharedTagSet) -> Self {
142 self.origin_tags = origin_tags;
143 self
144 }
145}
146
147impl Serialize for ServiceCheck {
148 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149 where
150 S: Serializer,
151 {
152 let mut map = serializer.serialize_map(None)?;
153 map.serialize_entry("check", &self.name)?;
154 if !self.hostname.is_empty() {
155 map.serialize_entry("host_name", &self.hostname)?;
156 }
157 if !self.message.is_empty() {
158 map.serialize_entry("message", &self.message)?;
159 }
160 map.serialize_entry("status", &self.status)?;
161
162 let tags = DeduplicatedTagsSerializable {
163 tags: &self.tags,
164 origin_tags: &self.origin_tags,
165 };
166 map.serialize_entry("tags", &tags)?;
167
168 if let Some(timestamp) = self.timestamp.as_ref() {
169 map.serialize_entry("timestamp", timestamp)?;
170 }
171 map.end()
172 }
173}
174
175impl CheckStatus {
176 pub const fn as_u8(&self) -> u8 {
178 match self {
179 Self::Ok => 0,
180 Self::Warning => 1,
181 Self::Critical => 2,
182 Self::Unknown => 3,
183 }
184 }
185}
186
187impl Serialize for CheckStatus {
188 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
189 where
190 S: Serializer,
191 {
192 serializer.serialize_u8(self.as_u8())
193 }
194}
195
196#[derive(Debug, Clone)]
198pub struct ParseCheckStatusError;
199
200impl std::fmt::Display for ParseCheckStatusError {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 write!(f, "invalid check status")
203 }
204}
205
206impl std::error::Error for ParseCheckStatusError {}
207
208impl TryFrom<u8> for CheckStatus {
209 type Error = ParseCheckStatusError;
210
211 fn try_from(value: u8) -> Result<Self, Self::Error> {
212 match value {
213 0 => Ok(Self::Ok),
214 1 => Ok(Self::Warning),
215 2 => Ok(Self::Critical),
216 3 => Ok(Self::Unknown),
217 _ => Err(ParseCheckStatusError),
218 }
219 }
220}
221
222struct DeduplicatedTagsSerializable<'a> {
224 tags: &'a SharedTagSet,
225 origin_tags: &'a SharedTagSet,
226}
227
228impl<'a> Serialize for DeduplicatedTagsSerializable<'a> {
229 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
230 where
231 S: Serializer,
232 {
233 let chained_tags = self.tags.into_iter().chain(self.origin_tags);
234
235 let mut tags_deduplicator = ReusableDeduplicator::new();
236 let deduplicated_tags = tags_deduplicator.deduplicated(chained_tags);
237 serializer.collect_seq(deduplicated_tags)
238 }
239}