Commit 89419c6999cc7b960d6f40fbb6e9b785a81c38dd
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 | +} | ... | ... |
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 | ... | ... |