diff options
Diffstat (limited to 'model/src/main/java/org/onap/policy/apex/model/enginemodel/concepts/AxEngineStats.java')
-rw-r--r-- | model/src/main/java/org/onap/policy/apex/model/enginemodel/concepts/AxEngineStats.java | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/model/src/main/java/org/onap/policy/apex/model/enginemodel/concepts/AxEngineStats.java b/model/src/main/java/org/onap/policy/apex/model/enginemodel/concepts/AxEngineStats.java new file mode 100644 index 000000000..1420d1e0d --- /dev/null +++ b/model/src/main/java/org/onap/policy/apex/model/enginemodel/concepts/AxEngineStats.java @@ -0,0 +1,533 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2016-2018 Ericsson. All rights reserved. + * Modifications Copyright (C) 2019-2020,2022 Nordix Foundation. + * Modifications Copyright (C) 2022 Bell Canada. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.apex.model.enginemodel.concepts; + +import io.prometheus.client.Gauge; +import io.prometheus.client.Histogram; +import java.text.SimpleDateFormat; +import java.util.List; +import lombok.Getter; +import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey; +import org.onap.policy.apex.model.basicmodel.concepts.AxConcept; +import org.onap.policy.apex.model.basicmodel.concepts.AxKey; +import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey; +import org.onap.policy.apex.model.basicmodel.concepts.AxValidationMessage; +import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult; +import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult; +import org.onap.policy.common.utils.resources.PrometheusUtils; +import org.onap.policy.common.utils.validation.Assertions; + +/** + * This class is a java bean that is used to record statistics on Apex engines as they execute. Statistics on the number + * of events, the amount of time taken to execute the last policy, the average policy execution time, the up time of the + * engine, and the time stamp of the last engine start are recorded. + */ + +public class AxEngineStats extends AxConcept { + private static final long serialVersionUID = -6981129081962785368L; + private static final int HASH_CODE_PRIME = 32; + static final String ENGINE_INSTANCE_ID = "engine_instance_id"; + static final Gauge ENGINE_EVENT_EXECUTIONS = Gauge.build().name("engine_event_executions") + .namespace(PrometheusUtils.PdpType.PDPA.getNamespace()).labelNames(ENGINE_INSTANCE_ID) + .help("Total number of APEX events processed by the engine.").register(); + static final Gauge ENGINE_UPTIME = Gauge.build().name("engine_uptime") + .namespace(PrometheusUtils.PdpType.PDPA.getNamespace()).labelNames(ENGINE_INSTANCE_ID) + .help("Time elapsed since the engine was started.").register(); + static final Gauge ENGINE_START_TIMESTAMP = Gauge.build().name("engine_last_start_timestamp_epoch") + .namespace(PrometheusUtils.PdpType.PDPA.getNamespace()).labelNames(ENGINE_INSTANCE_ID) + .help("Epoch timestamp of the instance when engine was last started.").register(); + static final Gauge ENGINE_AVG_EXECUTION_TIME = Gauge.build().name("engine_average_execution_time_seconds") + .namespace(PrometheusUtils.PdpType.PDPA.getNamespace()).labelNames(ENGINE_INSTANCE_ID) + .help("Average time taken to execute an APEX policy in seconds.").register(); + static final Histogram ENGINE_LAST_EXECUTION_TIME = Histogram.build() + .namespace(PrometheusUtils.PdpType.PDPA.getNamespace()) + .name("engine_last_execution_time").labelNames(ENGINE_INSTANCE_ID) + .help("Time taken to execute the last APEX policy in seconds.").register(); + + private AxReferenceKey key; + private long timeStamp; + private long eventCount; + private long lastExecutionTime; + private double averageExecutionTime; + private long upTime; + + @Getter + private transient long lastEnterTime; + private long lastStart; + + /** + * The Default Constructor creates an engine statistics instance with a null key and with all values cleared. + */ + public AxEngineStats() { + this(new AxReferenceKey()); + timeStamp = 0; + eventCount = 0; + lastExecutionTime = 0; + averageExecutionTime = 0; + upTime = 0; + lastEnterTime = 0; + lastStart = 0; + initEngineMetricsWithPrometheus(); + } + + /** + * Register the APEX engine metrics with Prometheus. + */ + private void initEngineMetricsWithPrometheus() { + var engineId = getKey().getParentArtifactKey().getId(); + if (engineId.startsWith(AxKey.NULL_KEY_NAME)) { + return; + } + ENGINE_UPTIME.labels(engineId).set(upTime / 1000d); + ENGINE_EVENT_EXECUTIONS.labels(engineId).set(this.eventCount); + ENGINE_START_TIMESTAMP.labels(engineId).set(this.lastStart); + ENGINE_AVG_EXECUTION_TIME.labels(engineId).set(this.averageExecutionTime / 1000d); + ENGINE_LAST_EXECUTION_TIME.labels(engineId).observe(this.lastExecutionTime / 1000d); + } + + /** + * Copy constructor. + * + * @param copyConcept the concept to copy from + */ + public AxEngineStats(final AxEngineStats copyConcept) { + super(copyConcept); + } + + /** + * The Keyed Constructor creates an engine statistics instance with the given key and all values cleared. + * + * @param key the key + */ + public AxEngineStats(final AxReferenceKey key) { + this(key, 0, 0, 0, 0, 0, 0); + } + + /** + * This Constructor creates an engine statistics instance with all its fields set. + * + * @param key the engine statistics key + * @param timeStamp the time stamp at which the statistics were recorded + * @param eventCount the number of events processed by the engine + * @param lastExecutionTime the amount of time taken to execute the last policy + * @param averageExecutionTime the average amount of time taken to execute a policy + * @param upTime the time that has elapsed since the policy engine was started + * @param lastStart the time at which the policy engine was last started + */ + public AxEngineStats(final AxReferenceKey key, final long timeStamp, final long eventCount, + final long lastExecutionTime, final double averageExecutionTime, final long upTime, final long lastStart) { + super(); + Assertions.argumentNotNull(key, "key may not be null"); + + this.key = key; + this.timeStamp = timeStamp; + this.eventCount = eventCount; + this.lastExecutionTime = lastExecutionTime; + this.averageExecutionTime = averageExecutionTime; + this.upTime = upTime; + this.lastStart = lastStart; + initEngineMetricsWithPrometheus(); + } + + /** + * {@inheritDoc}. + */ + @Override + public AxReferenceKey getKey() { + return key; + } + + /** + * {@inheritDoc}. + */ + @Override + public List<AxKey> getKeys() { + return key.getKeys(); + } + + /** + * Sets the engine statistics key. + * + * @param key the engine statistics key + */ + public void setKey(final AxReferenceKey key) { + Assertions.argumentNotNull(key, "key may not be null"); + this.key = key; + } + + /** + * Gets the time stamp at which the statistics were recorded. + * + * @return the time stamp at which the statistics were recorded + */ + public long getTimeStamp() { + return timeStamp; + } + + /** + * Gets the time stamp at which the statistics were recorded as a string. + * + * @return the time stamp at which the statistics were recorded as a string + */ + public String getTimeStampString() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(timeStamp); + } + + /** + * Sets the time stamp at which the statistics were recorded. + * + * @param timeStamp the time stamp at which the statistics were recorded + */ + public void setTimeStamp(final long timeStamp) { + this.timeStamp = timeStamp; + } + + /** + * Gets the number of events processed by the engine. + * + * @return the number of events processed by the engine + */ + public long getEventCount() { + return eventCount; + } + + /** + * Sets the number of events processed by the engine. + * + * @param eventCount the number of events processed by the engine + */ + public void setEventCount(final long eventCount) { + this.eventCount = eventCount; + ENGINE_EVENT_EXECUTIONS.labels(getKey().getParentArtifactKey().getId()) + .set(this.eventCount); + } + + /** + * Gets the amount of time taken to execute the last policy. + * + * @return the amount of time taken to execute the last policy + */ + public long getLastExecutionTime() { + return lastExecutionTime; + } + + /** + * Sets the amount of time taken to execute the last policy. + * + * @param lastExecutionTime the amount of time taken to execute the last policy + */ + public void setLastExecutionTime(final long lastExecutionTime) { + this.lastExecutionTime = lastExecutionTime; + ENGINE_LAST_EXECUTION_TIME.labels(getKey().getParentArtifactKey().getId()) + .observe(this.lastExecutionTime / 1000d); + } + + /** + * Gets the average amount of time taken to execute a policy. + * + * @return the average amount of time taken to execute a policy + */ + public double getAverageExecutionTime() { + return averageExecutionTime; + } + + /** + * Sets the average amount of time taken to execute a policy. + * + * @param averageExecutionTime the average amount of time taken to execute a policy + */ + public void setAverageExecutionTime(final double averageExecutionTime) { + this.averageExecutionTime = averageExecutionTime; + ENGINE_AVG_EXECUTION_TIME.labels(getKey().getParentArtifactKey().getId()) + .set(this.averageExecutionTime / 1000d); + } + + /** + * Gets the time that has elapsed since the policy engine was started. + * + * @return the time that has elapsed since the policy engine was started + */ + public long getUpTime() { + if (this.getLastStart() != 0) { + return upTime + (timeStamp - this.getLastStart()); + } + return upTime; + } + + /** + * Sets the time that has elapsed since the policy engine was started. + * + * @param upTime the time that has elapsed since the policy engine was started + */ + public void setUpTime(final long upTime) { + this.upTime = upTime; + ENGINE_UPTIME.labels(getKey().getParentArtifactKey().getId()).set(this.upTime / 1000d); + } + + /** + * Sets the time at which the policy engine was last started. + * + * @param lastStart the time at which the policy engine was last started + */ + private void setLastStart(final long lastStart) { + this.lastStart = lastStart; + ENGINE_START_TIMESTAMP.labels(getKey().getParentArtifactKey().getId()).set(this.lastStart); + } + + /** + * Gets the time at which the policy engine was last started. + * + * @return the time at which the policy engine was last started + */ + public long getLastStart() { + return lastStart; + } + + /** + * Resets all the statistic values to zero. + */ + public synchronized void reset() { + timeStamp = 0; + eventCount = 0; + lastExecutionTime = 0; + averageExecutionTime = 0; + upTime = 0; + lastEnterTime = 0; + lastStart = 0; + initEngineMetricsWithPrometheus(); + } + + /** + * Updates the statistics when called, used by the Apex engine when it starts executing a policy. + * + * @param eventkey the key of the event that is being executed + */ + public synchronized void executionEnter(final AxArtifactKey eventkey) { + final long now = System.currentTimeMillis(); + eventCount++; + if (eventCount < 0) { + eventCount = 2; + } + lastEnterTime = now; + timeStamp = now; + ENGINE_EVENT_EXECUTIONS.labels(getKey().getParentArtifactKey().getId()).set(this.eventCount); + } + + /** + * Updates the statistics when called, used by the Apex engine when it completes executing a policy. + */ + public synchronized void executionExit() { + final long now = System.currentTimeMillis(); + lastExecutionTime = now - lastEnterTime; + ENGINE_LAST_EXECUTION_TIME.labels(getKey().getParentArtifactKey().getId()) + .observe(this.lastExecutionTime / 1000d); + + averageExecutionTime = ((averageExecutionTime * (eventCount - 1.0)) + lastExecutionTime) / eventCount; + lastEnterTime = 0; + timeStamp = System.currentTimeMillis(); + ENGINE_AVG_EXECUTION_TIME.labels(getKey().getParentArtifactKey().getId()) + .set(this.averageExecutionTime / 1000d); + } + + /** + * Updates the statistics when called, used by the Apex engine when it is started. + */ + public synchronized void engineStart() { + final long now = System.currentTimeMillis(); + timeStamp = now; + this.setLastStart(now); + } + + /** + * Updates the statistics when called, used by the Apex engine when it is stopped. + */ + public synchronized void engineStop() { + final long now = System.currentTimeMillis(); + timeStamp = now; + upTime += (timeStamp - this.getLastStart()); + this.setLastStart(0); + ENGINE_UPTIME.labels(getKey().getParentArtifactKey().getId()).set(this.upTime / 1000d); + } + + /** + * {@inheritDoc}. + */ + @Override + public AxValidationResult validate(final AxValidationResult result) { + if (key.equals(AxReferenceKey.getNullKey())) { + result.addValidationMessage( + new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key")); + } + + return key.validate(result); + } + + /** + * {@inheritDoc}. + */ + @Override + public void clean() { + key.clean(); + } + + /** + * {@inheritDoc}. + */ + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + builder.append(":("); + builder.append("engineKey="); + builder.append(key); + builder.append(",timeStamp="); + builder.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(timeStamp)); + builder.append(",eventCount="); + builder.append(eventCount); + builder.append(",lastExecutionTime="); + builder.append(lastExecutionTime); + builder.append(",averageExecutionTime="); + builder.append(averageExecutionTime); + builder.append(",upTime="); + builder.append(getUpTime()); + builder.append(")"); + return builder.toString(); + } + + /** + * {@inheritDoc}. + */ + @Override + public AxConcept copyTo(final AxConcept targetObject) { + Assertions.argumentNotNull(targetObject, "target may not be null"); + + final Object copyObject = targetObject; + Assertions.instanceOf(copyObject, AxEngineStats.class); + + final AxEngineStats copy = ((AxEngineStats) copyObject); + copy.setKey(new AxReferenceKey(key)); + copy.setTimeStamp(timeStamp); + copy.setEventCount(eventCount); + copy.setLastExecutionTime(lastExecutionTime); + copy.setAverageExecutionTime(averageExecutionTime); + copy.setUpTime(upTime); + copy.setLastStart(lastStart); + initEngineMetricsWithPrometheus(); + + return copy; + } + + /** + * {@inheritDoc}. + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + key.hashCode(); + result = prime * result + (int) (timeStamp ^ (timeStamp >>> HASH_CODE_PRIME)); + result = prime * result + (int) (eventCount ^ (eventCount >>> HASH_CODE_PRIME)); + result = prime * result + (int) (lastExecutionTime ^ (lastExecutionTime >>> HASH_CODE_PRIME)); + result = prime * result + ((int) averageExecutionTime ^ ((int) averageExecutionTime >>> HASH_CODE_PRIME)); + result = prime * result + (int) (upTime ^ (upTime >>> HASH_CODE_PRIME)); + result = prime * result + (int) (getLastStart() ^ (getLastStart() >>> HASH_CODE_PRIME)); + return result; + } + + /** + * {@inheritDoc}. + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + + if (getClass() != obj.getClass()) { + return false; + } + + final AxEngineStats other = (AxEngineStats) obj; + if (!key.equals(other.key)) { + return false; + } + if (timeStamp != other.timeStamp) { + return false; + } + if (eventCount != other.eventCount) { + return false; + } + if (lastExecutionTime != other.lastExecutionTime) { + return false; + } + if (Double.compare(averageExecutionTime, other.averageExecutionTime) != 0) { + return false; + } + if (upTime != other.upTime) { + return false; + } + return getLastStart() == other.getLastStart(); + } + + /** + * {@inheritDoc}. + */ + @Override + public int compareTo(final AxConcept otherObj) { + if (otherObj == null) { + return -1; + } + if (this == otherObj) { + return 0; + } + if (getClass() != otherObj.getClass()) { + return this.hashCode() - otherObj.hashCode(); + } + + final AxEngineStats other = (AxEngineStats) otherObj; + if (!key.equals(other.key)) { + return key.compareTo(other.key); + } + if (timeStamp != other.timeStamp) { + return (int) (timeStamp - other.timeStamp); + } + if (eventCount != other.eventCount) { + return (int) (eventCount - other.eventCount); + } + if (lastExecutionTime != other.lastExecutionTime) { + return (int) (lastExecutionTime - other.lastExecutionTime); + } + final int result = Double.compare(averageExecutionTime, other.averageExecutionTime); + if (result != 0) { + return result; + } + if (upTime != other.upTime) { + return (int) (upTime - other.upTime); + } + + return Long.compare(lastStart, other.lastStart); + } +} |