
org.glowroot.ui.ErrorCommonService Maven / Gradle / Ivy
/*
* Copyright 2014-2015 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.ui;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.glowroot.agent.shaded.google.common.annotations.VisibleForTesting;
import org.glowroot.agent.shaded.google.common.collect.ImmutableList;
import org.glowroot.agent.shaded.google.common.collect.Lists;
import org.glowroot.agent.shaded.google.common.collect.Maps;
import org.glowroot.agent.shaded.google.common.collect.Ordering;
import org.glowroot.agent.shaded.google.common.primitives.Doubles;
import org.glowroot.agent.shaded.google.common.primitives.Longs;
import org.glowroot.common.live.ImmutableErrorPoint;
import org.glowroot.common.live.ImmutableOverallErrorSummary;
import org.glowroot.common.live.ImmutableTransactionErrorSummary;
import org.glowroot.common.live.LiveAggregateRepository;
import org.glowroot.common.live.LiveAggregateRepository.ErrorPoint;
import org.glowroot.common.live.LiveAggregateRepository.LiveResult;
import org.glowroot.common.live.LiveAggregateRepository.OverallErrorSummary;
import org.glowroot.common.live.LiveAggregateRepository.TransactionErrorSummary;
import org.glowroot.storage.repo.AggregateRepository;
import org.glowroot.storage.repo.AggregateRepository.ErrorSummaryQuery;
import org.glowroot.storage.repo.ConfigRepository.RollupConfig;
import org.glowroot.storage.repo.ImmutableErrorSummaryQuery;
import org.glowroot.storage.repo.Result;
import org.glowroot.storage.repo.Utils;
import static org.glowroot.agent.shaded.google.common.base.Preconditions.checkNotNull;
class ErrorCommonService {
@VisibleForTesting
static final Ordering orderingByErrorCountDesc =
new Ordering() {
@Override
public int compare(TransactionErrorSummary left, TransactionErrorSummary right) {
return Longs.compare(right.errorCount(), left.errorCount());
}
};
@VisibleForTesting
static final Ordering orderingByErrorRateDesc =
new Ordering() {
@Override
public int compare(TransactionErrorSummary left, TransactionErrorSummary right) {
return Doubles.compare(right.errorCount() / (double) right.transactionCount(),
left.errorCount() / (double) left.transactionCount());
}
};
private final AggregateRepository aggregateRepository;
private final LiveAggregateRepository liveAggregateRepository;
private final ImmutableList rollupConfigs;
ErrorCommonService(AggregateRepository aggregateRepository,
LiveAggregateRepository liveAggregateRepository, List rollupConfigs) {
this.aggregateRepository = aggregateRepository;
this.liveAggregateRepository = liveAggregateRepository;
this.rollupConfigs = ImmutableList.copyOf(rollupConfigs);
}
// from is non-inclusive
OverallErrorSummary readOverallErrorSummary(String serverRollup, String transactionType,
long from, long to) throws Exception {
int rollupLevel = aggregateRepository.getRollupLevelForView(serverRollup, from, to);
LiveResult liveResult = liveAggregateRepository
.getLiveOverallErrorSummary(serverRollup, transactionType, from, to);
if (liveResult == null) {
return aggregateRepository.readOverallErrorSummary(serverRollup, transactionType, from,
to, rollupLevel);
}
// -1 since query 'to' is inclusive
// this way don't need to worry about de-dupping between live and stored aggregates
long revisedTo = liveResult.initialCaptureTime() - 1;
OverallErrorSummary overallSummary = aggregateRepository.readOverallErrorSummary(
serverRollup, transactionType, from, revisedTo, rollupLevel);
for (OverallErrorSummary liveOverallErrorSummary : liveResult.get()) {
overallSummary = combineOverallErrorSummaries(overallSummary, liveOverallErrorSummary);
}
return overallSummary;
}
// query.from() is non-inclusive
Result readTransactionErrorSummaries(ErrorSummaryQuery query)
throws Exception {
LiveResult> liveResult =
liveAggregateRepository.getLiveTransactionErrorSummaries(query.serverRollup(),
query.transactionType(), query.from(), query.to());
if (liveResult == null) {
return aggregateRepository.readTransactionErrorSummaries(query);
}
// -1 since query 'to' is inclusive
// this way don't need to worry about de-dupping between live and stored aggregates
long revisedTo = liveResult.initialCaptureTime() - 1;
ErrorSummaryQuery revisedQuery =
ImmutableErrorSummaryQuery.builder().copyFrom(query).to(revisedTo).build();
Result queryResult =
aggregateRepository.readTransactionErrorSummaries(revisedQuery);
return mergeInLiveTransactionErrorSummaries(revisedQuery, queryResult, liveResult.get());
}
List readErrorPoints(String serverRollup, String transactionType,
@Nullable String transactionName, long from, long to, long liveCaptureTime)
throws Exception {
int rollupLevel = aggregateRepository.getRollupLevelForView(serverRollup, from, to);
LiveResult liveResult = liveAggregateRepository.getLiveErrorPoints(serverRollup,
transactionType, transactionName, from, to, liveCaptureTime);
// -1 since query 'to' is inclusive
// this way don't need to worry about de-dupping between live and stored aggregates
long revisedTo = liveResult == null ? to : liveResult.initialCaptureTime() - 1;
List errorPoints = readErrorPointsFromDao(serverRollup, transactionType,
transactionName, from, revisedTo, rollupLevel);
if (rollupLevel == 0) {
errorPoints = Lists.newArrayList(errorPoints);
if (liveResult != null) {
errorPoints.addAll(liveResult.get());
}
return errorPoints;
}
long nonRolledUpFrom = from;
if (!errorPoints.isEmpty()) {
long lastRolledUpTime = errorPoints.get(errorPoints.size() - 1).captureTime();
nonRolledUpFrom = Math.max(nonRolledUpFrom, lastRolledUpTime + 1);
}
List orderedNonRolledUpErrorPoints = Lists.newArrayList();
orderedNonRolledUpErrorPoints.addAll(readErrorPointsFromDao(serverRollup, transactionType,
transactionName, nonRolledUpFrom, revisedTo, 0));
if (liveResult != null) {
orderedNonRolledUpErrorPoints.addAll(liveResult.get());
}
errorPoints = Lists.newArrayList(errorPoints);
errorPoints.addAll(rollUp(orderedNonRolledUpErrorPoints, liveCaptureTime, rollupLevel));
return errorPoints;
}
private List rollUp(List orderedNonRolledUpErrorPoints,
long liveCaptureTime, int rollupLevel) {
long fixedIntervalMillis = rollupConfigs.get(rollupLevel).intervalMillis();
List rolledUpErrorPoints = Lists.newArrayList();
long currRollupTime = Long.MIN_VALUE;
long currErrorCount = 0;
long currTransactionCount = 0;
for (ErrorPoint errorPoint : orderedNonRolledUpErrorPoints) {
long rollupTime =
Utils.getNextRollupTime(errorPoint.captureTime(), fixedIntervalMillis);
if (rollupTime != currRollupTime && currTransactionCount != 0) {
rolledUpErrorPoints
.add(ImmutableErrorPoint.of(Math.min(currRollupTime, liveCaptureTime),
currErrorCount, currTransactionCount));
currErrorCount = 0;
currTransactionCount = 0;
}
currRollupTime = rollupTime;
currErrorCount += errorPoint.errorCount();
currTransactionCount += errorPoint.transactionCount();
}
if (currTransactionCount != 0) {
rolledUpErrorPoints
.add(ImmutableErrorPoint.of(Math.min(currRollupTime, liveCaptureTime),
currErrorCount, currTransactionCount));
}
return rolledUpErrorPoints;
}
private List readErrorPointsFromDao(String serverRollup, String transactionType,
@Nullable String transactionName, long from, long to, int rollupLevel)
throws Exception {
if (transactionName == null) {
return aggregateRepository.readOverallErrorPoints(serverRollup, transactionType, from,
to, rollupLevel);
} else {
return aggregateRepository.readTransactionErrorPoints(serverRollup, transactionType,
transactionName, from, to, rollupLevel);
}
}
private static OverallErrorSummary combineOverallErrorSummaries(OverallErrorSummary summary1,
OverallErrorSummary summary2) {
return ImmutableOverallErrorSummary.builder()
.errorCount(summary1.errorCount() + summary2.errorCount())
.transactionCount(summary1.transactionCount() + summary2.transactionCount())
.build();
}
private static TransactionErrorSummary combineTransactionErrorSummaries(String transactionName,
TransactionErrorSummary summary1, TransactionErrorSummary summary2) {
return ImmutableTransactionErrorSummary.builder()
.transactionName(transactionName)
.errorCount(summary1.errorCount() + summary2.errorCount())
.transactionCount(summary1.transactionCount() + summary2.transactionCount())
.build();
}
private static Result mergeInLiveTransactionErrorSummaries(
ErrorSummaryQuery query, Result queryResult,
List> liveErrorSummaries) {
List errorSummaries = queryResult.records();
Map errorSummaryMap = Maps.newHashMap();
for (TransactionErrorSummary errorSummary : errorSummaries) {
String transactionName = errorSummary.transactionName();
// transaction name is only null for overall summary
checkNotNull(transactionName);
errorSummaryMap.put(transactionName, errorSummary);
}
for (List mid : liveErrorSummaries) {
for (TransactionErrorSummary liveErrorSummary : mid) {
String transactionName = liveErrorSummary.transactionName();
// transaction name is only null for overall summary
checkNotNull(transactionName);
TransactionErrorSummary errorSummary = errorSummaryMap.get(transactionName);
if (errorSummary == null) {
errorSummaryMap.put(transactionName, liveErrorSummary);
} else {
errorSummaryMap.put(transactionName, combineTransactionErrorSummaries(
transactionName, errorSummary, liveErrorSummary));
}
}
}
List mergedErrorSummaries = Lists.newArrayList();
for (TransactionErrorSummary errorSummary : errorSummaryMap.values()) {
if (errorSummary.errorCount() > 0) {
mergedErrorSummaries.add(errorSummary);
}
}
mergedErrorSummaries = sortErrorSummaries(mergedErrorSummaries, query.sortOrder());
boolean moreAvailable = queryResult.moreAvailable();
if (mergedErrorSummaries.size() > query.limit()) {
moreAvailable = true;
mergedErrorSummaries = mergedErrorSummaries.subList(0, query.limit());
}
return new Result(mergedErrorSummaries, moreAvailable);
}
private static List sortErrorSummaries(
Iterable errorSummaries,
AggregateRepository.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);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy