add status code

This commit is contained in:
Brandon Thomas committed 2026-03-30 21:22:11 -04:00
1 parent 0c783e25fb
commit bef1dc6b95
4 files changed
+108 -16

No files matched your search

+10 -2
View File
@@ -116,10 +116,14 @@ impl PagerClient {
labels.push(("http_method".to_string(), method.clone()));
}
if let Some(path) = &notification.endpoint_path {
if let Some(path) = &notification.http_path {
labels.push(("http_path".to_string(), path.clone()));
}
if let Some(status_code) = notification.http_status_code {
labels.push(("http_status_code".to_string(), status_code.to_string()));
}
let labels = if labels.is_empty() { None } else { Some(labels) };
// Enrich the description with HTTP context and hostname if present.
@@ -131,10 +135,14 @@ impl PagerClient {
parts.push(format!("HTTP Method: {}", method));
}
if let Some(path) = &notification.endpoint_path {
if let Some(path) = &notification.http_path {
parts.push(format!("HTTP Path: {}", path));
}
if let Some(status_code) = notification.http_status_code {
parts.push(format!("HTTP Status Code: {}", status_code));
}
if let Some(h) = &self.hostname {
parts.push(format!("Hostname: {}", h));
}
@@ -23,11 +23,15 @@ pub(crate) fn generate_deduplication_key(details: &NotificationDetails) -> Strin
hasher.update(details.summary.as_bytes());
hasher.update(if details.is_from_error { b"1" } else { b"0" });
if let (Some(method), Some(path)) = (&details.http_method, &details.endpoint_path) {
if let (Some(method), Some(path)) = (&details.http_method, &details.http_path) {
hasher.update(method.as_bytes());
hasher.update(path.as_bytes());
}
if let Some(status_code) = details.http_status_code {
hasher.update(status_code.to_le_bytes());
}
hasher.update(hours_since_epoch(details.event_time).to_le_bytes());
let result = hasher.finalize();
@@ -43,7 +47,7 @@ mod tests {
summary: &str,
is_from_error: bool,
http_method: Option<&str>,
endpoint_path: Option<&str>,
http_path: Option<&str>,
event_time: DateTime<Utc>,
) -> NotificationDetails {
NotificationDetails {
@@ -51,7 +55,8 @@ mod tests {
description: None,
event_time,
http_method: http_method.map(|s| s.to_string()),
endpoint_path: endpoint_path.map(|s| s.to_string()),
http_path: http_path.map(|s| s.to_string()),
http_status_code: None,
is_from_error,
}
}
@@ -188,6 +193,70 @@ mod tests {
}
}
mod http_status_code_tests {
use super::*;
fn make_details_with_status(
summary: &str,
is_from_error: bool,
http_method: Option<&str>,
http_path: Option<&str>,
http_status_code: Option<u16>,
event_time: DateTime<Utc>,
) -> NotificationDetails {
NotificationDetails {
summary: summary.to_string(),
description: None,
event_time,
http_method: http_method.map(|s| s.to_string()),
http_path: http_path.map(|s| s.to_string()),
http_status_code,
is_from_error,
}
}
#[test]
fn different_status_code_different_key() {
let time = Utc.with_ymd_and_hms(2026, 3, 30, 14, 0, 0).unwrap();
let a = make_details_with_status("db error", true, Some("POST"), Some("/v1/jobs"), Some(500), time);
let b = make_details_with_status("db error", true, Some("POST"), Some("/v1/jobs"), Some(503), time);
assert_ne!(generate_deduplication_key(&a), generate_deduplication_key(&b));
}
#[test]
fn status_code_vs_none_different_key() {
let time = Utc.with_ymd_and_hms(2026, 3, 30, 14, 0, 0).unwrap();
let a = make_details_with_status("db error", true, Some("POST"), Some("/v1/jobs"), Some(500), time);
let b = make_details_with_status("db error", true, Some("POST"), Some("/v1/jobs"), None, time);
assert_ne!(generate_deduplication_key(&a), generate_deduplication_key(&b));
}
#[test]
fn same_status_code_same_key() {
let t1 = Utc.with_ymd_and_hms(2026, 3, 30, 14, 0, 0).unwrap();
let t2 = Utc.with_ymd_and_hms(2026, 3, 30, 14, 30, 0).unwrap();
let a = make_details_with_status("timeout", true, Some("GET"), Some("/v1/users"), Some(504), t1);
let b = make_details_with_status("timeout", true, Some("GET"), Some("/v1/users"), Some(504), t2);
assert_eq!(generate_deduplication_key(&a), generate_deduplication_key(&b));
}
#[test]
fn status_code_without_http_fields_still_differentiates() {
let time = Utc.with_ymd_and_hms(2026, 3, 30, 14, 0, 0).unwrap();
let a = make_details_with_status("error", true, None, None, Some(500), time);
let b = make_details_with_status("error", true, None, None, Some(502), time);
assert_ne!(generate_deduplication_key(&a), generate_deduplication_key(&b));
}
}
mod other_behaviors {
use super::*;
#[test]
@@ -18,8 +18,11 @@ pub struct NotificationDetails {
/// HTTP method associated with the event, if any.
pub http_method: Option<String>,
/// Endpoint path associated with the event, if any.
pub endpoint_path: Option<String>,
/// HTTP endpoint path associated with the event, if any.
pub http_path: Option<String>,
/// HTTP status code associated with the event, if any.
pub http_status_code: Option<u16>,
/// Whether this notification originated from an error.
pub is_from_error: bool,
@@ -37,7 +40,8 @@ impl NotificationDetails {
description: Some(description),
event_time: Utc::now(),
http_method: None,
endpoint_path: None,
http_path: None,
http_status_code: None,
is_from_error: false,
}
}
@@ -49,7 +53,8 @@ impl NotificationDetails {
description: None,
event_time: Utc::now(),
http_method: None,
endpoint_path: None,
http_path: None,
http_status_code: None,
is_from_error: false,
}
}
@@ -108,7 +113,8 @@ impl NotificationDetails {
description: Some(description),
event_time,
http_method: None,
endpoint_path: None,
http_path: None,
http_status_code: None,
is_from_error: true,
}
}
@@ -8,7 +8,8 @@ pub struct NotificationDetailsBuilder {
description: Option<String>,
event_time: DateTime<Utc>,
http_method: Option<String>,
endpoint_path: Option<String>,
http_path: Option<String>,
http_status_code: Option<u16>,
is_from_error: bool,
}
@@ -20,7 +21,8 @@ impl NotificationDetailsBuilder {
description: None,
event_time: Utc::now(),
http_method: None,
endpoint_path: None,
http_path: None,
http_status_code: None,
is_from_error: false,
}
}
@@ -37,7 +39,8 @@ impl NotificationDetailsBuilder {
description: details.description,
event_time: details.event_time,
http_method: None,
endpoint_path: None,
http_path: None,
http_status_code: None,
is_from_error: true,
}
}
@@ -52,8 +55,13 @@ impl NotificationDetailsBuilder {
self
}
pub fn set_endpoint_path(mut self, endpoint_path: Option<String>) -> Self {
self.endpoint_path = endpoint_path;
pub fn set_http_path(mut self, http_path: Option<String>) -> Self {
self.http_path = http_path;
self
}
pub fn set_http_status_code(mut self, http_status_code: Option<u16>) -> Self {
self.http_status_code = http_status_code;
self
}
@@ -63,7 +71,8 @@ impl NotificationDetailsBuilder {
description: self.description,
event_time: self.event_time,
http_method: self.http_method,
endpoint_path: self.endpoint_path,
http_path: self.http_path,
http_status_code: self.http_status_code,
is_from_error: self.is_from_error,
}
}