12 changed files with 588 additions and 27 deletions
@ -0,0 +1,117 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2024 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.server.service.housekeeper.stats; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.thingsboard.server.common.stats.DefaultCounter; |
||||
|
import org.thingsboard.server.common.stats.StatsCounter; |
||||
|
import org.thingsboard.server.common.stats.StatsFactory; |
||||
|
import org.thingsboard.server.common.stats.StatsType; |
||||
|
import org.thingsboard.server.dao.housekeeper.data.HousekeeperTask; |
||||
|
import org.thingsboard.server.dao.housekeeper.data.HousekeeperTaskType; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.EnumMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.Objects; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@Service |
||||
|
@Slf4j |
||||
|
public class HousekeeperStatsService { |
||||
|
|
||||
|
private final Map<HousekeeperTaskType, HousekeeperStats> stats = new EnumMap<>(HousekeeperTaskType.class); |
||||
|
|
||||
|
public HousekeeperStatsService(StatsFactory statsFactory) { |
||||
|
for (HousekeeperTaskType taskType : HousekeeperTaskType.values()) { |
||||
|
stats.put(taskType, new HousekeeperStats(taskType, statsFactory)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Scheduled(initialDelay = 60, fixedDelay = 60, timeUnit = TimeUnit.SECONDS) |
||||
|
private void reportStats() { |
||||
|
String statsStr = stats.values().stream().map(stats -> { |
||||
|
String countersStr = stats.getCounters().stream() |
||||
|
.filter(counter -> counter.get() > 0) |
||||
|
.map(counter -> counter.getName() + " = " + counter.get()) |
||||
|
.collect(Collectors.joining(", ")); |
||||
|
if (countersStr.isEmpty()) { |
||||
|
return null; |
||||
|
} else { |
||||
|
return stats.getTaskType() + " {" + countersStr + "}"; |
||||
|
} |
||||
|
}).filter(Objects::nonNull).collect(Collectors.joining("; ")); |
||||
|
|
||||
|
if (!statsStr.isEmpty()) { |
||||
|
stats.values().forEach(HousekeeperStats::reset); |
||||
|
log.info("Housekeeper stats: {}", statsStr); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void reportProcessed(HousekeeperTask task, ToHousekeeperServiceMsg msg) { |
||||
|
HousekeeperStats stats = this.stats.get(task.getTaskType()); |
||||
|
if (msg.getTask().getErrorsCount() == 0) { |
||||
|
stats.getProcessedCounter().increment(); |
||||
|
} else { |
||||
|
stats.getReprocessedCounter().increment(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void reportFailure(HousekeeperTask task, ToHousekeeperServiceMsg msg) { |
||||
|
HousekeeperStats stats = this.stats.get(task.getTaskType()); |
||||
|
if (msg.getTask().getErrorsCount() == 0) { |
||||
|
stats.getFailedProcessingCounter().increment(); |
||||
|
} else { |
||||
|
stats.getFailedReprocessingCounter().increment(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Getter |
||||
|
static class HousekeeperStats { |
||||
|
private final HousekeeperTaskType taskType; |
||||
|
private final List<StatsCounter> counters = new ArrayList<>(); |
||||
|
|
||||
|
private final StatsCounter processedCounter; |
||||
|
private final StatsCounter failedProcessingCounter; |
||||
|
private final StatsCounter reprocessedCounter; |
||||
|
private final StatsCounter failedReprocessingCounter; |
||||
|
|
||||
|
public HousekeeperStats(HousekeeperTaskType taskType, StatsFactory statsFactory) { |
||||
|
this.taskType = taskType; |
||||
|
this.processedCounter = register("processed", statsFactory); |
||||
|
this.failedProcessingCounter = register("failedProcessing", statsFactory); |
||||
|
this.reprocessedCounter = register("reprocessed", statsFactory); |
||||
|
this.failedReprocessingCounter = register("failedReprocessing", statsFactory); |
||||
|
} |
||||
|
|
||||
|
private StatsCounter register(String statsName, StatsFactory statsFactory) { |
||||
|
StatsCounter counter = statsFactory.createStatsCounter(StatsType.HOUSEKEEPER.getName(), statsName, Map.of("taskType", taskType.name())); |
||||
|
counters.add(counter); |
||||
|
return counter; |
||||
|
} |
||||
|
|
||||
|
public void reset() { |
||||
|
counters.forEach(DefaultCounter::clear); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,390 @@ |
|||||
|
{ |
||||
|
"annotations": { |
||||
|
"list": [ |
||||
|
{ |
||||
|
"builtIn": 1, |
||||
|
"datasource": "-- Grafana --", |
||||
|
"enable": true, |
||||
|
"hide": true, |
||||
|
"iconColor": "rgba(0, 211, 255, 1)", |
||||
|
"name": "Annotations & Alerts", |
||||
|
"target": { |
||||
|
"limit": 100, |
||||
|
"matchAny": false, |
||||
|
"tags": [], |
||||
|
"type": "dashboard" |
||||
|
}, |
||||
|
"type": "dashboard" |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"editable": true, |
||||
|
"fiscalYearStartMonth": 0, |
||||
|
"graphTooltip": 0, |
||||
|
"id": 2, |
||||
|
"links": [], |
||||
|
"liveNow": false, |
||||
|
"panels": [ |
||||
|
{ |
||||
|
"fieldConfig": { |
||||
|
"defaults": { |
||||
|
"color": { |
||||
|
"mode": "palette-classic" |
||||
|
}, |
||||
|
"custom": { |
||||
|
"axisLabel": "", |
||||
|
"axisPlacement": "auto", |
||||
|
"barAlignment": 0, |
||||
|
"drawStyle": "line", |
||||
|
"fillOpacity": 0, |
||||
|
"gradientMode": "none", |
||||
|
"hideFrom": { |
||||
|
"legend": false, |
||||
|
"tooltip": false, |
||||
|
"viz": false |
||||
|
}, |
||||
|
"lineInterpolation": "smooth", |
||||
|
"lineWidth": 1, |
||||
|
"pointSize": 5, |
||||
|
"scaleDistribution": { |
||||
|
"type": "linear" |
||||
|
}, |
||||
|
"showPoints": "auto", |
||||
|
"spanNulls": false, |
||||
|
"stacking": { |
||||
|
"group": "A", |
||||
|
"mode": "none" |
||||
|
}, |
||||
|
"thresholdsStyle": { |
||||
|
"mode": "off" |
||||
|
} |
||||
|
}, |
||||
|
"decimals": 0, |
||||
|
"mappings": [], |
||||
|
"thresholds": { |
||||
|
"mode": "absolute", |
||||
|
"steps": [ |
||||
|
{ |
||||
|
"color": "green", |
||||
|
"value": null |
||||
|
}, |
||||
|
{ |
||||
|
"color": "red", |
||||
|
"value": 80 |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"overrides": [] |
||||
|
}, |
||||
|
"gridPos": { |
||||
|
"h": 10, |
||||
|
"w": 12, |
||||
|
"x": 0, |
||||
|
"y": 0 |
||||
|
}, |
||||
|
"id": 2, |
||||
|
"options": { |
||||
|
"legend": { |
||||
|
"calcs": [], |
||||
|
"displayMode": "list", |
||||
|
"placement": "bottom" |
||||
|
}, |
||||
|
"tooltip": { |
||||
|
"mode": "single", |
||||
|
"sort": "none" |
||||
|
} |
||||
|
}, |
||||
|
"targets": [ |
||||
|
{ |
||||
|
"datasource": { |
||||
|
"type": "prometheus", |
||||
|
"uid": "9BonzvTSz" |
||||
|
}, |
||||
|
"exemplar": true, |
||||
|
"expr": "sum by (taskType) (increase(housekeeper_total{instance=\"192.168.3.27:8080\",statsName=\"processed\"}[1m]))", |
||||
|
"interval": "", |
||||
|
"legendFormat": "{{taskType}}", |
||||
|
"refId": "A" |
||||
|
} |
||||
|
], |
||||
|
"title": "Processed", |
||||
|
"type": "timeseries" |
||||
|
}, |
||||
|
{ |
||||
|
"fieldConfig": { |
||||
|
"defaults": { |
||||
|
"color": { |
||||
|
"mode": "palette-classic" |
||||
|
}, |
||||
|
"custom": { |
||||
|
"axisLabel": "", |
||||
|
"axisPlacement": "auto", |
||||
|
"barAlignment": 0, |
||||
|
"drawStyle": "line", |
||||
|
"fillOpacity": 0, |
||||
|
"gradientMode": "none", |
||||
|
"hideFrom": { |
||||
|
"legend": false, |
||||
|
"tooltip": false, |
||||
|
"viz": false |
||||
|
}, |
||||
|
"lineInterpolation": "smooth", |
||||
|
"lineWidth": 1, |
||||
|
"pointSize": 5, |
||||
|
"scaleDistribution": { |
||||
|
"type": "linear" |
||||
|
}, |
||||
|
"showPoints": "auto", |
||||
|
"spanNulls": false, |
||||
|
"stacking": { |
||||
|
"group": "A", |
||||
|
"mode": "none" |
||||
|
}, |
||||
|
"thresholdsStyle": { |
||||
|
"mode": "off" |
||||
|
} |
||||
|
}, |
||||
|
"decimals": 0, |
||||
|
"mappings": [], |
||||
|
"thresholds": { |
||||
|
"mode": "absolute", |
||||
|
"steps": [ |
||||
|
{ |
||||
|
"color": "green", |
||||
|
"value": null |
||||
|
}, |
||||
|
{ |
||||
|
"color": "red", |
||||
|
"value": 80 |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"overrides": [] |
||||
|
}, |
||||
|
"gridPos": { |
||||
|
"h": 10, |
||||
|
"w": 12, |
||||
|
"x": 12, |
||||
|
"y": 0 |
||||
|
}, |
||||
|
"id": 4, |
||||
|
"options": { |
||||
|
"legend": { |
||||
|
"calcs": [], |
||||
|
"displayMode": "list", |
||||
|
"placement": "bottom" |
||||
|
}, |
||||
|
"tooltip": { |
||||
|
"mode": "single", |
||||
|
"sort": "none" |
||||
|
} |
||||
|
}, |
||||
|
"targets": [ |
||||
|
{ |
||||
|
"datasource": { |
||||
|
"type": "prometheus", |
||||
|
"uid": "9BonzvTSz" |
||||
|
}, |
||||
|
"exemplar": true, |
||||
|
"expr": "sum by (taskType) (increase(housekeeper_total{instance=\"192.168.3.27:8080\",statsName=\"failedProcessing\"}[1m]))", |
||||
|
"interval": "", |
||||
|
"legendFormat": "{{taskType}}", |
||||
|
"refId": "A" |
||||
|
} |
||||
|
], |
||||
|
"title": "Processing failures", |
||||
|
"type": "timeseries" |
||||
|
}, |
||||
|
{ |
||||
|
"fieldConfig": { |
||||
|
"defaults": { |
||||
|
"color": { |
||||
|
"mode": "palette-classic" |
||||
|
}, |
||||
|
"custom": { |
||||
|
"axisLabel": "", |
||||
|
"axisPlacement": "auto", |
||||
|
"barAlignment": 0, |
||||
|
"drawStyle": "line", |
||||
|
"fillOpacity": 0, |
||||
|
"gradientMode": "none", |
||||
|
"hideFrom": { |
||||
|
"legend": false, |
||||
|
"tooltip": false, |
||||
|
"viz": false |
||||
|
}, |
||||
|
"lineInterpolation": "smooth", |
||||
|
"lineWidth": 1, |
||||
|
"pointSize": 5, |
||||
|
"scaleDistribution": { |
||||
|
"type": "linear" |
||||
|
}, |
||||
|
"showPoints": "auto", |
||||
|
"spanNulls": false, |
||||
|
"stacking": { |
||||
|
"group": "A", |
||||
|
"mode": "none" |
||||
|
}, |
||||
|
"thresholdsStyle": { |
||||
|
"mode": "off" |
||||
|
} |
||||
|
}, |
||||
|
"decimals": 0, |
||||
|
"mappings": [], |
||||
|
"thresholds": { |
||||
|
"mode": "absolute", |
||||
|
"steps": [ |
||||
|
{ |
||||
|
"color": "green", |
||||
|
"value": null |
||||
|
}, |
||||
|
{ |
||||
|
"color": "red", |
||||
|
"value": 80 |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"overrides": [] |
||||
|
}, |
||||
|
"gridPos": { |
||||
|
"h": 9, |
||||
|
"w": 12, |
||||
|
"x": 0, |
||||
|
"y": 10 |
||||
|
}, |
||||
|
"id": 5, |
||||
|
"options": { |
||||
|
"legend": { |
||||
|
"calcs": [], |
||||
|
"displayMode": "list", |
||||
|
"placement": "bottom" |
||||
|
}, |
||||
|
"tooltip": { |
||||
|
"mode": "single", |
||||
|
"sort": "none" |
||||
|
} |
||||
|
}, |
||||
|
"targets": [ |
||||
|
{ |
||||
|
"datasource": { |
||||
|
"type": "prometheus", |
||||
|
"uid": "9BonzvTSz" |
||||
|
}, |
||||
|
"exemplar": true, |
||||
|
"expr": "sum by (taskType) (increase(housekeeper_total{instance=\"192.168.3.27:8080\",statsName=\"reprocessed\"}[1m]))", |
||||
|
"interval": "", |
||||
|
"legendFormat": "{{taskType}}", |
||||
|
"refId": "A" |
||||
|
} |
||||
|
], |
||||
|
"title": "Reprocessed", |
||||
|
"type": "timeseries" |
||||
|
}, |
||||
|
{ |
||||
|
"fieldConfig": { |
||||
|
"defaults": { |
||||
|
"color": { |
||||
|
"mode": "palette-classic" |
||||
|
}, |
||||
|
"custom": { |
||||
|
"axisLabel": "", |
||||
|
"axisPlacement": "auto", |
||||
|
"barAlignment": 0, |
||||
|
"drawStyle": "line", |
||||
|
"fillOpacity": 0, |
||||
|
"gradientMode": "none", |
||||
|
"hideFrom": { |
||||
|
"legend": false, |
||||
|
"tooltip": false, |
||||
|
"viz": false |
||||
|
}, |
||||
|
"lineInterpolation": "smooth", |
||||
|
"lineWidth": 1, |
||||
|
"pointSize": 5, |
||||
|
"scaleDistribution": { |
||||
|
"type": "linear" |
||||
|
}, |
||||
|
"showPoints": "auto", |
||||
|
"spanNulls": false, |
||||
|
"stacking": { |
||||
|
"group": "A", |
||||
|
"mode": "none" |
||||
|
}, |
||||
|
"thresholdsStyle": { |
||||
|
"mode": "off" |
||||
|
} |
||||
|
}, |
||||
|
"decimals": 0, |
||||
|
"mappings": [], |
||||
|
"thresholds": { |
||||
|
"mode": "absolute", |
||||
|
"steps": [ |
||||
|
{ |
||||
|
"color": "green", |
||||
|
"value": null |
||||
|
}, |
||||
|
{ |
||||
|
"color": "red", |
||||
|
"value": 80 |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"overrides": [] |
||||
|
}, |
||||
|
"gridPos": { |
||||
|
"h": 9, |
||||
|
"w": 12, |
||||
|
"x": 12, |
||||
|
"y": 10 |
||||
|
}, |
||||
|
"id": 6, |
||||
|
"options": { |
||||
|
"legend": { |
||||
|
"calcs": [], |
||||
|
"displayMode": "list", |
||||
|
"placement": "bottom" |
||||
|
}, |
||||
|
"tooltip": { |
||||
|
"mode": "single", |
||||
|
"sort": "none" |
||||
|
} |
||||
|
}, |
||||
|
"targets": [ |
||||
|
{ |
||||
|
"datasource": { |
||||
|
"type": "prometheus", |
||||
|
"uid": "9BonzvTSz" |
||||
|
}, |
||||
|
"exemplar": true, |
||||
|
"expr": "sum by (taskType) (increase(housekeeper_total{instance=\"192.168.3.27:8080\",statsName=\"failedReprocessing\"}[1m]))", |
||||
|
"interval": "", |
||||
|
"legendFormat": "{{taskType}}", |
||||
|
"refId": "A" |
||||
|
} |
||||
|
], |
||||
|
"title": "Reprocessing failures", |
||||
|
"type": "timeseries" |
||||
|
} |
||||
|
], |
||||
|
"refresh": "10s", |
||||
|
"schemaVersion": 35, |
||||
|
"style": "dark", |
||||
|
"tags": [], |
||||
|
"templating": { |
||||
|
"list": [] |
||||
|
}, |
||||
|
"time": { |
||||
|
"from": "now-15m", |
||||
|
"to": "now" |
||||
|
}, |
||||
|
"timepicker": {}, |
||||
|
"timezone": "", |
||||
|
"title": "Housekeeper", |
||||
|
"uid": "JFJb7voIz", |
||||
|
"version": 5, |
||||
|
"weekStart": "" |
||||
|
} |
||||
Loading…
Reference in new issue