From 27c2844fecb382a2d741572a100baf7d08cba043 Mon Sep 17 00:00:00 2001 From: Oleksii Kuripko Date: Tue, 21 Apr 2026 18:53:06 +0200 Subject: [PATCH] linkify URL for 'request: Connect to failed' error variant Spring wraps Apache HttpClient connect failures as 'I/O error on POST request: Connect to failed: '. Same treatment as the RestClient variant: the URL is embedded in the 'request' word and the 'Connect to ... failed' restatement is dropped from the visible text. --- .../ServiceFailureNotification.java | 19 +++++++++++++------ .../ServiceFailureNotificationTest.java | 12 ++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/monitoring/src/main/java/org/thingsboard/monitoring/data/notification/ServiceFailureNotification.java b/monitoring/src/main/java/org/thingsboard/monitoring/data/notification/ServiceFailureNotification.java index 5fcc953cce..69e336f334 100644 --- a/monitoring/src/main/java/org/thingsboard/monitoring/data/notification/ServiceFailureNotification.java +++ b/monitoring/src/main/java/org/thingsboard/monitoring/data/notification/ServiceFailureNotification.java @@ -52,18 +52,25 @@ public class ServiceFailureNotification implements Notification { return String.format("%s - Failure: %s (number of subsequent failures: %s)", serviceKey, errorMsg, failuresCount); } - private static final Pattern REQUEST_URL_PATTERN = Pattern.compile("request for \"(https?://[^\"\\s]+)\""); + // Spring RestClient: '... request for ""' + private static final Pattern REQUEST_FOR_URL_PATTERN = Pattern.compile("request for \"(https?://[^\"\\s]+)\""); + // Apache HttpClient wrapped by Spring: 'I/O error on POST request: Connect to failed: ' + private static final Pattern REQUEST_CONNECT_PATTERN = Pattern.compile("request: Connect to (https?://\\S+?) failed:"); static String linkifyRequestUrl(String msg) { if (msg == null) { return null; } - Matcher m = REQUEST_URL_PATTERN.matcher(msg); - if (!m.find()) { - return msg; - } // Slack mrkdwn link: - return m.replaceAll("<$1|request>"); + Matcher m = REQUEST_FOR_URL_PATTERN.matcher(msg); + if (m.find()) { + return m.replaceAll("<$1|request>"); + } + Matcher m2 = REQUEST_CONNECT_PATTERN.matcher(msg); + if (m2.find()) { + return m2.replaceAll("<$1|request>:"); + } + return msg; } static String stripResponseBody(String msg) { diff --git a/monitoring/src/test/java/org/thingsboard/monitoring/data/notification/ServiceFailureNotificationTest.java b/monitoring/src/test/java/org/thingsboard/monitoring/data/notification/ServiceFailureNotificationTest.java index 7f66a456fe..500a713f7b 100644 --- a/monitoring/src/test/java/org/thingsboard/monitoring/data/notification/ServiceFailureNotificationTest.java +++ b/monitoring/src/test/java/org/thingsboard/monitoring/data/notification/ServiceFailureNotificationTest.java @@ -55,10 +55,18 @@ class ServiceFailureNotificationTest { @Test void linkifyReplacesRequestForUrlWithSlackMrkdwnLink() { - String msg = "503 Service Temporarily Unavailable on POST request for \"https://qa-tb-pe-lts43.iot-private.cloud/api/auth/login\""; + String msg = "503 Service Temporarily Unavailable on POST request for \"https://example.com/api/auth/login\""; assertThat(ServiceFailureNotification.linkifyRequestUrl(msg)) - .isEqualTo("503 Service Temporarily Unavailable on POST "); + .isEqualTo("503 Service Temporarily Unavailable on POST "); + } + + @Test + void linkifyReplacesRequestConnectToUrlFailed() { + String msg = "I/O error on POST request: Connect to https://example.com:443 failed: Connect timed out"; + + assertThat(ServiceFailureNotification.linkifyRequestUrl(msg)) + .isEqualTo("I/O error on POST : Connect timed out"); } @Test