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

org.glowroot.agent.model.ServiceCallCollector Maven / Gradle / Ivy

There is a newer version: 0.14.0-beta.3
Show newest version
/*
 * Copyright 2016-2018 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.agent.model;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.Lists;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.Maps;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.primitives.Doubles;

import org.glowroot.agent.shaded.org.glowroot.wire.api.model.AggregateOuterClass.Aggregate;

public class ServiceCallCollector {

    private static final String LIMIT_EXCEEDED_BUCKET = "LIMIT EXCEEDED BUCKET";

    // first key is the service call type, second key is the service call text
    private final Map> serviceCalls = Maps.newHashMap();
    private final Map limitExceededBuckets = Maps.newHashMap();
    private final int limit;
    private final int hardLimitMultiplierWhileBuilding;

    private int serviceCallCount;

    public ServiceCallCollector(int limit, int hardLimitMultiplierWhileBuilding) {
        this.limit = limit;
        this.hardLimitMultiplierWhileBuilding = hardLimitMultiplierWhileBuilding;
    }

    public List toAggregateProto() {
        // " + serviceCalls.size()" is to cover the maximum number of limit exceeded buckets
        List allServiceCalls = Lists
                .newArrayListWithCapacity(Math.min(serviceCallCount, limit) + serviceCalls.size());
        for (Map.Entry> outerEntry : serviceCalls
                .entrySet()) {
            for (Map.Entry innerEntry : outerEntry.getValue()
                    .entrySet()) {
                allServiceCalls.add(innerEntry.getValue().toAggregateProto(outerEntry.getKey(),
                        innerEntry.getKey()));
            }
        }
        if (allServiceCalls.size() <= limit) {
            // there could be limit exceeded buckets if hardLimitMultiplierWhileBuilding is 1
            for (Map.Entry entry : limitExceededBuckets.entrySet()) {
                allServiceCalls.add(
                        entry.getValue().toAggregateProto(entry.getKey(), LIMIT_EXCEEDED_BUCKET));
            }
            sort(allServiceCalls);
            return allServiceCalls;
        }
        sort(allServiceCalls);
        List exceededServiceCalls =
                allServiceCalls.subList(limit, allServiceCalls.size());
        allServiceCalls = Lists.newArrayList(allServiceCalls.subList(0, limit));
        // do not modify original limit exceeded buckets since adding exceeded queries below
        Map limitExceededBuckets = copyLimitExceededBuckets();
        for (Aggregate.ServiceCall exceededServiceCall : exceededServiceCalls) {
            String queryType = exceededServiceCall.getType();
            MutableServiceCall limitExceededBucket = limitExceededBuckets.get(queryType);
            if (limitExceededBucket == null) {
                limitExceededBucket = new MutableServiceCall();
                limitExceededBuckets.put(queryType, limitExceededBucket);
            }
            limitExceededBucket.add(exceededServiceCall);
        }
        for (Map.Entry entry : limitExceededBuckets.entrySet()) {
            allServiceCalls
                    .add(entry.getValue().toAggregateProto(entry.getKey(), LIMIT_EXCEEDED_BUCKET));
        }
        // need to re-sort now including limit exceeded bucket
        sort(allServiceCalls);
        return allServiceCalls;
    }

    public void mergeServiceCall(String serviceCallType, String serviceCallText,
            double totalDurationNanos, long executionCount) {
        Map serviceCallsForType = serviceCalls.get(serviceCallType);
        if (serviceCallsForType == null) {
            serviceCallsForType = Maps.newHashMap();
            serviceCalls.put(serviceCallType, serviceCallsForType);
        }
        MutableServiceCall aggregateServiceCall = serviceCallsForType.get(serviceCallText);
        if (aggregateServiceCall == null) {
            if (serviceCallCount < limit * hardLimitMultiplierWhileBuilding) {
                aggregateServiceCall = new MutableServiceCall();
                serviceCallsForType.put(serviceCallText, aggregateServiceCall);
                serviceCallCount++;
            } else {
                aggregateServiceCall = getOrCreateLimitExceededBucket(serviceCallType);
            }
        }
        aggregateServiceCall.addToTotalDurationNanos(totalDurationNanos);
        aggregateServiceCall.addToExecutionCount(executionCount);
    }

    public void mergeServiceCallsInto(ServiceCallCollector collector) {
        for (Map.Entry> outerEntry : serviceCalls
                .entrySet()) {
            for (Map.Entry entry : outerEntry.getValue().entrySet()) {
                MutableServiceCall serviceCall = entry.getValue();
                collector.mergeServiceCall(outerEntry.getKey(), entry.getKey(),
                        serviceCall.getTotalDurationNanos(), serviceCall.getExecutionCount());
            }
        }
        for (Map.Entry limitExceededBucket : limitExceededBuckets
                .entrySet()) {
            collector.mergeLimitExceededBucket(limitExceededBucket.getKey(),
                    limitExceededBucket.getValue());
        }
    }

    public void mergeServiceCallsInto(org.glowroot.agent.shaded.org.glowroot.common.model.ServiceCallCollector collector) {
        for (Map.Entry> outerEntry : serviceCalls
                .entrySet()) {
            for (Map.Entry entry : outerEntry.getValue().entrySet()) {
                MutableServiceCall serviceCall = entry.getValue();
                collector.mergeServiceCall(outerEntry.getKey(), entry.getKey(),
                        serviceCall.getTotalDurationNanos(), serviceCall.getExecutionCount());
            }
        }
        for (Map.Entry limitExceededBucket : limitExceededBuckets
                .entrySet()) {
            MutableServiceCall serviceCall = limitExceededBucket.getValue();
            collector.mergeServiceCall(limitExceededBucket.getKey(), LIMIT_EXCEEDED_BUCKET,
                    serviceCall.getTotalDurationNanos(), serviceCall.getExecutionCount());
        }
    }

    private void mergeLimitExceededBucket(String serviceCallType,
            MutableServiceCall limitExceededBucket) {
        MutableServiceCall serviceCall = getOrCreateLimitExceededBucket(serviceCallType);
        serviceCall.add(limitExceededBucket);
    }

    private MutableServiceCall getOrCreateLimitExceededBucket(String serviceCallType) {
        MutableServiceCall serviceCall = limitExceededBuckets.get(serviceCallType);
        if (serviceCall == null) {
            serviceCall = new MutableServiceCall();
            limitExceededBuckets.put(serviceCallType, serviceCall);
        }
        return serviceCall;
    }

    private Map copyLimitExceededBuckets() {
        Map copies = Maps.newHashMap();
        for (Map.Entry entry : limitExceededBuckets.entrySet()) {
            String serviceCallType = entry.getKey();
            MutableServiceCall limitExceededBucket = entry.getValue();
            MutableServiceCall copy = new MutableServiceCall();
            copy.add(limitExceededBucket);
            copies.put(serviceCallType, copy);
        }
        return copies;
    }

    private static void sort(List serviceCalls) {
        // reverse sort by total
        Collections.sort(serviceCalls, new Comparator() {
            @Override
            public int compare(Aggregate.ServiceCall left, Aggregate.ServiceCall right) {
                return Doubles.compare(right.getTotalDurationNanos(), left.getTotalDurationNanos());
            }
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy