PerformanceMetrics.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2014 wcm.io
* %%
* 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.
* #L%
*/
package io.wcm.caravan.common.performance;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import rx.functions.Action0;
import rx.functions.Action1;
/**
* Performance metrics aid to collect time spent for execution of operation, including any sub operations, which results
* could be expected before the actual operation takes place. Each operation could be traced by key
* and level. Key should stay the same for all dependent measurements, when the level should vary depends on the step of
* measured sub operation.
*/
public final class PerformanceMetrics {
/**
* Provides unique identifier per metrics story
*/
private static final AtomicInteger KEY_GEN = new AtomicInteger(0);
private Integer key;
private Integer level;
private String action;
private Class actionClass;
private String descriptor;
private String correlationId;
private Long startTime;
private Long operationTime;
private Long endTime;
private Long totalTakenTimeByStep;
private Long takenTimeByStepStart;
private Long takenTimeByStepOperation;
private PerformanceMetrics previous;
private PerformanceMetrics(Integer key, Integer level, String action, Class actionClass, String descriptor, String correlationId) {
this.key = key;
this.level = level;
this.action = action;
this.actionClass = actionClass;
this.descriptor = descriptor;
this.correlationId = correlationId;
}
/**
* Creates new instance of performance metrics. Generates new metrics key and assigns zero level.
* @param action a short name of measured operation, typically a first prefix of descriptor
* @param descriptor a full description of measured operation
* @param correlationId a reference to the request, which caused the operation
* @return PerformanceMetrics a new instance of performance metrics
*/
public static PerformanceMetrics createNew(String action, String descriptor, String correlationId) {
return new PerformanceMetrics(KEY_GEN.getAndIncrement(), 0, action, null, descriptor, correlationId);
}
/**
* Creates new instance of performance metrics. Stores the key and correlation id of the parent metrics instance.
* Assigns next level.
* @param nextAction a short name of measured operation, typically a first prefix of descriptor
* @param nextDescriptor a full description of measured operation
* @return PerformanceMetrics a new instance of performance metrics with stored key and correlationId from the parent
* metrics and assigned next level
*/
public PerformanceMetrics createNext(String nextAction, String nextDescriptor) {
return createNext(nextAction, nextDescriptor, null);
}
/**
* Creates new instance of performance metrics. Stores the key and correlation id of the parent metrics instance.
* Assigns next level.
* @param nextAction a short name of measured operation, typically a first prefix of descriptor
* @param nextActionClass a class which implements the action
* @param nextDescriptor a full description of measured operation
* @return PerformanceMetrics a new instance of performance metrics with stored key and correlationId from the parent
* metrics and assigned next level
*/
public PerformanceMetrics createNext(String nextAction, String nextDescriptor, Class nextActionClass) {
PerformanceMetrics next = new PerformanceMetrics(key, level + 1, nextAction, nextActionClass, nextDescriptor, correlationId);
next.previous = this;
return next;
}
/**
* When called, start action sets time stamp to identify start time of operation.
* @return Action0
*/
public Action0 getStartAction() {
return new Action0() {
@Override
public void call() {
if (startTime == null) {
startTime = new Date().getTime();
}
}
};
}
/**
* When called, end action sets time stamp to identify end time of operation and logs the metrics.
* @return Action0
*/
public Action0 getEndAction() {
return new Action0() {
@Override
public void call() {
if (endTime == null) {
endTime = new Date().getTime();
PerformanceLogger.log(PerformanceMetrics.this);
}
}
};
}
/**
* When called, end action sets time stamp to identify end time of operation and logs the metrics.
* @return Action0
* @param <T> Any type
*/
public <T> Action1<T> getOnNextAction() {
return new Action1<T>() {
@Override
public void call(T objectt) {
if (operationTime == null) {
operationTime = new Date().getTime();
}
}
};
}
/**
* Set time stamp of operation start.
*/
public void setStartTimestamp() {
startTime = new Date().getTime();
}
/**
* Set time stamp of operation delegation.
*/
public void setOperationTimestamp() {
operationTime = new Date().getTime();
}
/**
* Set time stamp of operation end.
*/
public void setEndTimestamp() {
endTime = new Date().getTime();
}
/**
* @return true if start and end time of measured operation are set
*/
public boolean isCharged() {
return endTime != null && operationTime != null && startTime != null;
}
/**
* @return true if there is a sub operation, which start and end time are set
*/
public boolean isPreviousCharged() {
return previous != null && previous.isCharged();
}
public PerformanceMetrics getPrevious() {
return this.previous;
}
public Integer getKey() {
return this.key;
}
public Integer getLevel() {
return this.level;
}
public String getAction() {
return this.action;
}
public Class getActionClass() {
return this.actionClass;
}
public String getDescriptor() {
return this.descriptor;
}
public String getCorrelationId() {
return this.correlationId;
}
public Long getStartTime() {
return this.startTime;
}
public Long getOperationTime() {
return this.operationTime;
}
public Long getEndTime() {
return this.endTime;
}
/**
* @return time in milliseconds taken by actual operation, excludes time taken by any measured sub operation
*/
public Long getTakenTimeByStep() {
if (this.isCharged() && this.totalTakenTimeByStep == null) {
this.totalTakenTimeByStep = isPreviousCharged() ? getTakenTimeByStepStart() + getTakenTimeByStepOperation() : this.endTime
- this.startTime;
}
return this.totalTakenTimeByStep;
}
/**
* @return time in milliseconds spent by operation before sub operation was called
*/
public Long getTakenTimeByStepStart() {
if (this.takenTimeByStepStart == null && this.isCharged() && this.isPreviousCharged()) {
this.takenTimeByStepStart = this.previous.startTime - this.startTime;
}
return this.takenTimeByStepStart;
}
/**
* @return time in milliseconds spent by operation after sub operation was released
*/
public Long getTakenTimeByStepOperation() {
if (this.takenTimeByStepOperation == null && this.isCharged() && this.isPreviousCharged()) {
this.takenTimeByStepOperation = this.operationTime - this.previous.operationTime;
}
return this.takenTimeByStepOperation;
}
/**
* @return integer a count of metric entities from the first till the last one in the whole story
*/
public int size() {
return isPreviousCharged() ? previous.size() + 1 : 1;
}
@Override
public String toString() {
return "PerformanceMetrics [key=" + this.key + ", level=" + this.level + ", action=" + this.action + ", actionClass=" + this.actionClass + ", descriptor="
+ this.descriptor + ", correlationId=" + this.correlationId + ", startTime=" + this.startTime + ", operationTime=" + this.operationTime + ", endTime="
+ this.endTime + ", totalTakenTimeByStep=" + this.totalTakenTimeByStep + ", takenTimeByStepStart=" + this.takenTimeByStepStart
+ ", takenTimeByStepOperation=" + this.takenTimeByStepOperation + ", previous=" + this.previous + "]";
}
}