From c39852f6a15c74395757ed591dcd1047f1c69721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teo=20Klestrup=20R=C3=B6ijezon?= Date: Fri, 18 Feb 2022 12:03:42 +0100 Subject: [PATCH 1/4] Truncate K8s event message if it is too long --- src/logging/k8s_events.rs | 65 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/logging/k8s_events.rs b/src/logging/k8s_events.rs index 74d380776..20ffd3d32 100644 --- a/src/logging/k8s_events.rs +++ b/src/logging/k8s_events.rs @@ -14,7 +14,7 @@ use super::controller::ReconcilerError; /// Converts an [`Error`] into a publishable Kubernetes [`Event`] fn error_to_event(err: &E) -> Event { // Walk the whole error chain, so that we get all the full reason for the error - let full_msg = { + let mut full_msg = { use std::fmt::Write; let mut buf = err.to_string(); let mut err: &dyn Error = err; @@ -28,6 +28,7 @@ fn error_to_event(err: &E) -> Event { } } }; + message::truncate_with_ellipsis(&mut full_msg, 1024); Event { type_: EventType::Warning, reason: err.category().to_string(), @@ -77,6 +78,68 @@ pub fn publish_controller_error_as_k8s_event( ); } +mod message { + pub fn truncate_with_ellipsis(msg: &mut String, max_len: usize) { + const ELLIPSIS: char = '…'; + const ELLIPSIS_LEN: usize = ELLIPSIS.len_utf8(); + let len = msg.len(); + if len > max_len { + msg.truncate(find_start_of_char(msg, len - ELLIPSIS_LEN)); + msg.push(ELLIPSIS); + } + } + + fn find_start_of_char(s: &str, mut pos: usize) -> usize { + loop { + if s.is_char_boundary(pos) { + break pos; + } + pos -= 1; + } + } + + #[cfg(test)] + mod tests { + use crate::logging::k8s_events::message::find_start_of_char; + + use super::truncate_with_ellipsis; + + #[test] + fn truncate_should_be_noop_if_string_fits() { + let mut x = "hello".to_string(); + truncate_with_ellipsis(&mut x, 5); + assert_eq!(&x, "hello"); + } + + #[test] + fn truncate_should_ellipsize_large_string() { + let mut x = "hello".to_string(); + truncate_with_ellipsis(&mut x, 4); + assert_eq!(&x, "he…"); + } + + #[test] + fn truncate_should_ellipsize_emoji() { + let mut x = "hello🙋".to_string(); + truncate_with_ellipsis(&mut x, 8); + assert_eq!(&x, "hello…"); + } + + #[test] + fn find_start_of_char_should_be_noop_for_ascii() { + assert_eq!(find_start_of_char("hello", 2 /* l */), 2); + } + + #[test] + fn find_start_of_char_should_find_start_of_emoji() { + assert_eq!( + find_start_of_char("hello🙋", 7 /* in the middle of the emoji */), + 5 + ); + } + } +} + #[cfg(test)] mod tests { use k8s_openapi::api::core::v1::ConfigMap; From f83229ad59bff10d283686734a4ec6b3c1511c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teo=20Klestrup=20R=C3=B6ijezon?= Date: Fri, 18 Feb 2022 12:08:27 +0100 Subject: [PATCH 2/4] Document `truncate_with_ellipsis` --- src/logging/k8s_events.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/logging/k8s_events.rs b/src/logging/k8s_events.rs index 20ffd3d32..be92eedd3 100644 --- a/src/logging/k8s_events.rs +++ b/src/logging/k8s_events.rs @@ -79,6 +79,9 @@ pub fn publish_controller_error_as_k8s_event( } mod message { + /// Ensures that `msg` is at most `max_len` _bytes_ long + /// + /// If `msg` is longer than `max_len` then the extra text is replaced with an ellipsis. pub fn truncate_with_ellipsis(msg: &mut String, max_len: usize) { const ELLIPSIS: char = '…'; const ELLIPSIS_LEN: usize = ELLIPSIS.len_utf8(); From 0d1ae86b3c5967e1fbbfbdc0f45e5188e0c3955b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teo=20Klestrup=20R=C3=B6ijezon?= Date: Fri, 18 Feb 2022 12:09:34 +0100 Subject: [PATCH 3/4] Don't panic if there is no room for an ellipsis --- src/logging/k8s_events.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/logging/k8s_events.rs b/src/logging/k8s_events.rs index be92eedd3..c55b7f870 100644 --- a/src/logging/k8s_events.rs +++ b/src/logging/k8s_events.rs @@ -87,8 +87,10 @@ mod message { const ELLIPSIS_LEN: usize = ELLIPSIS.len_utf8(); let len = msg.len(); if len > max_len { - msg.truncate(find_start_of_char(msg, len - ELLIPSIS_LEN)); - msg.push(ELLIPSIS); + msg.truncate(find_start_of_char(msg, len.saturating_sub(ELLIPSIS_LEN))); + if ELLIPSIS_LEN <= max_len { + msg.push(ELLIPSIS); + } } } From be0c39abac7ecb994493b76c23d27fb0f999b0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teo=20Klestrup=20R=C3=B6ijezon?= Date: Fri, 18 Feb 2022 12:10:17 +0100 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f57b6a55d..171cf9bc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,15 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed +- Reported K8s events are now limited to 1024 bytes ([#327]). + ### Removed - `Client::set_condition` ([#326]). - `Error` variants that are no longer used ([#326]). [#326]: https://github.com/stackabletech/operator-rs/pull/326 +[#327]: https://github.com/stackabletech/operator-rs/pull/327 ## [0.11.0] - 2022-02-17