/* * 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.annotations.VisibleForTesting; 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 TransactionErrorSummaryCollector { @VisibleForTesting static final Ordering<TransactionErrorSummary> orderingByErrorCountDesc = new Ordering<TransactionErrorSummary>() { @Override public int compare(TransactionErrorSummary left, TransactionErrorSummary right) { return Longs.compare(right.errorCount(), left.errorCount()); } }; @VisibleForTesting static final Ordering<TransactionErrorSummary> orderingByErrorRateDesc = new Ordering<TransactionErrorSummary>() { @Override public int compare(TransactionErrorSummary left, TransactionErrorSummary right) { return Doubles.compare(right.errorCount() / (double) right.transactionCount(), left.errorCount() / (double) left.transactionCount()); } }; private final Map<String, MutableTransactionErrorSummary> transactionErrorSummaries = Maps.newHashMap(); private long lastCaptureTime; public void collect(String transactionName, long errorCount, long transactionCount, long captureTime) { MutableTransactionErrorSummary mtes = transactionErrorSummaries.get(transactionName); if (mtes == null) { mtes = new MutableTransactionErrorSummary(); transactionErrorSummaries.put(transactionName, mtes); } mtes.errorCount += errorCount; mtes.transactionCount += transactionCount; lastCaptureTime = Math.max(lastCaptureTime, captureTime); } public long getLastCaptureTime() { return lastCaptureTime; } public Result<TransactionErrorSummary> getResult(ErrorSummarySortOrder sortOrder, int limit) { List<TransactionErrorSummary> summaries = Lists.newArrayList(); for (Map.Entry<String, MutableTransactionErrorSummary> entry : transactionErrorSummaries .entrySet()) { summaries.add(ImmutableTransactionErrorSummary.builder() .transactionName(entry.getKey()) .errorCount(entry.getValue().errorCount) .transactionCount(entry.getValue().transactionCount) .build()); } summaries = sortTransactionErrorSummaries(summaries, sortOrder); if (summaries.size() > limit) { return new Result<TransactionErrorSummary>(summaries.subList(0, limit), true); } else { return new Result<TransactionErrorSummary>(summaries, false); } } private static List<TransactionErrorSummary> sortTransactionErrorSummaries( Iterable<TransactionErrorSummary> errorSummaries, ErrorSummarySortOrder sortOrder) { switch (sortOrder) { case ERROR_COUNT: return orderingByErrorCountDesc.immutableSortedCopy(errorSummaries); case ERROR_RATE: return orderingByErrorRateDesc.immutableSortedCopy(errorSummaries); default: throw new AssertionError("Unexpected sort order: " + sortOrder); } } private static class MutableTransactionErrorSummary { private long errorCount; private long transactionCount; } public enum ErrorSummarySortOrder { ERROR_COUNT, ERROR_RATE } @Value.Immutable public interface TransactionErrorSummary { String transactionName(); long errorCount(); long transactionCount(); } }