2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.drools.apps.controlloop.feature.trans;
23 import com.google.common.cache.CacheBuilder;
24 import com.google.common.cache.CacheLoader;
25 import com.google.common.cache.LoadingCache;
26 import com.google.common.cache.RemovalListener;
27 import com.google.common.cache.RemovalNotification;
29 import java.time.Instant;
30 import java.time.ZonedDateTime;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Properties;
34 import java.util.UUID;
35 import java.util.concurrent.TimeUnit;
37 import org.onap.policy.controlloop.ControlLoopOperation;
38 import org.onap.policy.controlloop.VirtualControlLoopNotification;
39 import org.onap.policy.drools.persistence.SystemPersistence;
40 import org.onap.policy.drools.system.PolicyController;
41 import org.onap.policy.drools.utils.logging.MDCTransaction;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * Control Loop Metrics Tracker
48 public interface ControlLoopMetrics {
51 * gets all transaction identifiers being monitored
53 * @return transaction id list
55 List<UUID> getTransactionIds();
58 * gets all detailed transactions
60 * @return list of transactions
62 List<VirtualControlLoopNotification> getTransactions();
65 * track controller's notification events
67 * @param controller policy controller sending out notification
68 * @param notification notification
70 void transactionEvent(PolicyController controller, VirtualControlLoopNotification notification);
73 * gets an in-progress transaction
75 * @param requestId request ID
76 * @return in progress notification
78 VirtualControlLoopNotification getTransaction(UUID requestId);
81 * removes an in-progress transaction
83 * @param requestId request ID
85 void removeTransaction(UUID requestId);
99 long getCacheOccupancy();
104 * @param cacheSize cache size
106 void setMaxCacheSize(long cacheSize);
109 * cached transaction expiration timeout in seconds
111 * @return transaction timeout in seconds
113 long getTransactionTimeout();
116 * sets transaction timeout in seconds
118 * @param transactionTimeout transaction timeout in seconds
120 void setTransactionTimeout(long transactionTimeout);
125 * @param cacheSize new cache size
126 * @param transactionTimeout new transaction timeout in seconds
128 void resetCache(long cacheSize, long transactionTimeout);
131 * refresh underlying transaction management
136 * singleton manager object
138 ControlLoopMetrics manager = new CacheBasedControlLoopMetricsManager();
143 * Control Loop Metrics Tracker Implementation
145 class CacheBasedControlLoopMetricsManager implements ControlLoopMetrics {
147 private static final Logger logger = LoggerFactory.getLogger(CacheBasedControlLoopMetricsManager.class);
149 private LoadingCache<UUID, VirtualControlLoopNotification> cache;
150 private long cacheSize = ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_DEFAULT;
152 private long transactionTimeout = ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_DEFAULT;
154 public CacheBasedControlLoopMetricsManager() {
156 Properties properties =
157 SystemPersistence.manager.getProperties(ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME);
163 Long.parseLong(properties.getProperty(ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_PROPERTY,
164 "" + ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_DEFAULT));
165 } catch (Exception e) {
166 logger.warn("{}:{} property cannot be accessed", ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME,
167 ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_PROPERTY, e);
170 /* transaction timeout */
173 this.transactionTimeout = Long
174 .parseLong(properties.getProperty(ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_PROPERTY,
175 "" + ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_DEFAULT));
176 } catch (Exception e) {
177 logger.warn("{}:{} property cannot be accessed", ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME,
178 ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_PROPERTY, e);
181 resetCache(this.cacheSize, this.transactionTimeout);
185 public void resetCache(long cacheSize, long transactionTimeout) {
186 this.cacheSize = cacheSize;
187 this.transactionTimeout = transactionTimeout;
189 CacheLoader<UUID, VirtualControlLoopNotification> loader =
190 new CacheLoader<UUID, VirtualControlLoopNotification>() {
193 public VirtualControlLoopNotification load(UUID key) throws Exception {
198 RemovalListener<UUID, VirtualControlLoopNotification> listener =
199 new RemovalListener<UUID, VirtualControlLoopNotification>() {
201 public void onRemoval(RemovalNotification<UUID, VirtualControlLoopNotification> notification) {
202 if (notification.wasEvicted()) {
203 evicted(notification.getValue());
205 logger.info("REMOVAL: {} because of {}", notification.getValue().getRequestId(),
206 notification.getCause().name());
211 synchronized (this) {
212 if (this.cache != null) {
213 this.cache.cleanUp();
214 this.cache.invalidateAll();
217 this.cache = CacheBuilder.newBuilder().maximumSize(this.cacheSize)
218 .expireAfterWrite(transactionTimeout, TimeUnit.SECONDS).removalListener(listener).build(loader);
223 public void refresh() {
224 this.cache.cleanUp();
228 public List<UUID> getTransactionIds() {
229 return new ArrayList<>(this.cache.asMap().keySet());
233 public List<VirtualControlLoopNotification> getTransactions() {
234 return new ArrayList<>(this.cache.asMap().values());
238 public void transactionEvent(PolicyController controller, VirtualControlLoopNotification notification) {
239 if (notification == null || notification.getRequestId() == null || notification.getNotification() == null) {
240 logger.warn("Invalid notification: {}", notification);
244 if (notification.getNotificationTime() == null) {
245 notification.setNotificationTime(ZonedDateTime.now());
248 notification.setFrom(notification.getFrom() + ":" + controller.getName());
250 switch (notification.getNotification()) {
255 endTransaction(notification);
259 case OPERATION_SUCCESS:
260 case OPERATION_FAILURE:
261 /* any other value is an in progress transaction */
262 inProgressTransaction(notification);
266 logger.warn("unexpected notification type {} in notification {}",
267 notification.getNotification().toString(), notification);
273 public VirtualControlLoopNotification getTransaction(UUID requestId) {
274 return cache.getIfPresent(requestId);
278 public void removeTransaction(UUID requestId) {
279 cache.invalidate(requestId);
283 * tracks an in progress control loop transaction
285 * @param notification control loop notification
287 protected void inProgressTransaction(VirtualControlLoopNotification notification) {
288 if (cache.getIfPresent(notification.getRequestId()) == null) {
289 cache.put(notification.getRequestId(), notification);
292 this.metric(notification);
296 * end of a control loop transaction
298 * @param notification control loop notification
300 protected void endTransaction(VirtualControlLoopNotification notification) {
301 ZonedDateTime startTime;
302 VirtualControlLoopNotification startNotification = cache.getIfPresent(notification.getRequestId());
303 if (startNotification != null) {
304 startTime = startNotification.getNotificationTime();
306 startTime = notification.getNotificationTime();
309 this.transaction(notification, startTime);
310 cache.invalidate(startNotification);
313 protected void evicted(VirtualControlLoopNotification notification) {
314 // transaction(notification, ZonedDateTime.now());
315 MDCTransaction trans = MDCTransaction
316 .newTransaction(notification.getRequestId().toString(), notification.getFrom())
317 .setServiceName(notification.getClosedLoopControlName()).setTargetEntity(notification.getTarget())
318 .setStartTime(notification.getNotificationTime().toInstant()).setEndTime(Instant.now())
319 .setResponseDescription("EVICTED").setStatusCode(false).metric().resetTransaction();
323 public long getCacheSize() {
324 return this.cacheSize;
328 public void setMaxCacheSize(long cacheSize) {
329 this.cacheSize = cacheSize;
333 public long getTransactionTimeout() {
334 return this.transactionTimeout;
338 public void setTransactionTimeout(long transactionTimeout) {
339 this.transactionTimeout = transactionTimeout;
343 public long getCacheOccupancy() {
344 return this.cache.size();
347 protected void metric(VirtualControlLoopNotification notification) {
348 MDCTransaction trans = MDCTransaction
349 .newTransaction(notification.getRequestId().toString(), notification.getFrom())
350 .setServiceName(notification.getClosedLoopControlName()).setTargetEntity(notification.getTarget());
352 List<ControlLoopOperation> operations = notification.getHistory();
353 switch (notification.getNotification()) {
355 trans.setStatusCode(true);
356 trans.metric().resetTransaction();
359 trans.setStatusCode(true);
360 if (!operations.isEmpty()) {
361 ControlLoopOperation operation = operations.get(operations.size() - 1);
362 trans.setTargetEntity(operation.getTarget());
363 trans.setTargetServiceName(operation.getActor());
365 trans.metric().resetTransaction();
367 case OPERATION_SUCCESS:
368 trans.setStatusCode(true);
369 operation(trans, operations);
370 trans.transaction().resetTransaction();
372 case OPERATION_FAILURE:
373 trans.setStatusCode(false);
374 operation(trans, operations);
375 trans.transaction().resetTransaction();
379 logger.warn("unexpected notification type {} in notification {}",
380 notification.getNotification().toString(), notification);
385 protected void operation(MDCTransaction trans, List<ControlLoopOperation> operations) {
386 if (!operations.isEmpty()) {
387 ControlLoopOperation operation = operations.get(operations.size() - 1);
389 if (operation.getTarget() != null) {
390 trans.setTargetEntity(operation.getTarget());
393 if (operation.getActor() != null) {
394 trans.setTargetServiceName(operation.getActor());
397 if (operation.getMessage() != null) {
398 trans.setResponseDescription(operation.getMessage());
401 trans.setInvocationId(operation.getSubRequestId());
403 if (operation.getOutcome() != null) {
404 trans.setResponseCode(operation.getOutcome());
407 if (operation.getStart() != null) {
408 trans.setStartTime(operation.getStart());
411 if (operation.getEnd() != null) {
412 trans.setEndTime(operation.getEnd());
417 protected void transaction(VirtualControlLoopNotification notification, ZonedDateTime startTime) {
418 MDCTransaction trans = MDCTransaction
419 .newTransaction(notification.getRequestId().toString(), notification.getFrom())
420 .setServiceName(notification.getClosedLoopControlName()).setTargetEntity(notification.getTarget())
421 .setStartTime(startTime.toInstant()).setEndTime(notification.getNotificationTime().toInstant())
422 .setResponseDescription(notification.getMessage());
424 switch (notification.getNotification()) {
426 trans.setStatusCode(true);
429 trans.setStatusCode(true);
432 trans.setStatusCode(false);
435 trans.setStatusCode(false);
439 logger.warn("unexpected notification type {} in notification {}",
440 notification.getNotification().toString(), notification);
444 trans.transaction().resetTransaction();
448 public String toString() {
449 final StringBuffer sb = new StringBuffer("CacheBasedControlLoopMetricsManager{");
450 sb.append("cacheSize=").append(cacheSize);
451 sb.append(", transactionTimeout=").append(transactionTimeout);
453 return sb.toString();