All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.ui.ErrorCommonService Maven / Gradle / Ivy

There is a newer version: 0.9.28
Show newest version
/*
 * 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