Improvements for transports monitoring; remove UI healthchecker

This commit is contained in:
ViacheslavKlimov 2023-01-08 17:00:17 +02:00
parent 7eff0fc346
commit 1ffc8107d5
9 changed files with 28 additions and 144 deletions

View File

@ -21,12 +21,11 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.2-SNAPSHOT</version>
<version>3.4.3-SNAPSHOT</version>
<artifactId>thingsboard</artifactId>
</parent>
<artifactId>monitoring</artifactId>
<version>3.4.2-SNAPSHOT</version>
<name>ThingsBoard Monitoring Service</name>
<packaging>jar</packaging>
@ -96,20 +95,9 @@
<artifactId>Java-WebSocket</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.6.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>

View File

@ -14,9 +14,9 @@
# limitations under the License.
#
export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=@pkg.logFolder@/gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/tb-monitoring/gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError"
export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10"
export LOG_FILENAME=${pkg.name}.out
export LOADER_PATH=${pkg.installFolder}/conf
export LOG_FILENAME=tb-monitoring.out
export LOADER_PATH=/usr/share/tb-monitoring/conf

View File

@ -36,6 +36,10 @@ public class Latency {
return latencySum.get() / counter.get();
}
public boolean isNotEmpty() {
return counter.get() > 0;
}
public synchronized void reset() {
latencySum.set(0.0);
counter.set(0);

View File

@ -73,7 +73,9 @@ public class MonitoringReporter {
return;
}
log.info("Latencies:\n{}", latencies.values());
if (latencies.values().stream().anyMatch(latency -> latency.getAvg() >= (double) latencyThresholdMs)) {
if (latencies.values().stream()
.filter(Latency::isNotEmpty)
.anyMatch(latency -> latency.getAvg() >= (double) latencyThresholdMs)) {
HighLatencyNotification highLatencyNotification = new HighLatencyNotification(latencies.values(), latencyThresholdMs);
notificationService.sendNotification(highLatencyNotification);
}
@ -89,9 +91,11 @@ public class MonitoringReporter {
tbClient.logIn();
ObjectNode msg = JacksonUtil.newObjectNode();
latencies.forEach((key, latency) -> {
msg.set(key, new DoubleNode(latency.getAvg()));
if (latency.isNotEmpty()) {
msg.set(key, new DoubleNode(latency.getAvg()));
latency.reset();
}
});
latencies.clear();
tbClient.saveEntityTelemetry(entityId, "time", msg);
} catch (Exception e) {
log.error("Failed to report latencies: {}", e.getMessage());

View File

@ -143,7 +143,7 @@ public abstract class TransportMonitoringService<C extends TransportMonitoringSe
wsClient.waitForUpdate(wsConfig.getResultCheckTimeoutMs());
Object update = wsClient.getTelemetryKeyUpdate(TEST_TELEMETRY_KEY);
if (update == null) {
throw new TransportFailureException("No WS update arrived");
throw new TransportFailureException("No WS update arrived within " + wsConfig.getResultCheckTimeoutMs() + " ms");
} else if (!update.toString().equals(testValue)) {
throw new TransportFailureException("Was expecting value " + testValue + " but got " + update);
}

View File

@ -1,113 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.monitoring.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.thingsboard.monitoring.data.Latencies;
import org.thingsboard.monitoring.data.MonitoredServiceKey;
import org.thingsboard.monitoring.util.TbStopWatch;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.openqa.selenium.By.xpath;
import static org.openqa.selenium.support.ui.ExpectedConditions.elementToBeClickable;
import static org.openqa.selenium.support.ui.ExpectedConditions.urlContains;
@Component
@RequiredArgsConstructor
@Slf4j
@ConditionalOnProperty(name = "monitoring.ui.enabled", havingValue = "true")
public class WebUiHealthChecker {
@Value("${monitoring.ui.url}")
private String url;
@Value("${monitoring.auth.username}")
private String username;
@Value("${monitoring.auth.password}")
private String password;
@Value("${monitoring.ui.monitoring_rate_sec}")
private int monitoringRateSec;
@Value("${monitoring.rest_request_timeout_ms}")
private int timeoutMs;
@Value("${monitoring.ui.remote_webdriver_url}")
private String remoteWebdriverUrl;
private final MonitoringReporter monitoringReporter;
private final ScheduledExecutorService monitoringExecutor;
private final TbStopWatch stopWatch;
private static final String EMAIL_FIELD = "//input[@id='username-input']";
private static final String PASSWORD_FIELD = "//input[@id='password-input']";
private static final String SUBMIT_BTN = "//button[@type='submit']";
private static final String DEVICES_BTN = "//mat-toolbar//a[@href='/devices']";
@EventListener(ApplicationReadyEvent.class)
public void startMonitoring() {
monitoringExecutor.scheduleWithFixedDelay(() -> {
RemoteWebDriver driver = null;
try {
driver = createDriver();
WebDriverWait wait = createDriverWait(driver);
driver.manage().window().maximize();
driver.get(url + "/login");
try {
stopWatch.start();
wait.until(elementToBeClickable(xpath(EMAIL_FIELD))).sendKeys(username);
wait.until(elementToBeClickable(xpath(PASSWORD_FIELD))).sendKeys(password);
wait.until(elementToBeClickable(xpath(SUBMIT_BTN))).click();
monitoringReporter.reportLatency(Latencies.WEB_UI_LOAD, stopWatch.getTime());
wait.until(urlContains("/home"));
wait.until(elementToBeClickable(xpath(DEVICES_BTN))).click();
} catch (Exception e) {
throw new RuntimeException("Expected web UI elements were not displayed", e);
}
monitoringReporter.serviceIsOk(MonitoredServiceKey.WEB_UI);
} catch (Exception e) {
monitoringReporter.serviceFailure(MonitoredServiceKey.WEB_UI, e);
} finally {
if (driver != null) driver.quit();
}
}, 0, monitoringRateSec, TimeUnit.SECONDS);
}
private RemoteWebDriver createDriver() throws MalformedURLException {
ChromeOptions options = new ChromeOptions();
options.setPageLoadTimeout(Duration.ofMillis(timeoutMs));
return new RemoteWebDriver(new URL(remoteWebdriverUrl + "/wd/hub"), options);
}
private WebDriverWait createDriverWait(WebDriver driver) {
return new WebDriverWait(driver, Duration.ofMillis(timeoutMs));
}
}

View File

@ -15,7 +15,9 @@
*/
package org.thingsboard.monitoring.service.impl;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
@ -31,7 +33,7 @@ import org.thingsboard.monitoring.service.TransportMonitoringService;
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MqttTransportMonitoringService extends TransportMonitoringService<MqttTransportMonitoringServiceConfig> {
private MqttAsyncClient mqttClient;
private MqttClient mqttClient;
private static final String DEVICE_TELEMETRY_TOPIC = "v1/devices/me/telemetry";
@ -44,11 +46,16 @@ public class MqttTransportMonitoringService extends TransportMonitoringService<M
if (mqttClient == null || !mqttClient.isConnected()) {
String clientId = MqttAsyncClient.generateClientId();
String accessToken = target.getDevice().getCredentials().getCredentialsId();
mqttClient = new MqttAsyncClient(target.getBaseUrl(), clientId, new MemoryPersistence());
mqttClient = new MqttClient(target.getBaseUrl(), clientId, new MemoryPersistence());
mqttClient.setTimeToWait(config.getRequestTimeoutMs());
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(accessToken);
mqttClient.connect(options).waitForCompletion(config.getRequestTimeoutMs());
options.setConnectionTimeout(config.getRequestTimeoutMs() / 1000);
IMqttToken result = mqttClient.connectWithResult(options);
if (result.getException() != null) {
throw result.getException();
}
}
}
@ -57,7 +64,7 @@ public class MqttTransportMonitoringService extends TransportMonitoringService<M
MqttMessage message = new MqttMessage();
message.setPayload(payload.getBytes());
message.setQos(config.getQos());
mqttClient.publish(DEVICE_TELEMETRY_TOPIC, message).waitForCompletion(config.getRequestTimeoutMs());
mqttClient.publish(DEVICE_TELEMETRY_TOPIC, message);
}
@Override

View File

@ -63,12 +63,6 @@ monitoring:
device:
id: '${HTTP_TRANSPORT_TARGET_DEVICE_ID:}'
ui:
enabled: '${UI_MONITORING_ENABLED:false}'
url: '${UI_URL:http://localhost:4200}'
remote_webdriver_url: '${UI_MONITORING_REMOTE_WEBDRIVER_URL:http://localhost:4444}'
monitoring_rate_sec: '${UI_MONITORING_RATE_SEC:300}'
notification_channels:
slack:
enabled: '${SLACK_NOTIFICATION_CHANNEL_ENABLED:false}'

View File

@ -22,7 +22,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.2-SNAPSHOT</version>
<version>3.4.3-SNAPSHOT</version>
<artifactId>msa</artifactId>
</parent>