Commit 89419c6999cc7b960d6f40fbb6e9b785a81c38dd

Authored by vzikratyi-tb
Committed by GitHub
1 parent 7d739dfa

Prometheus Metrics (#3052)

* Moved resetting ruleEngineStats to Consumer

* Moved counters to Map in TbCoreConsumerStats

* Added actuator and MetricsService

* Added metrics to core and rule_engine consumers

* Replaced summary with counters

* Removed most setters and getters from TbRuleEngine stats

* Added stats to Transport consumer

* Added JsInvoke actuator stats

* Removed MetricsService
Showing 20 changed files with 598 additions and 96 deletions
... ... @@ -298,6 +298,18 @@
298 298 <groupId>com.github.ua-parser</groupId>
299 299 <artifactId>uap-java</artifactId>
300 300 </dependency>
  301 + <dependency>
  302 + <groupId>org.springframework.boot</groupId>
  303 + <artifactId>spring-boot-starter-actuator</artifactId>
  304 + </dependency>
  305 + <dependency>
  306 + <groupId>io.micrometer</groupId>
  307 + <artifactId>micrometer-core</artifactId>
  308 + </dependency>
  309 + <dependency>
  310 + <groupId>io.micrometer</groupId>
  311 + <artifactId>micrometer-registry-prometheus</artifactId>
  312 + </dependency>
301 313 </dependencies>
302 314
303 315 <build>
... ...
... ... @@ -219,6 +219,10 @@ public class ActorSystemContext {
219 219 @Getter
220 220 private ClaimDevicesService claimDevicesService;
221 221
  222 + @Autowired
  223 + @Getter
  224 + private JsInvokeStats jsInvokeStats;
  225 +
222 226 //TODO: separate context for TbCore and TbRuleEngine
223 227 @Autowired(required = false)
224 228 @Getter
... ... @@ -272,19 +276,14 @@ public class ActorSystemContext {
272 276 @Getter
273 277 private long statisticsPersistFrequency;
274 278
275   - @Getter
276   - private final AtomicInteger jsInvokeRequestsCount = new AtomicInteger(0);
277   - @Getter
278   - private final AtomicInteger jsInvokeResponsesCount = new AtomicInteger(0);
279   - @Getter
280   - private final AtomicInteger jsInvokeFailuresCount = new AtomicInteger(0);
281 279
282 280 @Scheduled(fixedDelayString = "${actors.statistics.js_print_interval_ms}")
283 281 public void printStats() {
284 282 if (statisticsEnabled) {
285   - if (jsInvokeRequestsCount.get() > 0 || jsInvokeResponsesCount.get() > 0 || jsInvokeFailuresCount.get() > 0) {
  283 + if (jsInvokeStats.getRequests() > 0 || jsInvokeStats.getResponses() > 0 || jsInvokeStats.getFailures() > 0) {
286 284 log.info("Rule Engine JS Invoke Stats: requests [{}] responses [{}] failures [{}]",
287   - jsInvokeRequestsCount.getAndSet(0), jsInvokeResponsesCount.getAndSet(0), jsInvokeFailuresCount.getAndSet(0));
  285 + jsInvokeStats.getRequests(), jsInvokeStats.getResponses(), jsInvokeStats.getFailures());
  286 + jsInvokeStats.reset();
288 287 }
289 288 }
290 289 }
... ...
... ... @@ -292,21 +292,21 @@ class DefaultTbContext implements TbContext {
292 292 @Override
293 293 public void logJsEvalRequest() {
294 294 if (mainCtx.isStatisticsEnabled()) {
295   - mainCtx.getJsInvokeRequestsCount().incrementAndGet();
  295 + mainCtx.getJsInvokeStats().incrementRequests();
296 296 }
297 297 }
298 298
299 299 @Override
300 300 public void logJsEvalResponse() {
301 301 if (mainCtx.isStatisticsEnabled()) {
302   - mainCtx.getJsInvokeResponsesCount().incrementAndGet();
  302 + mainCtx.getJsInvokeStats().incrementResponses();
303 303 }
304 304 }
305 305
306 306 @Override
307 307 public void logJsEvalFailure() {
308 308 if (mainCtx.isStatisticsEnabled()) {
309   - mainCtx.getJsInvokeFailuresCount().incrementAndGet();
  309 + mainCtx.getJsInvokeStats().incrementFailures();
310 310 }
311 311 }
312 312
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.metrics;
  17 +
  18 +import io.micrometer.core.instrument.Counter;
  19 +
  20 +public class StubCounter implements Counter {
  21 + @Override
  22 + public void increment(double amount) {}
  23 +
  24 + @Override
  25 + public double count() {
  26 + return 0;
  27 + }
  28 +
  29 + @Override
  30 + public Id getId() {
  31 + return null;
  32 + }
  33 +}
... ...
... ... @@ -26,16 +26,7 @@ import org.thingsboard.server.common.msg.MsgType;
26 26 import org.thingsboard.server.common.msg.TbActorMsg;
27 27 import org.thingsboard.server.common.msg.queue.ServiceType;
28 28 import org.thingsboard.server.common.msg.queue.TbCallback;
29   -import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto;
30   -import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto;
31   -import org.thingsboard.server.gen.transport.TransportProtos.LocalSubscriptionServiceMsgProto;
32   -import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionMgrMsgProto;
33   -import org.thingsboard.server.gen.transport.TransportProtos.TbAttributeUpdateProto;
34   -import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionCloseProto;
35   -import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto;
36   -import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
37   -import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
38   -import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
  29 +import org.thingsboard.server.gen.transport.TransportProtos.*;
39 30 import org.thingsboard.server.queue.TbQueueConsumer;
40 31 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
41 32 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
... ... @@ -47,6 +38,7 @@ import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
47 38 import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
48 39 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
49 40 import org.thingsboard.server.service.state.DeviceStateService;
  41 +import org.thingsboard.server.service.stats.StatsCounterFactory;
50 42 import org.thingsboard.server.service.subscription.SubscriptionManagerService;
51 43 import org.thingsboard.server.service.subscription.TbLocalSubscriptionService;
52 44 import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
... ... @@ -81,18 +73,19 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
81 73 private final TbLocalSubscriptionService localSubscriptionService;
82 74 private final SubscriptionManagerService subscriptionManagerService;
83 75 private final TbCoreDeviceRpcService tbCoreDeviceRpcService;
84   - private final TbCoreConsumerStats stats = new TbCoreConsumerStats();
  76 + private final TbCoreConsumerStats stats;
85 77
86 78 public DefaultTbCoreConsumerService(TbCoreQueueFactory tbCoreQueueFactory, ActorSystemContext actorContext,
87 79 DeviceStateService stateService, TbLocalSubscriptionService localSubscriptionService,
88 80 SubscriptionManagerService subscriptionManagerService, DataDecodingEncodingService encodingService,
89   - TbCoreDeviceRpcService tbCoreDeviceRpcService) {
  81 + TbCoreDeviceRpcService tbCoreDeviceRpcService, StatsCounterFactory counterFactory) {
90 82 super(actorContext, encodingService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer());
91 83 this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer();
92 84 this.stateService = stateService;
93 85 this.localSubscriptionService = localSubscriptionService;
94 86 this.subscriptionManagerService = subscriptionManagerService;
95 87 this.tbCoreDeviceRpcService = tbCoreDeviceRpcService;
  88 + this.stats = new TbCoreConsumerStats(counterFactory);
96 89 }
97 90
98 91 @PostConstruct
... ... @@ -228,6 +221,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
228 221 public void printStats() {
229 222 if (statsEnabled) {
230 223 stats.printStats();
  224 + stats.reset();
231 225 }
232 226 }
233 227
... ...
... ... @@ -52,6 +52,7 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrateg
52 52 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
53 53 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
54 54 import org.thingsboard.server.service.stats.RuleEngineStatisticsService;
  55 +import org.thingsboard.server.service.stats.StatsCounterFactory;
55 56
56 57 import javax.annotation.PostConstruct;
57 58 import javax.annotation.PreDestroy;
... ... @@ -79,6 +80,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
79 80 @Value("${queue.rule-engine.stats.enabled:true}")
80 81 private boolean statsEnabled;
81 82
  83 + private final StatsCounterFactory counterFactory;
82 84 private final TbRuleEngineSubmitStrategyFactory submitStrategyFactory;
83 85 private final TbRuleEngineProcessingStrategyFactory processingStrategyFactory;
84 86 private final TbRuleEngineQueueFactory tbRuleEngineQueueFactory;
... ... @@ -95,7 +97,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
95 97 TbQueueRuleEngineSettings ruleEngineSettings,
96 98 TbRuleEngineQueueFactory tbRuleEngineQueueFactory, RuleEngineStatisticsService statisticsService,
97 99 ActorSystemContext actorContext, DataDecodingEncodingService encodingService,
98   - TbRuleEngineDeviceRpcService tbDeviceRpcService) {
  100 + TbRuleEngineDeviceRpcService tbDeviceRpcService,
  101 + StatsCounterFactory counterFactory) {
99 102 super(actorContext, encodingService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer());
100 103 this.statisticsService = statisticsService;
101 104 this.ruleEngineSettings = ruleEngineSettings;
... ... @@ -103,6 +106,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
103 106 this.submitStrategyFactory = submitStrategyFactory;
104 107 this.processingStrategyFactory = processingStrategyFactory;
105 108 this.tbDeviceRpcService = tbDeviceRpcService;
  109 + this.counterFactory = counterFactory;
106 110 }
107 111
108 112 @PostConstruct
... ... @@ -111,7 +115,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
111 115 for (TbRuleEngineQueueConfiguration configuration : ruleEngineSettings.getQueues()) {
112 116 consumerConfigurations.putIfAbsent(configuration.getName(), configuration);
113 117 consumers.computeIfAbsent(configuration.getName(), queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration));
114   - consumerStats.put(configuration.getName(), new TbRuleEngineConsumerStats(configuration.getName()));
  118 + consumerStats.put(configuration.getName(), new TbRuleEngineConsumerStats(configuration.getName(), counterFactory));
115 119 }
116 120 submitExecutor = Executors.newSingleThreadExecutor();
117 121 }
... ... @@ -269,6 +273,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
269 273 consumerStats.forEach((queue, stats) -> {
270 274 stats.printStats();
271 275 statisticsService.reportQueueStats(ts, stats);
  276 + stats.reset();
272 277 });
273 278 }
274 279 }
... ...
... ... @@ -17,76 +17,124 @@ package org.thingsboard.server.service.queue;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.thingsboard.server.gen.transport.TransportProtos;
  20 +import org.thingsboard.server.service.stats.StatsCounter;
  21 +import org.thingsboard.server.service.stats.StatsCounterFactory;
  22 +import org.thingsboard.server.service.stats.StatsType;
20 23
  24 +import java.util.*;
21 25 import java.util.concurrent.atomic.AtomicInteger;
22 26
23 27 @Slf4j
24 28 public class TbCoreConsumerStats {
  29 + public static final String TOTAL_MSGS = "totalMsgs";
  30 + public static final String SESSION_EVENTS = "sessionEvents";
  31 + public static final String GET_ATTRIBUTE = "getAttr";
  32 + public static final String ATTRIBUTE_SUBSCRIBES = "subToAttr";
  33 + public static final String RPC_SUBSCRIBES = "subToRpc";
  34 + public static final String TO_DEVICE_RPC_CALL_RESPONSES = "toDevRpc";
  35 + public static final String SUBSCRIPTION_INFO = "subInfo";
  36 + public static final String DEVICE_CLAIMS = "claimDevice";
  37 + public static final String DEVICE_STATES = "deviceState";
  38 + public static final String SUBSCRIPTION_MSGS = "subMsgs";
  39 + public static final String TO_CORE_NOTIFICATIONS = "coreNfs";
25 40
26   - private final AtomicInteger totalCounter = new AtomicInteger(0);
27   - private final AtomicInteger sessionEventCounter = new AtomicInteger(0);
28   - private final AtomicInteger getAttributesCounter = new AtomicInteger(0);
29   - private final AtomicInteger subscribeToAttributesCounter = new AtomicInteger(0);
30   - private final AtomicInteger subscribeToRPCCounter = new AtomicInteger(0);
31   - private final AtomicInteger toDeviceRPCCallResponseCounter = new AtomicInteger(0);
32   - private final AtomicInteger subscriptionInfoCounter = new AtomicInteger(0);
33   - private final AtomicInteger claimDeviceCounter = new AtomicInteger(0);
  41 + private final StatsCounter totalCounter;
  42 + private final StatsCounter sessionEventCounter;
  43 + private final StatsCounter getAttributesCounter;
  44 + private final StatsCounter subscribeToAttributesCounter;
  45 + private final StatsCounter subscribeToRPCCounter;
  46 + private final StatsCounter toDeviceRPCCallResponseCounter;
  47 + private final StatsCounter subscriptionInfoCounter;
  48 + private final StatsCounter claimDeviceCounter;
34 49
35   - private final AtomicInteger deviceStateCounter = new AtomicInteger(0);
36   - private final AtomicInteger subscriptionMsgCounter = new AtomicInteger(0);
37   - private final AtomicInteger toCoreNotificationsCounter = new AtomicInteger(0);
  50 + private final StatsCounter deviceStateCounter;
  51 + private final StatsCounter subscriptionMsgCounter;
  52 + private final StatsCounter toCoreNotificationsCounter;
  53 +
  54 + private final List<StatsCounter> counters = new ArrayList<>();
  55 +
  56 + public TbCoreConsumerStats(StatsCounterFactory counterFactory) {
  57 + String statsKey = StatsType.CORE.getName();
  58 +
  59 + this.totalCounter = counterFactory.createStatsCounter(statsKey, TOTAL_MSGS);
  60 + this.sessionEventCounter = counterFactory.createStatsCounter(statsKey, SESSION_EVENTS);
  61 + this.getAttributesCounter = counterFactory.createStatsCounter(statsKey, GET_ATTRIBUTE);
  62 + this.subscribeToAttributesCounter = counterFactory.createStatsCounter(statsKey, ATTRIBUTE_SUBSCRIBES);
  63 + this.subscribeToRPCCounter = counterFactory.createStatsCounter(statsKey, RPC_SUBSCRIBES);
  64 + this.toDeviceRPCCallResponseCounter = counterFactory.createStatsCounter(statsKey, TO_DEVICE_RPC_CALL_RESPONSES);
  65 + this.subscriptionInfoCounter = counterFactory.createStatsCounter(statsKey, SUBSCRIPTION_INFO);
  66 + this.claimDeviceCounter = counterFactory.createStatsCounter(statsKey, DEVICE_CLAIMS);
  67 + this.deviceStateCounter = counterFactory.createStatsCounter(statsKey, DEVICE_STATES);
  68 + this.subscriptionMsgCounter = counterFactory.createStatsCounter(statsKey, SUBSCRIPTION_MSGS);
  69 + this.toCoreNotificationsCounter = counterFactory.createStatsCounter(statsKey, TO_CORE_NOTIFICATIONS);
  70 +
  71 +
  72 + counters.add(totalCounter);
  73 + counters.add(sessionEventCounter);
  74 + counters.add(getAttributesCounter);
  75 + counters.add(subscribeToAttributesCounter);
  76 + counters.add(subscribeToRPCCounter);
  77 + counters.add(toDeviceRPCCallResponseCounter);
  78 + counters.add(subscriptionInfoCounter);
  79 + counters.add(claimDeviceCounter);
  80 +
  81 + counters.add(deviceStateCounter);
  82 + counters.add(subscriptionMsgCounter);
  83 + counters.add(toCoreNotificationsCounter);
  84 + }
38 85
39 86 public void log(TransportProtos.TransportToDeviceActorMsg msg) {
40   - totalCounter.incrementAndGet();
  87 + totalCounter.increment();
41 88 if (msg.hasSessionEvent()) {
42   - sessionEventCounter.incrementAndGet();
  89 + sessionEventCounter.increment();
43 90 }
44 91 if (msg.hasGetAttributes()) {
45   - getAttributesCounter.incrementAndGet();
  92 + getAttributesCounter.increment();
46 93 }
47 94 if (msg.hasSubscribeToAttributes()) {
48   - subscribeToAttributesCounter.incrementAndGet();
  95 + subscribeToAttributesCounter.increment();
49 96 }
50 97 if (msg.hasSubscribeToRPC()) {
51   - subscribeToRPCCounter.incrementAndGet();
  98 + subscribeToRPCCounter.increment();
52 99 }
53 100 if (msg.hasToDeviceRPCCallResponse()) {
54   - toDeviceRPCCallResponseCounter.incrementAndGet();
  101 + toDeviceRPCCallResponseCounter.increment();
55 102 }
56 103 if (msg.hasSubscriptionInfo()) {
57   - subscriptionInfoCounter.incrementAndGet();
  104 + subscriptionInfoCounter.increment();
58 105 }
59 106 if (msg.hasClaimDevice()) {
60   - claimDeviceCounter.incrementAndGet();
  107 + claimDeviceCounter.increment();
61 108 }
62 109 }
63 110
64 111 public void log(TransportProtos.DeviceStateServiceMsgProto msg) {
65   - totalCounter.incrementAndGet();
66   - deviceStateCounter.incrementAndGet();
  112 + totalCounter.increment();
  113 + deviceStateCounter.increment();
67 114 }
68 115
69 116 public void log(TransportProtos.SubscriptionMgrMsgProto msg) {
70   - totalCounter.incrementAndGet();
71   - subscriptionMsgCounter.incrementAndGet();
  117 + totalCounter.increment();
  118 + subscriptionMsgCounter.increment();
72 119 }
73 120
74 121 public void log(TransportProtos.ToCoreNotificationMsg msg) {
75   - totalCounter.incrementAndGet();
76   - toCoreNotificationsCounter.incrementAndGet();
  122 + totalCounter.increment();
  123 + toCoreNotificationsCounter.increment();
77 124 }
78 125
79 126 public void printStats() {
80   - int total = totalCounter.getAndSet(0);
  127 + int total = totalCounter.get();
81 128 if (total > 0) {
82   - log.info("Total [{}] sessionEvents [{}] getAttr [{}] subToAttr [{}] subToRpc [{}] toDevRpc [{}] subInfo [{}] claimDevice [{}]" +
83   - " deviceState [{}] subMgr [{}] coreNfs [{}]",
84   - total, sessionEventCounter.getAndSet(0),
85   - getAttributesCounter.getAndSet(0), subscribeToAttributesCounter.getAndSet(0),
86   - subscribeToRPCCounter.getAndSet(0), toDeviceRPCCallResponseCounter.getAndSet(0),
87   - subscriptionInfoCounter.getAndSet(0), claimDeviceCounter.getAndSet(0)
88   - , deviceStateCounter.getAndSet(0), subscriptionMsgCounter.getAndSet(0), toCoreNotificationsCounter.getAndSet(0));
  129 + StringBuilder stats = new StringBuilder();
  130 + counters.forEach(counter -> {
  131 + stats.append(counter.getName()).append(" = [").append(counter.get()).append("] ");
  132 + });
  133 + log.info("Core Stats: {}", stats);
89 134 }
90 135 }
91 136
  137 + public void reset() {
  138 + counters.forEach(StatsCounter::clear);
  139 + }
92 140 }
... ...
... ... @@ -22,16 +22,16 @@ import org.thingsboard.server.common.msg.queue.RuleEngineException;
22 22 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
23 23 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
24 24 import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult;
  25 +import org.thingsboard.server.service.stats.StatsCounter;
  26 +import org.thingsboard.server.service.stats.StatsCounterFactory;
  27 +import org.thingsboard.server.service.stats.StatsType;
25 28
26   -import java.util.HashMap;
27   -import java.util.Map;
28   -import java.util.UUID;
  29 +import java.util.*;
29 30 import java.util.concurrent.ConcurrentHashMap;
30 31 import java.util.concurrent.ConcurrentMap;
31 32 import java.util.concurrent.atomic.AtomicInteger;
32 33
33 34 @Slf4j
34   -@Data
35 35 public class TbRuleEngineConsumerStats {
36 36
37 37 public static final String TOTAL_MSGS = "totalMsgs";
... ... @@ -43,61 +43,72 @@ public class TbRuleEngineConsumerStats {
43 43 public static final String SUCCESSFUL_ITERATIONS = "successfulIterations";
44 44 public static final String FAILED_ITERATIONS = "failedIterations";
45 45
46   - private final AtomicInteger totalMsgCounter = new AtomicInteger(0);
47   - private final AtomicInteger successMsgCounter = new AtomicInteger(0);
48   - private final AtomicInteger tmpTimeoutMsgCounter = new AtomicInteger(0);
49   - private final AtomicInteger tmpFailedMsgCounter = new AtomicInteger(0);
  46 + private final StatsCounter totalMsgCounter;
  47 + private final StatsCounter successMsgCounter;
  48 + private final StatsCounter tmpTimeoutMsgCounter;
  49 + private final StatsCounter tmpFailedMsgCounter;
50 50
51   - private final AtomicInteger timeoutMsgCounter = new AtomicInteger(0);
52   - private final AtomicInteger failedMsgCounter = new AtomicInteger(0);
  51 + private final StatsCounter timeoutMsgCounter;
  52 + private final StatsCounter failedMsgCounter;
53 53
54   - private final AtomicInteger successIterationsCounter = new AtomicInteger(0);
55   - private final AtomicInteger failedIterationsCounter = new AtomicInteger(0);
  54 + private final StatsCounter successIterationsCounter;
  55 + private final StatsCounter failedIterationsCounter;
56 56
57   - private final Map<String, AtomicInteger> counters = new HashMap<>();
  57 + private final List<StatsCounter> counters = new ArrayList<>();
58 58 private final ConcurrentMap<UUID, TbTenantRuleEngineStats> tenantStats = new ConcurrentHashMap<>();
59 59 private final ConcurrentMap<TenantId, RuleEngineException> tenantExceptions = new ConcurrentHashMap<>();
60 60
61 61 private final String queueName;
62 62
63   - public TbRuleEngineConsumerStats(String queueName) {
  63 + public TbRuleEngineConsumerStats(String queueName, StatsCounterFactory counterFactory) {
64 64 this.queueName = queueName;
65   - counters.put(TOTAL_MSGS, totalMsgCounter);
66   - counters.put(SUCCESSFUL_MSGS, successMsgCounter);
67   - counters.put(TIMEOUT_MSGS, timeoutMsgCounter);
68   - counters.put(FAILED_MSGS, failedMsgCounter);
69   -
70   - counters.put(TMP_TIMEOUT, tmpTimeoutMsgCounter);
71   - counters.put(TMP_FAILED, tmpFailedMsgCounter);
72   - counters.put(SUCCESSFUL_ITERATIONS, successIterationsCounter);
73   - counters.put(FAILED_ITERATIONS, failedIterationsCounter);
  65 +
  66 + String statsKey = StatsType.RULE_ENGINE.getName() + "." + queueName;
  67 + this.totalMsgCounter = counterFactory.createStatsCounter(statsKey, TOTAL_MSGS);
  68 + this.successMsgCounter = counterFactory.createStatsCounter(statsKey, SUCCESSFUL_MSGS);
  69 + this.timeoutMsgCounter = counterFactory.createStatsCounter(statsKey, TIMEOUT_MSGS);
  70 + this.failedMsgCounter = counterFactory.createStatsCounter(statsKey, FAILED_MSGS);
  71 + this.tmpTimeoutMsgCounter = counterFactory.createStatsCounter(statsKey, TMP_TIMEOUT);
  72 + this.tmpFailedMsgCounter = counterFactory.createStatsCounter(statsKey, TMP_FAILED);
  73 + this.successIterationsCounter = counterFactory.createStatsCounter(statsKey, SUCCESSFUL_ITERATIONS);
  74 + this.failedIterationsCounter = counterFactory.createStatsCounter(statsKey, FAILED_ITERATIONS);
  75 +
  76 + counters.add(totalMsgCounter);
  77 + counters.add(successMsgCounter);
  78 + counters.add(timeoutMsgCounter);
  79 + counters.add(failedMsgCounter);
  80 +
  81 + counters.add(tmpTimeoutMsgCounter);
  82 + counters.add(tmpFailedMsgCounter);
  83 + counters.add(successIterationsCounter);
  84 + counters.add(failedIterationsCounter);
74 85 }
75 86
76 87 public void log(TbRuleEngineProcessingResult msg, boolean finalIterationForPack) {
77 88 int success = msg.getSuccessMap().size();
78 89 int pending = msg.getPendingMap().size();
79 90 int failed = msg.getFailedMap().size();
80   - totalMsgCounter.addAndGet(success + pending + failed);
81   - successMsgCounter.addAndGet(success);
  91 + totalMsgCounter.add(success + pending + failed);
  92 + successMsgCounter.add(success);
82 93 msg.getSuccessMap().values().forEach(m -> getTenantStats(m).logSuccess());
83 94 if (finalIterationForPack) {
84 95 if (pending > 0 || failed > 0) {
85   - timeoutMsgCounter.addAndGet(pending);
86   - failedMsgCounter.addAndGet(failed);
  96 + timeoutMsgCounter.add(pending);
  97 + failedMsgCounter.add(failed);
87 98 if (pending > 0) {
88 99 msg.getPendingMap().values().forEach(m -> getTenantStats(m).logTimeout());
89 100 }
90 101 if (failed > 0) {
91 102 msg.getFailedMap().values().forEach(m -> getTenantStats(m).logFailed());
92 103 }
93   - failedIterationsCounter.incrementAndGet();
  104 + failedIterationsCounter.increment();
94 105 } else {
95   - successIterationsCounter.incrementAndGet();
  106 + successIterationsCounter.increment();
96 107 }
97 108 } else {
98   - failedIterationsCounter.incrementAndGet();
99   - tmpTimeoutMsgCounter.addAndGet(pending);
100   - tmpFailedMsgCounter.addAndGet(failed);
  109 + failedIterationsCounter.increment();
  110 + tmpTimeoutMsgCounter.add(pending);
  111 + tmpFailedMsgCounter.add(failed);
101 112 if (pending > 0) {
102 113 msg.getPendingMap().values().forEach(m -> getTenantStats(m).logTmpTimeout());
103 114 }
... ... @@ -113,19 +124,31 @@ public class TbRuleEngineConsumerStats {
113 124 return tenantStats.computeIfAbsent(new UUID(reMsg.getTenantIdMSB(), reMsg.getTenantIdLSB()), TbTenantRuleEngineStats::new);
114 125 }
115 126
  127 + public ConcurrentMap<UUID, TbTenantRuleEngineStats> getTenantStats() {
  128 + return tenantStats;
  129 + }
  130 +
  131 + public String getQueueName() {
  132 + return queueName;
  133 + }
  134 +
  135 + public ConcurrentMap<TenantId, RuleEngineException> getTenantExceptions() {
  136 + return tenantExceptions;
  137 + }
  138 +
116 139 public void printStats() {
117 140 int total = totalMsgCounter.get();
118 141 if (total > 0) {
119 142 StringBuilder stats = new StringBuilder();
120   - counters.forEach((label, value) -> {
121   - stats.append(label).append(" = [").append(value.get()).append("] ");
  143 + counters.forEach(counter -> {
  144 + stats.append(counter.getName()).append(" = [").append(counter.get()).append("] ");
122 145 });
123 146 log.info("[{}] Stats: {}", queueName, stats);
124 147 }
125 148 }
126 149
127 150 public void reset() {
128   - counters.values().forEach(counter -> counter.set(0));
  151 + counters.forEach(StatsCounter::clear);
129 152 tenantStats.clear();
130 153 tenantExceptions.clear();
131 154 }
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.stats;
  17 +
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.stereotype.Service;
  20 +import org.thingsboard.server.actors.JsInvokeStats;
  21 +
  22 +import javax.annotation.PostConstruct;
  23 +
  24 +@Service
  25 +public class DefaultJsInvokeStats implements JsInvokeStats {
  26 + private static final String REQUESTS = "requests";
  27 + private static final String RESPONSES = "responses";
  28 + private static final String FAILURES = "failures";
  29 +
  30 + private StatsCounter requestsCounter;
  31 + private StatsCounter responsesCounter;
  32 + private StatsCounter failuresCounter;
  33 +
  34 + @Autowired
  35 + private StatsCounterFactory counterFactory;
  36 +
  37 + @PostConstruct
  38 + public void init() {
  39 + String key = StatsType.JS_INVOKE.getName();
  40 + this.requestsCounter = counterFactory.createStatsCounter(key, REQUESTS);
  41 + this.responsesCounter = counterFactory.createStatsCounter(key, RESPONSES);
  42 + this.failuresCounter = counterFactory.createStatsCounter(key, FAILURES);
  43 + }
  44 +
  45 + @Override
  46 + public void incrementRequests(int amount) {
  47 + requestsCounter.add(amount);
  48 + }
  49 +
  50 + @Override
  51 + public void incrementResponses(int amount) {
  52 + responsesCounter.add(amount);
  53 + }
  54 +
  55 + @Override
  56 + public void incrementFailures(int amount) {
  57 + failuresCounter.add(amount);
  58 + }
  59 +
  60 + @Override
  61 + public int getRequests() {
  62 + return requestsCounter.get();
  63 + }
  64 +
  65 + @Override
  66 + public int getResponses() {
  67 + return responsesCounter.get();
  68 + }
  69 +
  70 + @Override
  71 + public int getFailures() {
  72 + return failuresCounter.get();
  73 + }
  74 +
  75 + @Override
  76 + public void reset() {
  77 + requestsCounter.clear();
  78 + responsesCounter.clear();
  79 + failuresCounter.clear();
  80 + }
  81 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.stats;
  17 +
  18 +import org.thingsboard.server.queue.stats.QueueStats;
  19 +
  20 +public class DefaultQueueStats implements QueueStats {
  21 + private final StatsCounter totalCounter;
  22 + private final StatsCounter successfulCounter;
  23 + private final StatsCounter failedCounter;
  24 +
  25 + public DefaultQueueStats(StatsCounter totalCounter, StatsCounter successfulCounter, StatsCounter failedCounter) {
  26 + this.totalCounter = totalCounter;
  27 + this.successfulCounter = successfulCounter;
  28 + this.failedCounter = failedCounter;
  29 + }
  30 +
  31 + @Override
  32 + public void incrementTotal(int amount) {
  33 + totalCounter.add(amount);
  34 + }
  35 +
  36 + @Override
  37 + public void incrementSuccessful(int amount) {
  38 + successfulCounter.add(amount);
  39 + }
  40 +
  41 + @Override
  42 + public void incrementFailed(int amount) {
  43 + failedCounter.add(amount);
  44 + }
  45 +}
... ...
... ... @@ -104,7 +104,6 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS
104 104 }
105 105 }
106 106 });
107   - ruleEngineStats.reset();
108 107 }
109 108
110 109 private AssetId getServiceAssetId(TenantId tenantId, String queueName) {
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.stats;
  17 +
  18 +import io.micrometer.core.instrument.Counter;
  19 +
  20 +import java.util.concurrent.atomic.AtomicInteger;
  21 +
  22 +public class StatsCounter {
  23 + private final AtomicInteger aiCounter;
  24 + private final Counter micrometerCounter;
  25 + private final String name;
  26 +
  27 + public StatsCounter(AtomicInteger aiCounter, Counter micrometerCounter, String name) {
  28 + this.aiCounter = aiCounter;
  29 + this.micrometerCounter = micrometerCounter;
  30 + this.name = name;
  31 + }
  32 +
  33 + public void increment() {
  34 + aiCounter.incrementAndGet();
  35 + micrometerCounter.increment();
  36 + }
  37 +
  38 + public void clear() {
  39 + aiCounter.set(0);
  40 + }
  41 +
  42 + public int get() {
  43 + return aiCounter.get();
  44 + }
  45 +
  46 + public void add(int delta){
  47 + aiCounter.addAndGet(delta);
  48 + micrometerCounter.increment(delta);
  49 + }
  50 +
  51 + public String getName() {
  52 + return name;
  53 + }
  54 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.stats;
  17 +
  18 +import io.micrometer.core.instrument.Counter;
  19 +import io.micrometer.core.instrument.MeterRegistry;
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.springframework.beans.factory.annotation.Value;
  22 +import org.springframework.stereotype.Service;
  23 +import org.thingsboard.server.service.metrics.StubCounter;
  24 +
  25 +import java.util.concurrent.atomic.AtomicInteger;
  26 +
  27 +@Service
  28 +public class StatsCounterFactory {
  29 + private static final String STATS_NAME_TAG = "statsName";
  30 +
  31 + private static final Counter STUB_COUNTER = new StubCounter();
  32 +
  33 + @Autowired
  34 + private MeterRegistry meterRegistry;
  35 +
  36 + @Value("${metrics.enabled}")
  37 + private Boolean metricsEnabled;
  38 +
  39 + public StatsCounter createStatsCounter(String key, String statsName) {
  40 + return new StatsCounter(
  41 + new AtomicInteger(0),
  42 + metricsEnabled ?
  43 + meterRegistry.counter(key, STATS_NAME_TAG, statsName)
  44 + : STUB_COUNTER,
  45 + statsName
  46 + );
  47 + }
  48 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.stats;
  17 +
  18 +public enum StatsType {
  19 + RULE_ENGINE("ruleEngine"), CORE("core"), TRANSPORT("transport"), JS_INVOKE("jsInvoke");
  20 +
  21 + private String name;
  22 +
  23 + StatsType(String name) {
  24 + this.name = name;
  25 + }
  26 +
  27 + public String getName() {
  28 + return name;
  29 + }
  30 +}
... ...
... ... @@ -29,6 +29,10 @@ import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestM
29 29 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
30 30 import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
31 31 import org.thingsboard.server.queue.util.TbCoreComponent;
  32 +import org.thingsboard.server.service.stats.DefaultQueueStats;
  33 +import org.thingsboard.server.service.stats.StatsCounter;
  34 +import org.thingsboard.server.service.stats.StatsCounterFactory;
  35 +import org.thingsboard.server.service.stats.StatsType;
32 36
33 37 import javax.annotation.PostConstruct;
34 38 import javax.annotation.PreDestroy;
... ... @@ -41,9 +45,13 @@ import java.util.concurrent.*;
41 45 @Service
42 46 @TbCoreComponent
43 47 public class TbCoreTransportApiService {
  48 + private static final String TOTAL_MSGS = "totalMsgs";
  49 + private static final String SUCCESSFUL_MSGS = "successfulMsgs";
  50 + private static final String FAILED_MSGS = "failedMsgs";
44 51
45 52 private final TbCoreQueueFactory tbCoreQueueFactory;
46 53 private final TransportApiService transportApiService;
  54 + private final StatsCounterFactory counterFactory;
47 55
48 56 @Value("${queue.transport_api.max_pending_requests:10000}")
49 57 private int maxPendingRequests;
... ... @@ -58,9 +66,10 @@ public class TbCoreTransportApiService {
58 66 private TbQueueResponseTemplate<TbProtoQueueMsg<TransportApiRequestMsg>,
59 67 TbProtoQueueMsg<TransportApiResponseMsg>> transportApiTemplate;
60 68
61   - public TbCoreTransportApiService(TbCoreQueueFactory tbCoreQueueFactory, TransportApiService transportApiService) {
  69 + public TbCoreTransportApiService(TbCoreQueueFactory tbCoreQueueFactory, TransportApiService transportApiService, StatsCounterFactory counterFactory) {
62 70 this.tbCoreQueueFactory = tbCoreQueueFactory;
63 71 this.transportApiService = transportApiService;
  72 + this.counterFactory = counterFactory;
64 73 }
65 74
66 75 @PostConstruct
... ... @@ -69,6 +78,12 @@ public class TbCoreTransportApiService {
69 78 TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> producer = tbCoreQueueFactory.createTransportApiResponseProducer();
70 79 TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> consumer = tbCoreQueueFactory.createTransportApiRequestConsumer();
71 80
  81 + String key = StatsType.TRANSPORT.getName();
  82 + StatsCounter totalCounter = counterFactory.createStatsCounter(key, TOTAL_MSGS);
  83 + StatsCounter successfulCounter = counterFactory.createStatsCounter(key, SUCCESSFUL_MSGS);
  84 + StatsCounter failedCounter = counterFactory.createStatsCounter(key, FAILED_MSGS);
  85 + DefaultQueueStats queueStats = new DefaultQueueStats(totalCounter, successfulCounter, failedCounter);
  86 +
72 87 DefaultTbQueueResponseTemplate.DefaultTbQueueResponseTemplateBuilder
73 88 <TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> builder = DefaultTbQueueResponseTemplate.builder();
74 89 builder.requestTemplate(consumer);
... ... @@ -78,6 +93,7 @@ public class TbCoreTransportApiService {
78 93 builder.pollInterval(responsePollDuration);
79 94 builder.executor(transportCallbackExecutor);
80 95 builder.handler(transportApiService);
  96 + builder.stats(queueStats);
81 97 transportApiTemplate = builder.build();
82 98 }
83 99
... ...
... ... @@ -754,3 +754,13 @@ service:
754 754 id: "${TB_SERVICE_ID:}"
755 755 tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id.
756 756
  757 +metrics:
  758 + # Enable/disable actuator metrics.
  759 + enabled: "${METRICS_ENABLED:false}"
  760 +
  761 +management:
  762 + endpoints:
  763 + web:
  764 + exposure:
  765 + # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics).
  766 + include: '${METRICS_ENDPOINTS_EXPOSE:info}'
\ No newline at end of file
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.actors;
  17 +
  18 +public interface JsInvokeStats {
  19 + default void incrementRequests() {
  20 + incrementRequests(1);
  21 + }
  22 +
  23 + void incrementRequests(int amount);
  24 +
  25 + default void incrementResponses() {
  26 + incrementResponses(1);
  27 + }
  28 +
  29 + void incrementResponses(int amount);
  30 +
  31 + default void incrementFailures() {
  32 + incrementFailures(1);
  33 + }
  34 +
  35 + void incrementFailures(int amount);
  36 +
  37 + int getRequests();
  38 +
  39 + int getResponses();
  40 +
  41 + int getFailures();
  42 +
  43 + void reset();
  44 +}
... ...
... ... @@ -23,6 +23,7 @@ import org.thingsboard.server.queue.TbQueueHandler;
23 23 import org.thingsboard.server.queue.TbQueueMsg;
24 24 import org.thingsboard.server.queue.TbQueueProducer;
25 25 import org.thingsboard.server.queue.TbQueueResponseTemplate;
  26 +import org.thingsboard.server.queue.stats.QueueStats;
26 27
27 28 import java.util.List;
28 29 import java.util.UUID;
... ... @@ -44,6 +45,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
44 45 private final ExecutorService loopExecutor;
45 46 private final ScheduledExecutorService timeoutExecutor;
46 47 private final ExecutorService callbackExecutor;
  48 + private final QueueStats stats;
47 49 private final int maxPendingRequests;
48 50 private final long requestTimeout;
49 51
... ... @@ -58,7 +60,8 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
58 60 long pollInterval,
59 61 long requestTimeout,
60 62 int maxPendingRequests,
61   - ExecutorService executor) {
  63 + ExecutorService executor,
  64 + QueueStats stats) {
62 65 this.requestTemplate = requestTemplate;
63 66 this.responseTemplate = responseTemplate;
64 67 this.pendingRequests = new ConcurrentHashMap<>();
... ... @@ -66,6 +69,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
66 69 this.pollInterval = pollInterval;
67 70 this.requestTimeout = requestTimeout;
68 71 this.callbackExecutor = executor;
  72 + this.stats = stats;
69 73 this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
70 74 this.loopExecutor = Executors.newSingleThreadExecutor();
71 75 }
... ... @@ -108,11 +112,13 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
108 112 String responseTopic = bytesToString(responseTopicHeader);
109 113 try {
110 114 pendingRequestCount.getAndIncrement();
  115 + stats.incrementTotal();
111 116 AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(request),
112 117 response -> {
113 118 pendingRequestCount.decrementAndGet();
114 119 response.getHeaders().put(REQUEST_ID_HEADER, uuidToBytes(requestId));
115 120 responseTemplate.send(TopicPartitionInfo.builder().topic(responseTopic).build(), response, null);
  121 + stats.incrementSuccessful();
116 122 },
117 123 e -> {
118 124 pendingRequestCount.decrementAndGet();
... ... @@ -121,6 +127,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
121 127 } else {
122 128 log.trace("[{}] Failed to process the request: {}", requestId, request, e);
123 129 }
  130 + stats.incrementFailed();
124 131 },
125 132 requestTimeout,
126 133 timeoutExecutor,
... ... @@ -128,6 +135,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
128 135 } catch (Throwable e) {
129 136 pendingRequestCount.decrementAndGet();
130 137 log.warn("[{}] Failed to process the request: {}", requestId, request, e);
  138 + stats.incrementFailed();
131 139 }
132 140 }
133 141 });
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.queue.stats;
  17 +
  18 +public interface QueueStats {
  19 + default void incrementTotal() {
  20 + incrementTotal(1);
  21 + }
  22 +
  23 + void incrementTotal(int amount);
  24 +
  25 + default void incrementSuccessful() {
  26 + incrementSuccessful(1);
  27 + }
  28 +
  29 + void incrementSuccessful(int amount);
  30 +
  31 +
  32 + default void incrementFailed() {
  33 + incrementFailed(1);
  34 + }
  35 +
  36 + void incrementFailed(int amount);
  37 +}
... ...
... ... @@ -105,6 +105,7 @@
105 105 <ua-parser.version>1.4.3</ua-parser.version>
106 106 <commons-beanutils.version>1.9.4</commons-beanutils.version>
107 107 <commons-collections.version>3.2.2</commons-collections.version>
  108 + <micrometer.version>1.5.2</micrometer.version>
108 109 </properties>
109 110
110 111 <modules>
... ... @@ -1371,6 +1372,21 @@
1371 1372 <artifactId>struts-tiles</artifactId>
1372 1373 <version>${struts.version}</version>
1373 1374 </dependency>
  1375 + <dependency>
  1376 + <groupId>org.springframework.boot</groupId>
  1377 + <artifactId>spring-boot-starter-actuator</artifactId>
  1378 + <version>${spring-boot.version}</version>
  1379 + </dependency>
  1380 + <dependency>
  1381 + <groupId>io.micrometer</groupId>
  1382 + <artifactId>micrometer-core</artifactId>
  1383 + <version>${micrometer.version}</version>
  1384 + </dependency>
  1385 + <dependency>
  1386 + <groupId>io.micrometer</groupId>
  1387 + <artifactId>micrometer-registry-prometheus</artifactId>
  1388 + <version>${micrometer.version}</version>
  1389 + </dependency>
1374 1390 </dependencies>
1375 1391 </dependencyManagement>
1376 1392
... ...