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

org.glowroot.collector.AggregateBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013-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.collector;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;

import org.glowroot.shaded.fasterxml.jackson.databind.ObjectMapper;

import org.glowroot.collector.QueryComponent.AggregateQuery;
import org.glowroot.common.ObjectMappers;
import org.glowroot.common.ScratchBuffer;
import org.glowroot.config.AdvancedConfigBase;
import org.glowroot.transaction.model.Profile;
import org.glowroot.transaction.model.ProfileNode;
import org.glowroot.transaction.model.QueryData;
import org.glowroot.transaction.model.ThreadInfoData;
import org.glowroot.transaction.model.TimerImpl;
import org.glowroot.transaction.model.Transaction;

import static java.util.concurrent.TimeUnit.NANOSECONDS;

// must be used under an appropriate lock
class AggregateBuilder {

    private static final ObjectMapper mapper = ObjectMappers.create();

    private final String transactionType;
    private final @Nullable String transactionName;
    private long totalMicros;
    private long errorCount;
    private long transactionCount;
    private @Nullable Long totalCpuTime;
    private @Nullable Long totalBlockedTime;
    private @Nullable Long totalWaitedTime;
    private @Nullable Long totalAllocatedBytes;
    // histogram uses microseconds to reduce (or at least simplify) bucket allocations
    private final LazyHistogram lazyHistogram = new LazyHistogram();
    private final AggregateTimer syntheticRootTimer = AggregateTimer.createSyntheticRootTimer();
    private final QueryComponent queryComponent;
    private final AggregateProfileBuilder aggregateProfile = new AggregateProfileBuilder();

    AggregateBuilder(String transactionType, @Nullable String transactionName,
            int maxAggregateQueriesPerQueryType) {
        this.transactionType = transactionType;
        this.transactionName = transactionName;
        int hardLimitMultiplierWhileBuilding = transactionName == null
                ? AdvancedConfigBase.OVERALL_AGGREGATE_QUERIES_HARD_LIMIT_MULTIPLIER
                : AdvancedConfigBase.TRANSACTION_AGGREGATE_QUERIES_HARD_LIMIT_MULTIPLIER;
        queryComponent = new QueryComponent(maxAggregateQueriesPerQueryType,
                hardLimitMultiplierWhileBuilding);
    }

    void add(Transaction transaction) {
        long durationMicros = NANOSECONDS.toMicros(transaction.getDuration());
        totalMicros += durationMicros;
        if (transaction.getErrorMessage() != null) {
            errorCount++;
        }
        transactionCount++;
        ThreadInfoData threadInfo = transaction.getThreadInfo();
        if (threadInfo != null) {
            totalCpuTime = nullAwareAdd(totalCpuTime, threadInfo.threadCpuTime());
            totalBlockedTime = nullAwareAdd(totalBlockedTime, threadInfo.threadBlockedTime());
            totalWaitedTime = nullAwareAdd(totalWaitedTime, threadInfo.threadWaitedTime());
            totalAllocatedBytes =
                    nullAwareAdd(totalAllocatedBytes, threadInfo.threadAllocatedBytes());
        }
        lazyHistogram.add(durationMicros);
    }

    void addToTimers(TimerImpl rootTimer) {
        syntheticRootTimer.mergeAsChildTimer(rootTimer);
    }

    void addToQueries(Iterable queries) {
        for (QueryData query : queries) {
            queryComponent.mergeQuery(query);
        }
    }

    void addToProfile(Profile profile) {
        aggregateProfile.addProfile(profile);
    }

    Aggregate build(long captureTime, ScratchBuffer scratchBuffer) throws IOException {
        ByteBuffer buffer = scratchBuffer.getBuffer(lazyHistogram.getNeededByteBufferCapacity());
        buffer.clear();
        byte[] histogram = lazyHistogram.encodeUsingTempByteBuffer(buffer);
        return Aggregate.builder()
                .transactionType(transactionType)
                .transactionName(transactionName)
                .captureTime(captureTime)
                .totalMicros(totalMicros)
                .errorCount(errorCount)
                .transactionCount(transactionCount)
                .totalCpuMicros(nullAwareNanosToMicros(totalCpuTime))
                .totalBlockedMicros(nullAwareNanosToMicros(totalBlockedTime))
                .totalWaitedMicros(nullAwareNanosToMicros(totalWaitedTime))
                .totalAllocatedKBytes(nullAwareBytesToKBytes(totalAllocatedBytes))
                .histogram(histogram)
                .timers(mapper.writeValueAsString(syntheticRootTimer))
                .queries(getQueriesJson())
                .profile(getProfileJson())
                .build();
    }

    TransactionSummary getLiveTransactionSummary() {
        return TransactionSummary.builder()
                .transactionName(transactionName)
                .totalMicros(totalMicros)
                .transactionCount(transactionCount)
                .build();
    }

    ErrorSummary getLiveErrorSummary() {
        return ErrorSummary.builder()
                .transactionName(transactionName)
                .errorCount(errorCount)
                .transactionCount(transactionCount)
                .build();
    }

    @Nullable
    ErrorPoint buildErrorPoint(long captureTime) {
        if (errorCount == 0) {
            return null;
        }
        return ErrorPoint.builder()
                .captureTime(captureTime)
                .errorCount(errorCount)
                .transactionCount(transactionCount)
                .build();
    }

    @Nullable
    String getQueriesJson() throws IOException {
        Map> queries = queryComponent.getOrderedAndTruncatedQueries();
        if (queries.isEmpty()) {
            return null;
        }
        return mapper.writeValueAsString(queries);
    }

    @Nullable
    String getProfileJson() throws IOException {
        ProfileNode syntheticRootNode = aggregateProfile.getSyntheticRootNode();
        if (syntheticRootNode.isChildNodesEmpty()) {
            return null;
        }
        return mapper.writeValueAsString(syntheticRootNode);
    }

    private static @Nullable Long nullAwareNanosToMicros(@Nullable Long nanoseconds) {
        if (nanoseconds == null) {
            return null;
        }
        return NANOSECONDS.toMicros(nanoseconds);
    }

    private static @Nullable Long nullAwareBytesToKBytes(@Nullable Long bytes) {
        if (bytes == null) {
            return null;
        }
        return bytes / 1024;
    }

    private static @Nullable Long nullAwareAdd(@Nullable Long x, @Nullable Long y) {
        if (x == null) {
            return y;
        }
        if (y == null) {
            return x;
        }
        return x + y;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy