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,6 +298,18 @@
298 <groupId>com.github.ua-parser</groupId> 298 <groupId>com.github.ua-parser</groupId>
299 <artifactId>uap-java</artifactId> 299 <artifactId>uap-java</artifactId>
300 </dependency> 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 </dependencies> 313 </dependencies>
302 314
303 <build> 315 <build>
@@ -219,6 +219,10 @@ public class ActorSystemContext { @@ -219,6 +219,10 @@ public class ActorSystemContext {
219 @Getter 219 @Getter
220 private ClaimDevicesService claimDevicesService; 220 private ClaimDevicesService claimDevicesService;
221 221
  222 + @Autowired
  223 + @Getter
  224 + private JsInvokeStats jsInvokeStats;
  225 +
222 //TODO: separate context for TbCore and TbRuleEngine 226 //TODO: separate context for TbCore and TbRuleEngine
223 @Autowired(required = false) 227 @Autowired(required = false)
224 @Getter 228 @Getter
@@ -272,19 +276,14 @@ public class ActorSystemContext { @@ -272,19 +276,14 @@ public class ActorSystemContext {
272 @Getter 276 @Getter
273 private long statisticsPersistFrequency; 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 @Scheduled(fixedDelayString = "${actors.statistics.js_print_interval_ms}") 280 @Scheduled(fixedDelayString = "${actors.statistics.js_print_interval_ms}")
283 public void printStats() { 281 public void printStats() {
284 if (statisticsEnabled) { 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 log.info("Rule Engine JS Invoke Stats: requests [{}] responses [{}] failures [{}]", 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,21 +292,21 @@ class DefaultTbContext implements TbContext {
292 @Override 292 @Override
293 public void logJsEvalRequest() { 293 public void logJsEvalRequest() {
294 if (mainCtx.isStatisticsEnabled()) { 294 if (mainCtx.isStatisticsEnabled()) {
295 - mainCtx.getJsInvokeRequestsCount().incrementAndGet(); 295 + mainCtx.getJsInvokeStats().incrementRequests();
296 } 296 }
297 } 297 }
298 298
299 @Override 299 @Override
300 public void logJsEvalResponse() { 300 public void logJsEvalResponse() {
301 if (mainCtx.isStatisticsEnabled()) { 301 if (mainCtx.isStatisticsEnabled()) {
302 - mainCtx.getJsInvokeResponsesCount().incrementAndGet(); 302 + mainCtx.getJsInvokeStats().incrementResponses();
303 } 303 }
304 } 304 }
305 305
306 @Override 306 @Override
307 public void logJsEvalFailure() { 307 public void logJsEvalFailure() {
308 if (mainCtx.isStatisticsEnabled()) { 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,16 +26,7 @@ import org.thingsboard.server.common.msg.MsgType;
26 import org.thingsboard.server.common.msg.TbActorMsg; 26 import org.thingsboard.server.common.msg.TbActorMsg;
27 import org.thingsboard.server.common.msg.queue.ServiceType; 27 import org.thingsboard.server.common.msg.queue.ServiceType;
28 import org.thingsboard.server.common.msg.queue.TbCallback; 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 import org.thingsboard.server.queue.TbQueueConsumer; 30 import org.thingsboard.server.queue.TbQueueConsumer;
40 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 31 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
41 import org.thingsboard.server.queue.discovery.PartitionChangeEvent; 32 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
@@ -47,6 +38,7 @@ import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; @@ -47,6 +38,7 @@ import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
47 import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; 38 import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
48 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 39 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
49 import org.thingsboard.server.service.state.DeviceStateService; 40 import org.thingsboard.server.service.state.DeviceStateService;
  41 +import org.thingsboard.server.service.stats.StatsCounterFactory;
50 import org.thingsboard.server.service.subscription.SubscriptionManagerService; 42 import org.thingsboard.server.service.subscription.SubscriptionManagerService;
51 import org.thingsboard.server.service.subscription.TbLocalSubscriptionService; 43 import org.thingsboard.server.service.subscription.TbLocalSubscriptionService;
52 import org.thingsboard.server.service.subscription.TbSubscriptionUtils; 44 import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
@@ -81,18 +73,19 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore @@ -81,18 +73,19 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
81 private final TbLocalSubscriptionService localSubscriptionService; 73 private final TbLocalSubscriptionService localSubscriptionService;
82 private final SubscriptionManagerService subscriptionManagerService; 74 private final SubscriptionManagerService subscriptionManagerService;
83 private final TbCoreDeviceRpcService tbCoreDeviceRpcService; 75 private final TbCoreDeviceRpcService tbCoreDeviceRpcService;
84 - private final TbCoreConsumerStats stats = new TbCoreConsumerStats(); 76 + private final TbCoreConsumerStats stats;
85 77
86 public DefaultTbCoreConsumerService(TbCoreQueueFactory tbCoreQueueFactory, ActorSystemContext actorContext, 78 public DefaultTbCoreConsumerService(TbCoreQueueFactory tbCoreQueueFactory, ActorSystemContext actorContext,
87 DeviceStateService stateService, TbLocalSubscriptionService localSubscriptionService, 79 DeviceStateService stateService, TbLocalSubscriptionService localSubscriptionService,
88 SubscriptionManagerService subscriptionManagerService, DataDecodingEncodingService encodingService, 80 SubscriptionManagerService subscriptionManagerService, DataDecodingEncodingService encodingService,
89 - TbCoreDeviceRpcService tbCoreDeviceRpcService) { 81 + TbCoreDeviceRpcService tbCoreDeviceRpcService, StatsCounterFactory counterFactory) {
90 super(actorContext, encodingService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer()); 82 super(actorContext, encodingService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer());
91 this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer(); 83 this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer();
92 this.stateService = stateService; 84 this.stateService = stateService;
93 this.localSubscriptionService = localSubscriptionService; 85 this.localSubscriptionService = localSubscriptionService;
94 this.subscriptionManagerService = subscriptionManagerService; 86 this.subscriptionManagerService = subscriptionManagerService;
95 this.tbCoreDeviceRpcService = tbCoreDeviceRpcService; 87 this.tbCoreDeviceRpcService = tbCoreDeviceRpcService;
  88 + this.stats = new TbCoreConsumerStats(counterFactory);
96 } 89 }
97 90
98 @PostConstruct 91 @PostConstruct
@@ -228,6 +221,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore @@ -228,6 +221,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
228 public void printStats() { 221 public void printStats() {
229 if (statsEnabled) { 222 if (statsEnabled) {
230 stats.printStats(); 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,6 +52,7 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrateg
52 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 52 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
53 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; 53 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
54 import org.thingsboard.server.service.stats.RuleEngineStatisticsService; 54 import org.thingsboard.server.service.stats.RuleEngineStatisticsService;
  55 +import org.thingsboard.server.service.stats.StatsCounterFactory;
55 56
56 import javax.annotation.PostConstruct; 57 import javax.annotation.PostConstruct;
57 import javax.annotation.PreDestroy; 58 import javax.annotation.PreDestroy;
@@ -79,6 +80,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -79,6 +80,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
79 @Value("${queue.rule-engine.stats.enabled:true}") 80 @Value("${queue.rule-engine.stats.enabled:true}")
80 private boolean statsEnabled; 81 private boolean statsEnabled;
81 82
  83 + private final StatsCounterFactory counterFactory;
82 private final TbRuleEngineSubmitStrategyFactory submitStrategyFactory; 84 private final TbRuleEngineSubmitStrategyFactory submitStrategyFactory;
83 private final TbRuleEngineProcessingStrategyFactory processingStrategyFactory; 85 private final TbRuleEngineProcessingStrategyFactory processingStrategyFactory;
84 private final TbRuleEngineQueueFactory tbRuleEngineQueueFactory; 86 private final TbRuleEngineQueueFactory tbRuleEngineQueueFactory;
@@ -95,7 +97,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -95,7 +97,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
95 TbQueueRuleEngineSettings ruleEngineSettings, 97 TbQueueRuleEngineSettings ruleEngineSettings,
96 TbRuleEngineQueueFactory tbRuleEngineQueueFactory, RuleEngineStatisticsService statisticsService, 98 TbRuleEngineQueueFactory tbRuleEngineQueueFactory, RuleEngineStatisticsService statisticsService,
97 ActorSystemContext actorContext, DataDecodingEncodingService encodingService, 99 ActorSystemContext actorContext, DataDecodingEncodingService encodingService,
98 - TbRuleEngineDeviceRpcService tbDeviceRpcService) { 100 + TbRuleEngineDeviceRpcService tbDeviceRpcService,
  101 + StatsCounterFactory counterFactory) {
99 super(actorContext, encodingService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer()); 102 super(actorContext, encodingService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer());
100 this.statisticsService = statisticsService; 103 this.statisticsService = statisticsService;
101 this.ruleEngineSettings = ruleEngineSettings; 104 this.ruleEngineSettings = ruleEngineSettings;
@@ -103,6 +106,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -103,6 +106,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
103 this.submitStrategyFactory = submitStrategyFactory; 106 this.submitStrategyFactory = submitStrategyFactory;
104 this.processingStrategyFactory = processingStrategyFactory; 107 this.processingStrategyFactory = processingStrategyFactory;
105 this.tbDeviceRpcService = tbDeviceRpcService; 108 this.tbDeviceRpcService = tbDeviceRpcService;
  109 + this.counterFactory = counterFactory;
106 } 110 }
107 111
108 @PostConstruct 112 @PostConstruct
@@ -111,7 +115,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -111,7 +115,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
111 for (TbRuleEngineQueueConfiguration configuration : ruleEngineSettings.getQueues()) { 115 for (TbRuleEngineQueueConfiguration configuration : ruleEngineSettings.getQueues()) {
112 consumerConfigurations.putIfAbsent(configuration.getName(), configuration); 116 consumerConfigurations.putIfAbsent(configuration.getName(), configuration);
113 consumers.computeIfAbsent(configuration.getName(), queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration)); 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 submitExecutor = Executors.newSingleThreadExecutor(); 120 submitExecutor = Executors.newSingleThreadExecutor();
117 } 121 }
@@ -269,6 +273,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -269,6 +273,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
269 consumerStats.forEach((queue, stats) -> { 273 consumerStats.forEach((queue, stats) -> {
270 stats.printStats(); 274 stats.printStats();
271 statisticsService.reportQueueStats(ts, stats); 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,76 +17,124 @@ package org.thingsboard.server.service.queue;
17 17
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.thingsboard.server.gen.transport.TransportProtos; 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 import java.util.concurrent.atomic.AtomicInteger; 25 import java.util.concurrent.atomic.AtomicInteger;
22 26
23 @Slf4j 27 @Slf4j
24 public class TbCoreConsumerStats { 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 public void log(TransportProtos.TransportToDeviceActorMsg msg) { 86 public void log(TransportProtos.TransportToDeviceActorMsg msg) {
40 - totalCounter.incrementAndGet(); 87 + totalCounter.increment();
41 if (msg.hasSessionEvent()) { 88 if (msg.hasSessionEvent()) {
42 - sessionEventCounter.incrementAndGet(); 89 + sessionEventCounter.increment();
43 } 90 }
44 if (msg.hasGetAttributes()) { 91 if (msg.hasGetAttributes()) {
45 - getAttributesCounter.incrementAndGet(); 92 + getAttributesCounter.increment();
46 } 93 }
47 if (msg.hasSubscribeToAttributes()) { 94 if (msg.hasSubscribeToAttributes()) {
48 - subscribeToAttributesCounter.incrementAndGet(); 95 + subscribeToAttributesCounter.increment();
49 } 96 }
50 if (msg.hasSubscribeToRPC()) { 97 if (msg.hasSubscribeToRPC()) {
51 - subscribeToRPCCounter.incrementAndGet(); 98 + subscribeToRPCCounter.increment();
52 } 99 }
53 if (msg.hasToDeviceRPCCallResponse()) { 100 if (msg.hasToDeviceRPCCallResponse()) {
54 - toDeviceRPCCallResponseCounter.incrementAndGet(); 101 + toDeviceRPCCallResponseCounter.increment();
55 } 102 }
56 if (msg.hasSubscriptionInfo()) { 103 if (msg.hasSubscriptionInfo()) {
57 - subscriptionInfoCounter.incrementAndGet(); 104 + subscriptionInfoCounter.increment();
58 } 105 }
59 if (msg.hasClaimDevice()) { 106 if (msg.hasClaimDevice()) {
60 - claimDeviceCounter.incrementAndGet(); 107 + claimDeviceCounter.increment();
61 } 108 }
62 } 109 }
63 110
64 public void log(TransportProtos.DeviceStateServiceMsgProto msg) { 111 public void log(TransportProtos.DeviceStateServiceMsgProto msg) {
65 - totalCounter.incrementAndGet();  
66 - deviceStateCounter.incrementAndGet(); 112 + totalCounter.increment();
  113 + deviceStateCounter.increment();
67 } 114 }
68 115
69 public void log(TransportProtos.SubscriptionMgrMsgProto msg) { 116 public void log(TransportProtos.SubscriptionMgrMsgProto msg) {
70 - totalCounter.incrementAndGet();  
71 - subscriptionMsgCounter.incrementAndGet(); 117 + totalCounter.increment();
  118 + subscriptionMsgCounter.increment();
72 } 119 }
73 120
74 public void log(TransportProtos.ToCoreNotificationMsg msg) { 121 public void log(TransportProtos.ToCoreNotificationMsg msg) {
75 - totalCounter.incrementAndGet();  
76 - toCoreNotificationsCounter.incrementAndGet(); 122 + totalCounter.increment();
  123 + toCoreNotificationsCounter.increment();
77 } 124 }
78 125
79 public void printStats() { 126 public void printStats() {
80 - int total = totalCounter.getAndSet(0); 127 + int total = totalCounter.get();
81 if (total > 0) { 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,16 +22,16 @@ import org.thingsboard.server.common.msg.queue.RuleEngineException;
22 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; 22 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
23 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 23 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
24 import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; 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 import java.util.concurrent.ConcurrentHashMap; 30 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.ConcurrentMap; 31 import java.util.concurrent.ConcurrentMap;
31 import java.util.concurrent.atomic.AtomicInteger; 32 import java.util.concurrent.atomic.AtomicInteger;
32 33
33 @Slf4j 34 @Slf4j
34 -@Data  
35 public class TbRuleEngineConsumerStats { 35 public class TbRuleEngineConsumerStats {
36 36
37 public static final String TOTAL_MSGS = "totalMsgs"; 37 public static final String TOTAL_MSGS = "totalMsgs";
@@ -43,61 +43,72 @@ public class TbRuleEngineConsumerStats { @@ -43,61 +43,72 @@ public class TbRuleEngineConsumerStats {
43 public static final String SUCCESSFUL_ITERATIONS = "successfulIterations"; 43 public static final String SUCCESSFUL_ITERATIONS = "successfulIterations";
44 public static final String FAILED_ITERATIONS = "failedIterations"; 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 private final ConcurrentMap<UUID, TbTenantRuleEngineStats> tenantStats = new ConcurrentHashMap<>(); 58 private final ConcurrentMap<UUID, TbTenantRuleEngineStats> tenantStats = new ConcurrentHashMap<>();
59 private final ConcurrentMap<TenantId, RuleEngineException> tenantExceptions = new ConcurrentHashMap<>(); 59 private final ConcurrentMap<TenantId, RuleEngineException> tenantExceptions = new ConcurrentHashMap<>();
60 60
61 private final String queueName; 61 private final String queueName;
62 62
63 - public TbRuleEngineConsumerStats(String queueName) { 63 + public TbRuleEngineConsumerStats(String queueName, StatsCounterFactory counterFactory) {
64 this.queueName = queueName; 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 public void log(TbRuleEngineProcessingResult msg, boolean finalIterationForPack) { 87 public void log(TbRuleEngineProcessingResult msg, boolean finalIterationForPack) {
77 int success = msg.getSuccessMap().size(); 88 int success = msg.getSuccessMap().size();
78 int pending = msg.getPendingMap().size(); 89 int pending = msg.getPendingMap().size();
79 int failed = msg.getFailedMap().size(); 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 msg.getSuccessMap().values().forEach(m -> getTenantStats(m).logSuccess()); 93 msg.getSuccessMap().values().forEach(m -> getTenantStats(m).logSuccess());
83 if (finalIterationForPack) { 94 if (finalIterationForPack) {
84 if (pending > 0 || failed > 0) { 95 if (pending > 0 || failed > 0) {
85 - timeoutMsgCounter.addAndGet(pending);  
86 - failedMsgCounter.addAndGet(failed); 96 + timeoutMsgCounter.add(pending);
  97 + failedMsgCounter.add(failed);
87 if (pending > 0) { 98 if (pending > 0) {
88 msg.getPendingMap().values().forEach(m -> getTenantStats(m).logTimeout()); 99 msg.getPendingMap().values().forEach(m -> getTenantStats(m).logTimeout());
89 } 100 }
90 if (failed > 0) { 101 if (failed > 0) {
91 msg.getFailedMap().values().forEach(m -> getTenantStats(m).logFailed()); 102 msg.getFailedMap().values().forEach(m -> getTenantStats(m).logFailed());
92 } 103 }
93 - failedIterationsCounter.incrementAndGet(); 104 + failedIterationsCounter.increment();
94 } else { 105 } else {
95 - successIterationsCounter.incrementAndGet(); 106 + successIterationsCounter.increment();
96 } 107 }
97 } else { 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 if (pending > 0) { 112 if (pending > 0) {
102 msg.getPendingMap().values().forEach(m -> getTenantStats(m).logTmpTimeout()); 113 msg.getPendingMap().values().forEach(m -> getTenantStats(m).logTmpTimeout());
103 } 114 }
@@ -113,19 +124,31 @@ public class TbRuleEngineConsumerStats { @@ -113,19 +124,31 @@ public class TbRuleEngineConsumerStats {
113 return tenantStats.computeIfAbsent(new UUID(reMsg.getTenantIdMSB(), reMsg.getTenantIdLSB()), TbTenantRuleEngineStats::new); 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 public void printStats() { 139 public void printStats() {
117 int total = totalMsgCounter.get(); 140 int total = totalMsgCounter.get();
118 if (total > 0) { 141 if (total > 0) {
119 StringBuilder stats = new StringBuilder(); 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 log.info("[{}] Stats: {}", queueName, stats); 146 log.info("[{}] Stats: {}", queueName, stats);
124 } 147 }
125 } 148 }
126 149
127 public void reset() { 150 public void reset() {
128 - counters.values().forEach(counter -> counter.set(0)); 151 + counters.forEach(StatsCounter::clear);
129 tenantStats.clear(); 152 tenantStats.clear();
130 tenantExceptions.clear(); 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,7 +104,6 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS
104 } 104 }
105 } 105 }
106 }); 106 });
107 - ruleEngineStats.reset();  
108 } 107 }
109 108
110 private AssetId getServiceAssetId(TenantId tenantId, String queueName) { 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,6 +29,10 @@ import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestM
29 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; 29 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
30 import org.thingsboard.server.queue.provider.TbCoreQueueFactory; 30 import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
31 import org.thingsboard.server.queue.util.TbCoreComponent; 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 import javax.annotation.PostConstruct; 37 import javax.annotation.PostConstruct;
34 import javax.annotation.PreDestroy; 38 import javax.annotation.PreDestroy;
@@ -41,9 +45,13 @@ import java.util.concurrent.*; @@ -41,9 +45,13 @@ import java.util.concurrent.*;
41 @Service 45 @Service
42 @TbCoreComponent 46 @TbCoreComponent
43 public class TbCoreTransportApiService { 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 private final TbCoreQueueFactory tbCoreQueueFactory; 52 private final TbCoreQueueFactory tbCoreQueueFactory;
46 private final TransportApiService transportApiService; 53 private final TransportApiService transportApiService;
  54 + private final StatsCounterFactory counterFactory;
47 55
48 @Value("${queue.transport_api.max_pending_requests:10000}") 56 @Value("${queue.transport_api.max_pending_requests:10000}")
49 private int maxPendingRequests; 57 private int maxPendingRequests;
@@ -58,9 +66,10 @@ public class TbCoreTransportApiService { @@ -58,9 +66,10 @@ public class TbCoreTransportApiService {
58 private TbQueueResponseTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, 66 private TbQueueResponseTemplate<TbProtoQueueMsg<TransportApiRequestMsg>,
59 TbProtoQueueMsg<TransportApiResponseMsg>> transportApiTemplate; 67 TbProtoQueueMsg<TransportApiResponseMsg>> transportApiTemplate;
60 68
61 - public TbCoreTransportApiService(TbCoreQueueFactory tbCoreQueueFactory, TransportApiService transportApiService) { 69 + public TbCoreTransportApiService(TbCoreQueueFactory tbCoreQueueFactory, TransportApiService transportApiService, StatsCounterFactory counterFactory) {
62 this.tbCoreQueueFactory = tbCoreQueueFactory; 70 this.tbCoreQueueFactory = tbCoreQueueFactory;
63 this.transportApiService = transportApiService; 71 this.transportApiService = transportApiService;
  72 + this.counterFactory = counterFactory;
64 } 73 }
65 74
66 @PostConstruct 75 @PostConstruct
@@ -69,6 +78,12 @@ public class TbCoreTransportApiService { @@ -69,6 +78,12 @@ public class TbCoreTransportApiService {
69 TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> producer = tbCoreQueueFactory.createTransportApiResponseProducer(); 78 TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> producer = tbCoreQueueFactory.createTransportApiResponseProducer();
70 TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> consumer = tbCoreQueueFactory.createTransportApiRequestConsumer(); 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 DefaultTbQueueResponseTemplate.DefaultTbQueueResponseTemplateBuilder 87 DefaultTbQueueResponseTemplate.DefaultTbQueueResponseTemplateBuilder
73 <TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> builder = DefaultTbQueueResponseTemplate.builder(); 88 <TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> builder = DefaultTbQueueResponseTemplate.builder();
74 builder.requestTemplate(consumer); 89 builder.requestTemplate(consumer);
@@ -78,6 +93,7 @@ public class TbCoreTransportApiService { @@ -78,6 +93,7 @@ public class TbCoreTransportApiService {
78 builder.pollInterval(responsePollDuration); 93 builder.pollInterval(responsePollDuration);
79 builder.executor(transportCallbackExecutor); 94 builder.executor(transportCallbackExecutor);
80 builder.handler(transportApiService); 95 builder.handler(transportApiService);
  96 + builder.stats(queueStats);
81 transportApiTemplate = builder.build(); 97 transportApiTemplate = builder.build();
82 } 98 }
83 99
@@ -754,3 +754,13 @@ service: @@ -754,3 +754,13 @@ service:
754 id: "${TB_SERVICE_ID:}" 754 id: "${TB_SERVICE_ID:}"
755 tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id. 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}'
  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,6 +23,7 @@ import org.thingsboard.server.queue.TbQueueHandler;
23 import org.thingsboard.server.queue.TbQueueMsg; 23 import org.thingsboard.server.queue.TbQueueMsg;
24 import org.thingsboard.server.queue.TbQueueProducer; 24 import org.thingsboard.server.queue.TbQueueProducer;
25 import org.thingsboard.server.queue.TbQueueResponseTemplate; 25 import org.thingsboard.server.queue.TbQueueResponseTemplate;
  26 +import org.thingsboard.server.queue.stats.QueueStats;
26 27
27 import java.util.List; 28 import java.util.List;
28 import java.util.UUID; 29 import java.util.UUID;
@@ -44,6 +45,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response @@ -44,6 +45,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
44 private final ExecutorService loopExecutor; 45 private final ExecutorService loopExecutor;
45 private final ScheduledExecutorService timeoutExecutor; 46 private final ScheduledExecutorService timeoutExecutor;
46 private final ExecutorService callbackExecutor; 47 private final ExecutorService callbackExecutor;
  48 + private final QueueStats stats;
47 private final int maxPendingRequests; 49 private final int maxPendingRequests;
48 private final long requestTimeout; 50 private final long requestTimeout;
49 51
@@ -58,7 +60,8 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response @@ -58,7 +60,8 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
58 long pollInterval, 60 long pollInterval,
59 long requestTimeout, 61 long requestTimeout,
60 int maxPendingRequests, 62 int maxPendingRequests,
61 - ExecutorService executor) { 63 + ExecutorService executor,
  64 + QueueStats stats) {
62 this.requestTemplate = requestTemplate; 65 this.requestTemplate = requestTemplate;
63 this.responseTemplate = responseTemplate; 66 this.responseTemplate = responseTemplate;
64 this.pendingRequests = new ConcurrentHashMap<>(); 67 this.pendingRequests = new ConcurrentHashMap<>();
@@ -66,6 +69,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response @@ -66,6 +69,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
66 this.pollInterval = pollInterval; 69 this.pollInterval = pollInterval;
67 this.requestTimeout = requestTimeout; 70 this.requestTimeout = requestTimeout;
68 this.callbackExecutor = executor; 71 this.callbackExecutor = executor;
  72 + this.stats = stats;
69 this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(); 73 this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
70 this.loopExecutor = Executors.newSingleThreadExecutor(); 74 this.loopExecutor = Executors.newSingleThreadExecutor();
71 } 75 }
@@ -108,11 +112,13 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response @@ -108,11 +112,13 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
108 String responseTopic = bytesToString(responseTopicHeader); 112 String responseTopic = bytesToString(responseTopicHeader);
109 try { 113 try {
110 pendingRequestCount.getAndIncrement(); 114 pendingRequestCount.getAndIncrement();
  115 + stats.incrementTotal();
111 AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(request), 116 AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(request),
112 response -> { 117 response -> {
113 pendingRequestCount.decrementAndGet(); 118 pendingRequestCount.decrementAndGet();
114 response.getHeaders().put(REQUEST_ID_HEADER, uuidToBytes(requestId)); 119 response.getHeaders().put(REQUEST_ID_HEADER, uuidToBytes(requestId));
115 responseTemplate.send(TopicPartitionInfo.builder().topic(responseTopic).build(), response, null); 120 responseTemplate.send(TopicPartitionInfo.builder().topic(responseTopic).build(), response, null);
  121 + stats.incrementSuccessful();
116 }, 122 },
117 e -> { 123 e -> {
118 pendingRequestCount.decrementAndGet(); 124 pendingRequestCount.decrementAndGet();
@@ -121,6 +127,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response @@ -121,6 +127,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
121 } else { 127 } else {
122 log.trace("[{}] Failed to process the request: {}", requestId, request, e); 128 log.trace("[{}] Failed to process the request: {}", requestId, request, e);
123 } 129 }
  130 + stats.incrementFailed();
124 }, 131 },
125 requestTimeout, 132 requestTimeout,
126 timeoutExecutor, 133 timeoutExecutor,
@@ -128,6 +135,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response @@ -128,6 +135,7 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
128 } catch (Throwable e) { 135 } catch (Throwable e) {
129 pendingRequestCount.decrementAndGet(); 136 pendingRequestCount.decrementAndGet();
130 log.warn("[{}] Failed to process the request: {}", requestId, request, e); 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,6 +105,7 @@
105 <ua-parser.version>1.4.3</ua-parser.version> 105 <ua-parser.version>1.4.3</ua-parser.version>
106 <commons-beanutils.version>1.9.4</commons-beanutils.version> 106 <commons-beanutils.version>1.9.4</commons-beanutils.version>
107 <commons-collections.version>3.2.2</commons-collections.version> 107 <commons-collections.version>3.2.2</commons-collections.version>
  108 + <micrometer.version>1.5.2</micrometer.version>
108 </properties> 109 </properties>
109 110
110 <modules> 111 <modules>
@@ -1371,6 +1372,21 @@ @@ -1371,6 +1372,21 @@
1371 <artifactId>struts-tiles</artifactId> 1372 <artifactId>struts-tiles</artifactId>
1372 <version>${struts.version}</version> 1373 <version>${struts.version}</version>
1373 </dependency> 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 </dependencies> 1390 </dependencies>
1375 </dependencyManagement> 1391 </dependencyManagement>
1376 1392