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.ZonedDateTime;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Properties;
32 import java.util.UUID;
33 import java.util.concurrent.TimeUnit;
34 import org.onap.policy.controlloop.VirtualControlLoopNotification;
35 import org.onap.policy.drools.persistence.SystemPersistence;
36 import org.onap.policy.drools.system.PolicyController;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * Control Loop Metrics Tracker
43 public interface ControlLoopMetrics {
46 * gets all transaction identifiers being monitored
48 * @return transaction id list
50 List<UUID> getTransactionIds();
53 * gets all detailed transactions
55 * @return list of transactions
57 List<VirtualControlLoopNotification> getTransactions();
60 * track controller's notification events
62 * @param controller policy controller sending out notification
63 * @param notification notification
65 void transactionEvent(PolicyController controller, VirtualControlLoopNotification notification);
68 * gets an in-progress transaction
70 * @param requestId request ID
71 * @return in progress notification
73 VirtualControlLoopNotification getTransaction(UUID requestId);
76 * removes an in-progress transaction
78 * @param requestId request ID
79 * @return in progress notification
81 void removeTransaction(UUID requestId);
95 long getCacheOccupancy();
100 * @param cacheSize cache size
102 void setMaxCacheSize(long cacheSize);
105 * cached transaction expiration timeout in seconds
107 * @return transaction timeout in seconds
109 long getTransactionTimeout();
112 * sets transaction timeout in seconds
114 * @param transactionTimeout transaction timeout in seconds
116 void setTransactionTimeout(long transactionTimeout);
121 * @param cacheSize new cache size
122 * @param transactionTimeout new transaction timeout in seconds
124 void resetCache(long cacheSize, long transactionTimeout);
127 * refresh underlying transaction management
132 * singleton manager object
134 ControlLoopMetrics manager = new CacheBasedControlLoopMetricsManager();
138 * Control Loop Metrics Tracker Implementation
140 class CacheBasedControlLoopMetricsManager implements ControlLoopMetrics {
142 private static final Logger logger = LoggerFactory.getLogger(CacheBasedControlLoopMetricsManager.class);
144 private LoadingCache<UUID, VirtualControlLoopNotification> cache;
145 private long cacheSize = ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_DEFAULT;
147 private long transactionTimeout = ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_DEFAULT;
149 public CacheBasedControlLoopMetricsManager() {
151 Properties properties =
152 SystemPersistence.manager.getProperties(ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME);
158 Long.parseLong(properties.getProperty(ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_PROPERTY,
159 "" + ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_DEFAULT));
160 } catch (Exception e) {
161 logger.warn("{}:{} property cannot be accessed", ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME,
162 ControlLoopMetricsFeature.CL_CACHE_TRANS_SIZE_PROPERTY, e);
165 /* transaction timeout */
168 this.transactionTimeout =
169 Long.parseLong(properties.getProperty(ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_PROPERTY,
170 "" + ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_DEFAULT));
171 } catch (Exception e) {
172 logger.warn("{}:{} property cannot be accessed", ControlLoopMetricsFeature.CONFIGURATION_PROPERTIES_NAME,
173 ControlLoopMetricsFeature.CL_CACHE_TRANS_TIMEOUT_SECONDS_PROPERTY, e);
176 resetCache(this.cacheSize, this.transactionTimeout);
180 public void resetCache(long cacheSize, long transactionTimeout) {
181 this.cacheSize = cacheSize;
182 this.transactionTimeout = transactionTimeout;
184 CacheLoader<UUID, VirtualControlLoopNotification> loader = new CacheLoader<UUID, VirtualControlLoopNotification>() {
187 public VirtualControlLoopNotification load(UUID key) throws Exception {
192 RemovalListener<UUID, VirtualControlLoopNotification> listener = new RemovalListener<UUID, VirtualControlLoopNotification>() {
194 public void onRemoval(RemovalNotification<UUID, VirtualControlLoopNotification> notification) {
195 if (notification.wasEvicted()) {
196 evicted(notification.getValue());
198 logger.info("REMOVAL: {}->{} from {} because of {}", notification.getValue().getFrom(),
199 notification.getValue(), notification.getCause().name());
204 synchronized (this) {
205 if (this.cache != null) {
206 this.cache.cleanUp();
207 this.cache.invalidateAll();
210 this.cache = CacheBuilder.newBuilder().
211 maximumSize(this.cacheSize).expireAfterWrite(transactionTimeout, TimeUnit.SECONDS).
212 removalListener(listener).build(loader);
217 public void refresh() {
218 this.cache.cleanUp();
222 public List<UUID> getTransactionIds() {
223 return new ArrayList<>(this.cache.asMap().keySet());
227 public List<VirtualControlLoopNotification> getTransactions() {
228 return new ArrayList<>(this.cache.asMap().values());
232 public void transactionEvent(PolicyController controller, VirtualControlLoopNotification notification) {
233 if (notification == null || notification.getRequestID() == null || notification.getNotification() == null) {
234 logger.warn("Invalid notification: {}", notification);
238 if (notification.getNotificationTime() == null) {
239 notification.setNotificationTime(ZonedDateTime.now());
242 notification.setFrom(notification.getFrom() + ":" + controller.getName());
244 this.metric(notification);
246 switch (notification.getNotification()) {
251 endTransaction(notification);
254 /* any other value is an in progress transaction */
255 inProgressTransaction(notification);
261 public VirtualControlLoopNotification getTransaction(UUID requestId) {
262 return cache.getIfPresent(requestId);
266 public void removeTransaction(UUID requestId) {
267 cache.invalidate(requestId);
271 * tracks an in progress control loop transaction
273 * @param notification control loop notification
275 protected void inProgressTransaction(VirtualControlLoopNotification notification) {
276 if (cache.getIfPresent(notification.getRequestID()) == null) {
277 cache.put(notification.getRequestID(), notification);
282 * end of a control loop transaction
284 * @param notification control loop notification
286 protected void endTransaction(VirtualControlLoopNotification notification) {
287 ZonedDateTime startTime;
288 VirtualControlLoopNotification startNotification = cache.getIfPresent(notification.getRequestID());
289 if (startNotification != null) {
290 startTime = startNotification.getNotificationTime();
292 startTime = notification.getNotificationTime();
295 this.transaction(notification, startTime);
297 cache.invalidate(startNotification);
300 protected void evicted(VirtualControlLoopNotification notification) {
301 transaction(notification, ZonedDateTime.now());
305 public long getCacheSize() {
306 return this.cacheSize;
310 public void setMaxCacheSize(long cacheSize) {
311 this.cacheSize = cacheSize;
315 public long getTransactionTimeout() {
316 return this.transactionTimeout;
320 public void setTransactionTimeout(long transactionTimeout) {
321 this.transactionTimeout = transactionTimeout;
325 public long getCacheOccupancy() {
326 return this.cache.size();
329 protected void metric(VirtualControlLoopNotification notification) {
332 // logger.info(LoggerUtil.METRIC_LOG_MARKER, "METRIC:{}", notification);
335 protected void transaction(VirtualControlLoopNotification notification, ZonedDateTime startTime) {
338 // Duration.between(notification.getNotificationTime(), ZonedDateTime.now()).toMillis())
339 // logger.info(LoggerUtil.TRANSACTION_LOG_MARKER, "TRANSACTION:{}->{} {} ms.", notification.getRequestID(), notification,
344 public String toString() {
345 final StringBuffer sb = new StringBuffer("CacheBasedControlLoopMetricsManager{");
346 sb.append("cacheSize=").append(cacheSize);
347 sb.append(", transactionTimeout=").append(transactionTimeout);
349 return sb.toString();