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;
28 import java.time.Instant;
29 import java.time.ZonedDateTime;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Properties;
33 import java.util.UUID;
34 import java.util.concurrent.TimeUnit;
35 import org.onap.policy.controlloop.ControlLoopOperation;
36 import org.onap.policy.controlloop.VirtualControlLoopNotification;
37 import org.onap.policy.drools.persistence.SystemPersistence;
38 import org.onap.policy.drools.system.PolicyController;
39 import org.onap.policy.drools.utils.logging.MDCTransaction;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * Control Loop Metrics Tracker
46 public interface ControlLoopMetrics {
49 * gets all transaction identifiers being monitored
51 * @return transaction id list
53 List<UUID> getTransactionIds();
56 * gets all detailed transactions
58 * @return list of transactions
60 List<VirtualControlLoopNotification> getTransactions();
63 * track controller's notification events
65 * @param controller policy controller sending out notification
66 * @param notification notification
68 void transactionEvent(PolicyController controller, VirtualControlLoopNotification notification);
71 * gets an in-progress transaction
73 * @param requestId request ID
74 * @return in progress notification
76 VirtualControlLoopNotification getTransaction(UUID requestId);
79 * removes an in-progress transaction
81 * @param requestId request ID
83 void removeTransaction(UUID requestId);
97 long getCacheOccupancy();
102 * @param cacheSize cache size
104 void setMaxCacheSize(long cacheSize);
107 * cached transaction expiration timeout in seconds
109 * @return transaction timeout in seconds
111 long getTransactionTimeout();
114 * sets transaction timeout in seconds
116 * @param transactionTimeout transaction timeout in seconds
118 void setTransactionTimeout(long transactionTimeout);
123 * @param cacheSize new cache size
124 * @param transactionTimeout new transaction timeout in seconds
126 void resetCache(long cacheSize, long transactionTimeout);
129 * refresh underlying transaction management
134 * singleton manager object
136 ControlLoopMetrics manager = new CacheBasedControlLoopMetricsManager();
140 * Control Loop Metrics Tracker Implementation
142 class CacheBasedControlLoopMetricsManager implements ControlLoopMetrics {
144 private static final Logger logger = LoggerFactory.getLogger(CacheBasedControlLoopMetricsManager.class);
146 private LoadingCache<UUID, VirtualControlLoopNotification> cache;
147 private long cacheSize = ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_DEFAULT;
149 private long transactionTimeout = ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_DEFAULT;
151 public CacheBasedControlLoopMetricsManager() {
153 Properties properties =
154 SystemPersistence.manager.getProperties(ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME);
160 Long.parseLong(properties.getProperty(ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_PROPERTY,
161 "" + ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_DEFAULT));
162 } catch (Exception e) {
163 logger.warn("{}:{} property cannot be accessed", ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME,
164 ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_PROPERTY, e);
167 /* transaction timeout */
170 this.transactionTimeout =
171 Long.parseLong(properties.getProperty(ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_PROPERTY,
172 "" + ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_DEFAULT));
173 } catch (Exception e) {
174 logger.warn("{}:{} property cannot be accessed", ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME,
175 ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_PROPERTY, e);
178 resetCache(this.cacheSize, this.transactionTimeout);
182 public void resetCache(long cacheSize, long transactionTimeout) {
183 this.cacheSize = cacheSize;
184 this.transactionTimeout = transactionTimeout;
186 CacheLoader<UUID, VirtualControlLoopNotification> loader = new CacheLoader<UUID, VirtualControlLoopNotification>() {
189 public VirtualControlLoopNotification load(UUID key) throws Exception {
194 RemovalListener<UUID, VirtualControlLoopNotification> listener = new RemovalListener<UUID, VirtualControlLoopNotification>() {
196 public void onRemoval(RemovalNotification<UUID, VirtualControlLoopNotification> notification) {
197 if (notification.wasEvicted()) {
198 evicted(notification.getValue());
200 logger.info("REMOVAL: {} because of {}", notification.getValue().getRequestID(), notification.getCause().name());
205 synchronized (this) {
206 if (this.cache != null) {
207 this.cache.cleanUp();
208 this.cache.invalidateAll();
211 this.cache = CacheBuilder.newBuilder().
212 maximumSize(this.cacheSize).expireAfterWrite(transactionTimeout, TimeUnit.SECONDS).
213 removalListener(listener).build(loader);
218 public void refresh() {
219 this.cache.cleanUp();
223 public List<UUID> getTransactionIds() {
224 return new ArrayList<>(this.cache.asMap().keySet());
228 public List<VirtualControlLoopNotification> getTransactions() {
229 return new ArrayList<>(this.cache.asMap().values());
233 public void transactionEvent(PolicyController controller, VirtualControlLoopNotification notification) {
234 if (notification == null || notification.getRequestID() == null || notification.getNotification() == null) {
235 logger.warn("Invalid notification: {}", notification);
239 if (notification.getNotificationTime() == null) {
240 notification.setNotificationTime(ZonedDateTime.now());
243 notification.setFrom(notification.getFrom() + ":" + controller.getName());
245 switch (notification.getNotification()) {
250 endTransaction(notification);
254 case OPERATION_SUCCESS:
255 case OPERATION_FAILURE:
256 /* any other value is an in progress transaction */
257 inProgressTransaction(notification);
261 logger.warn("unexpected notification type {} in notification {}",
262 notification.getNotification().toString(), notification);
268 public VirtualControlLoopNotification getTransaction(UUID requestId) {
269 return cache.getIfPresent(requestId);
273 public void removeTransaction(UUID requestId) {
274 cache.invalidate(requestId);
278 * tracks an in progress control loop transaction
280 * @param notification control loop notification
282 protected void inProgressTransaction(VirtualControlLoopNotification notification) {
283 if (cache.getIfPresent(notification.getRequestID()) == null) {
284 cache.put(notification.getRequestID(), notification);
287 this.metric(notification);
291 * end of a control loop transaction
293 * @param notification control loop notification
295 protected void endTransaction(VirtualControlLoopNotification notification) {
296 ZonedDateTime startTime;
297 VirtualControlLoopNotification startNotification = cache.getIfPresent(notification.getRequestID());
298 if (startNotification != null) {
299 startTime = startNotification.getNotificationTime();
301 startTime = notification.getNotificationTime();
304 this.transaction(notification, startTime);
305 cache.invalidate(startNotification);
308 protected void evicted(VirtualControlLoopNotification notification) {
309 // transaction(notification, ZonedDateTime.now());
310 MDCTransaction trans =
311 MDCTransaction.newTransaction(notification.getRequestID().toString(), notification.getFrom()).
312 setServiceName(notification.getClosedLoopControlName()).
313 setTargetEntity(notification.getTarget()).
314 setStartTime(notification.getNotificationTime().toInstant()).
315 setEndTime(Instant.now()).
316 setResponseDescription("EVICTED").
317 setStatusCode(false).metric().resetTransaction();
321 public long getCacheSize() {
322 return this.cacheSize;
326 public void setMaxCacheSize(long cacheSize) {
327 this.cacheSize = cacheSize;
331 public long getTransactionTimeout() {
332 return this.transactionTimeout;
336 public void setTransactionTimeout(long transactionTimeout) {
337 this.transactionTimeout = transactionTimeout;
341 public long getCacheOccupancy() {
342 return this.cache.size();
345 protected void metric(VirtualControlLoopNotification notification) {
346 MDCTransaction trans =
347 MDCTransaction.newTransaction(notification.getRequestID().toString(), notification.getFrom()).
348 setServiceName(notification.getClosedLoopControlName()).
349 setTargetEntity(notification.getTarget());
351 List<ControlLoopOperation> operations = notification.getHistory();
352 switch (notification.getNotification()) {
354 trans.setStatusCode(true);
355 trans.metric().resetTransaction();
358 trans.setStatusCode(true);
359 if (!operations.isEmpty()) {
360 ControlLoopOperation operation = operations.get(operations.size()-1);
361 trans.setTargetEntity(operation.getTarget());
362 trans.setTargetServiceName(operation.getActor());
364 trans.metric().resetTransaction();
366 case OPERATION_SUCCESS:
367 trans.setStatusCode(true);
368 operation(trans, operations);
369 trans.transaction().resetTransaction();
371 case OPERATION_FAILURE:
372 trans.setStatusCode(false);
373 operation(trans, operations);
374 trans.transaction().resetTransaction();
378 logger.warn("unexpected notification type {} in notification {}",
379 notification.getNotification().toString(), notification);
384 protected void operation(MDCTransaction trans, List<ControlLoopOperation> operations) {
385 if (!operations.isEmpty()) {
386 ControlLoopOperation operation = operations.get(operations.size()-1);
388 if (operation.getTarget() != null)
389 trans.setTargetEntity(operation.getTarget());
391 if (operation.getActor() != null)
392 trans.setTargetServiceName(operation.getActor());
394 if (operation.getMessage() != null)
395 trans.setResponseDescription(operation.getMessage());
397 trans.setInvocationId(operation.getSubRequestId());
399 if (operation.getOutcome() != null)
400 trans.setResponseCode(operation.getOutcome());
402 if (operation.getStart() != null)
403 trans.setStartTime(operation.getStart());
405 if (operation.getEnd() != null)
406 trans.setEndTime(operation.getEnd());
410 protected void transaction(VirtualControlLoopNotification notification, ZonedDateTime startTime) {
411 MDCTransaction trans =
412 MDCTransaction.newTransaction(notification.getRequestID().toString(), notification.getFrom()).
413 setServiceName(notification.getClosedLoopControlName()).
414 setTargetEntity(notification.getTarget()).
415 setStartTime(startTime.toInstant()).
416 setEndTime(notification.getNotificationTime().toInstant()).
417 setResponseDescription(notification.getMessage());
419 switch (notification.getNotification()) {
421 trans.setStatusCode(true);
424 trans.setStatusCode(true);
427 trans.setStatusCode(false);
430 trans.setStatusCode(false);
434 logger.warn("unexpected notification type {} in notification {}",
435 notification.getNotification().toString(), notification);
439 trans.transaction().resetTransaction();
443 public String toString() {
444 final StringBuffer sb = new StringBuffer("CacheBasedControlLoopMetricsManager{");
445 sb.append("cacheSize=").append(cacheSize);
446 sb.append(", transactionTimeout=").append(transactionTimeout);
448 return sb.toString();