/*
* Copyright 2015-2016 the original author or authors.
*
* 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.
*/
package org.glowroot.common.model;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Doubles;
import com.google.common.primitives.Longs;
import org.immutables.value.Value;
public class TransactionSummaryCollector {
private static final Ordering<TransactionSummary> orderingByTotalTimeDesc =
new Ordering<TransactionSummary>() {
@Override
public int compare(TransactionSummary left, TransactionSummary right) {
return Doubles.compare(right.totalDurationNanos(), left.totalDurationNanos());
}
};
private static final Ordering<TransactionSummary> orderingByAverageTimeDesc =
new Ordering<TransactionSummary>() {
@Override
public int compare(TransactionSummary left, TransactionSummary right) {
return Doubles.compare(right.totalDurationNanos() / right.transactionCount(),
left.totalDurationNanos() / left.transactionCount());
}
};
private static final Ordering<TransactionSummary> orderingByTransactionCountDesc =
new Ordering<TransactionSummary>() {
@Override
public int compare(TransactionSummary left, TransactionSummary right) {
return Longs.compare(right.transactionCount(), left.transactionCount());
}
};
private final Map<String, MutableTransactionSummary> transactionSummaries = Maps.newHashMap();
private long lastCaptureTime;
public void collect(String transactionName, double totalDurationNanos, long transactionCount,
long captureTime) {
MutableTransactionSummary mts = transactionSummaries.get(transactionName);
if (mts == null) {
mts = new MutableTransactionSummary();
transactionSummaries.put(transactionName, mts);
}
mts.totalDurationNanos += totalDurationNanos;
mts.transactionCount += transactionCount;
lastCaptureTime = Math.max(lastCaptureTime, captureTime);
}
public long getLastCaptureTime() {
return lastCaptureTime;
}
public Result<TransactionSummary> getResult(SummarySortOrder sortOrder, int limit) {
List<TransactionSummary> summaries = Lists.newArrayList();
for (Map.Entry<String, MutableTransactionSummary> entry : transactionSummaries.entrySet()) {
summaries.add(ImmutableTransactionSummary.builder()
.transactionName(entry.getKey())
.totalDurationNanos(entry.getValue().totalDurationNanos)
.transactionCount(entry.getValue().transactionCount)
.build());
}
summaries = sortTransactionSummaries(summaries, sortOrder);
if (summaries.size() > limit) {
return new Result<TransactionSummary>(summaries.subList(0, limit), true);
} else {
return new Result<TransactionSummary>(summaries, false);
}
}
private static List<TransactionSummary> sortTransactionSummaries(
Iterable<TransactionSummary> transactionSummaries, SummarySortOrder sortOrder) {
switch (sortOrder) {
case TOTAL_TIME:
return orderingByTotalTimeDesc.immutableSortedCopy(transactionSummaries);
case AVERAGE_TIME:
return orderingByAverageTimeDesc.immutableSortedCopy(transactionSummaries);
case THROUGHPUT:
return orderingByTransactionCountDesc.immutableSortedCopy(transactionSummaries);
default:
throw new AssertionError("Unexpected sort order: " + sortOrder);
}
}
public enum SummarySortOrder {
TOTAL_TIME, AVERAGE_TIME, THROUGHPUT
}
@Value.Immutable
public interface TransactionSummary {
String transactionName();
// aggregates use double instead of long to avoid (unlikely) 292 year nanosecond rollover
double totalDurationNanos();
long transactionCount();
}
private static class MutableTransactionSummary {
private double totalDurationNanos;
private long transactionCount;
}
}