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

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

The 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.local.ui;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;

import org.glowroot.shaded.google.common.collect.ImmutableList;
import org.glowroot.shaded.google.common.collect.Lists;
import org.glowroot.shaded.google.common.collect.Maps;

import org.glowroot.collector.AggregateCollector;
import org.glowroot.collector.AggregateIntervalCollector;
import org.glowroot.collector.ErrorPoint;
import org.glowroot.collector.ErrorSummary;
import org.glowroot.config.RollupConfig;
import org.glowroot.local.store.AggregateDao;
import org.glowroot.local.store.AggregateDao.ErrorSummarySortOrder;
import org.glowroot.local.store.ErrorSummaryQuery;
import org.glowroot.local.store.QueryResult;

import static org.glowroot.shaded.google.common.base.Preconditions.checkNotNull;

class ErrorCommonService {

    private final AggregateDao aggregateDao;
    private final @Nullable AggregateCollector aggregateCollector;
    private final ImmutableList rollupConfigs;

    ErrorCommonService(AggregateDao aggregateDao, @Nullable AggregateCollector aggregateCollector,
            ImmutableList rollupConfigs) {
        this.aggregateDao = aggregateDao;
        this.aggregateCollector = aggregateCollector;
        this.rollupConfigs = rollupConfigs;
    }

    // from is non-inclusive
    ErrorSummary readOverallErrorSummary(String transactionType, long from, long to)
            throws SQLException {
        int rollupLevel = aggregateDao.getRollupLevelForView(from, to);
        List orderedIntervalCollectors =
                getOrderedIntervalCollectorsInRange(from, to);
        if (orderedIntervalCollectors.isEmpty()) {
            return aggregateDao.readOverallErrorSummary(transactionType, from, to, rollupLevel);
        }
        long revisedTo = getRevisedTo(to, orderedIntervalCollectors);
        ErrorSummary overallSummary =
                aggregateDao.readOverallErrorSummary(transactionType, from, revisedTo, rollupLevel);
        for (AggregateIntervalCollector intervalCollector : orderedIntervalCollectors) {
            ErrorSummary liveOverallSummary =
                    intervalCollector.getLiveOverallErrorSummary(transactionType);
            if (liveOverallSummary != null) {
                overallSummary = combineErrorSummaries(null, overallSummary, liveOverallSummary);
            }
        }
        return overallSummary;
    }

    // query.from() is non-inclusive
    QueryResult readTransactionErrorSummaries(ErrorSummaryQuery query)
            throws SQLException {
        int rollupLevel = aggregateDao.getRollupLevelForView(query.from(), query.to());
        List orderedIntervalCollectors =
                getOrderedIntervalCollectorsInRange(query.from(), query.to());
        if (orderedIntervalCollectors.isEmpty()) {
            return aggregateDao.readTransactionErrorSummaries(query, rollupLevel);
        }
        long revisedTo = getRevisedTo(query.to(), orderedIntervalCollectors);
        ErrorSummaryQuery revisedQuery = query.withTo(revisedTo);
        QueryResult queryResult =
                aggregateDao.readTransactionErrorSummaries(revisedQuery, rollupLevel);
        if (orderedIntervalCollectors.isEmpty()) {
            return queryResult;
        }
        return mergeInLiveTransactionErrorSummaries(revisedQuery, queryResult,
                orderedIntervalCollectors);
    }

    List readErrorPoints(String transactionType, @Nullable String transactionName,
            long from, long to, long liveCaptureTime) throws Exception {
        int rollupLevel = aggregateDao.getRollupLevelForView(from, to);
        List orderedIntervalCollectors =
                getOrderedIntervalCollectorsInRange(from, to);
        long revisedTo = getRevisedTo(to, orderedIntervalCollectors);
        List errorPoints = readErrorPointsFromDao(transactionType, transactionName,
                from, revisedTo, rollupLevel);
        if (rollupLevel == 0) {
            errorPoints = Lists.newArrayList(errorPoints);
            errorPoints.addAll(getLiveErrorPoints(transactionType, transactionName,
                    orderedIntervalCollectors, liveCaptureTime));
            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(transactionType,
                transactionName, nonRolledUpFrom, revisedTo, 0));
        orderedNonRolledUpErrorPoints.addAll(getLiveErrorPoints(transactionType, transactionName,
                orderedIntervalCollectors, liveCaptureTime));
        errorPoints = Lists.newArrayList(errorPoints);
        errorPoints.addAll(rollUp(orderedNonRolledUpErrorPoints, liveCaptureTime, rollupLevel));
        return errorPoints;
    }

    // from is non-inclusive
    private List getOrderedIntervalCollectorsInRange(long from,
            long to) {
        if (aggregateCollector == null) {
            return ImmutableList.of();
        }
        return aggregateCollector.getOrderedIntervalCollectorsInRange(from, to);
    }

    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 = AggregateDao.getNextRollupTime(
                    errorPoint.captureTime(), fixedIntervalMillis);
            if (rollupTime != currRollupTime && currTransactionCount != 0) {
                rolledUpErrorPoints.add(ErrorPoint.of(Math.min(currRollupTime, liveCaptureTime),
                        currErrorCount, currTransactionCount));
                currErrorCount = 0;
                currTransactionCount = 0;
            }
            currRollupTime = rollupTime;
            currErrorCount += errorPoint.errorCount();
            currTransactionCount += errorPoint.transactionCount();
        }
        if (currTransactionCount != 0) {
            rolledUpErrorPoints.add(ErrorPoint.of(Math.min(currRollupTime, liveCaptureTime),
                    currErrorCount, currTransactionCount));
        }
        return rolledUpErrorPoints;
    }

    private List readErrorPointsFromDao(String transactionType,
            @Nullable String transactionName, long from, long to, int rollupLevel)
                    throws SQLException {
        if (transactionName == null) {
            return aggregateDao.readOverallErrorPoints(transactionType, from, to, rollupLevel);
        } else {
            return aggregateDao.readTransactionErrorPoints(transactionType, transactionName, from,
                    to, rollupLevel);
        }
    }

    private static long getRevisedTo(long to,
            List orderedIntervalCollectors) {
        if (orderedIntervalCollectors.isEmpty()) {
            return to;
        } else {
            // -1 since query 'to' is inclusive
            // this way don't need to worry about de-dupping between live and stored aggregates
            return orderedIntervalCollectors.get(0).getEndTime() - 1;
        }
    }

    private static List getLiveErrorPoints(String transactionType,
            @Nullable String transactionName, List intervalCollectors,
            long liveCaptureTime) throws IOException {
        List errorPoints = Lists.newArrayList();
        for (AggregateIntervalCollector intervalCollector : intervalCollectors) {
            ErrorPoint liveErrorPoint = intervalCollector.getLiveErrorPoint(transactionType,
                    transactionName, liveCaptureTime);
            if (liveErrorPoint != null) {
                errorPoints.add(liveErrorPoint);
            }
        }
        return errorPoints;
    }

    private static ErrorSummary combineErrorSummaries(@Nullable String transactionName,
            ErrorSummary summary1, ErrorSummary summary2) {
        return ErrorSummary.builder()
                .transactionName(transactionName)
                .errorCount(summary1.errorCount() + summary2.errorCount())
                .transactionCount(summary1.transactionCount() + summary2.transactionCount())
                .build();
    }

    private static QueryResult mergeInLiveTransactionErrorSummaries(
            ErrorSummaryQuery query, QueryResult queryResult,
            List intervalCollectors) {
        List errorSummaries = queryResult.records();
        Map errorSummaryMap = Maps.newHashMap();
        for (ErrorSummary errorSummary : errorSummaries) {
            String transactionName = errorSummary.transactionName();
            // transaction name is only null for overall summary
            checkNotNull(transactionName);
            errorSummaryMap.put(transactionName, errorSummary);
        }
        for (AggregateIntervalCollector intervalCollector : intervalCollectors) {
            List liveErrorSummaries =
                    intervalCollector.getLiveTransactionErrorSummaries(query.transactionType());
            for (ErrorSummary liveErrorSummary : liveErrorSummaries) {
                String transactionName = liveErrorSummary.transactionName();
                // transaction name is only null for overall summary
                checkNotNull(transactionName);
                ErrorSummary errorSummary = errorSummaryMap.get(transactionName);
                if (errorSummary == null) {
                    errorSummaryMap.put(transactionName, liveErrorSummary);
                } else {
                    errorSummaryMap.put(transactionName,
                            combineErrorSummaries(transactionName, errorSummary, liveErrorSummary));
                }
            }
        }
        List mergedErrorSummaries = Lists.newArrayList();
        for (ErrorSummary 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 QueryResult(mergedErrorSummaries, moreAvailable);
    }

    private static List sortErrorSummaries(Iterable errorSummaries,
            ErrorSummarySortOrder sortOrder) {
        switch (sortOrder) {
            case ERROR_COUNT:
                return ErrorSummary.orderingByErrorCountDesc.immutableSortedCopy(errorSummaries);
            case ERROR_RATE:
                return ErrorSummary.orderingByErrorRateDesc.immutableSortedCopy(errorSummaries);
            default:
                throw new AssertionError("Unexpected sort order: " + sortOrder);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy