org.glowroot.collector.AggregateIntervalCollector Maven / Gradle / Ivy
The newest version!
/*
* Copyright 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.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
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.shaded.google.common.io.CharSource;
import org.glowroot.shaded.slf4j.Logger;
import org.glowroot.shaded.slf4j.LoggerFactory;
import org.glowroot.common.ScratchBuffer;
import org.glowroot.config.ConfigService;
import org.glowroot.local.store.AggregateDao;
import org.glowroot.transaction.model.Profile;
import org.glowroot.transaction.model.Transaction;
public class AggregateIntervalCollector {
private static final Logger logger = LoggerFactory.getLogger(AggregateIntervalCollector.class);
private static final AtomicBoolean maxAggregateTransactionsWarnLogged = new AtomicBoolean();
private final long endTime;
private final Map typeCollectors = Maps.newConcurrentMap();
private final int maxAggregateTransactionsPerTransactionType;
private final int maxAggregateQueriesPerQueryType;
AggregateIntervalCollector(long currentTime, long fixedAggregateIntervalMillis,
ConfigService configService) {
endTime = AggregateDao.getNextRollupTime(currentTime,
fixedAggregateIntervalMillis);
this.maxAggregateTransactionsPerTransactionType =
configService.getAdvancedConfig().maxAggregateTransactionsPerTransactionType();
this.maxAggregateQueriesPerQueryType =
configService.getAdvancedConfig().maxAggregateQueriesPerQueryType();
}
public long getEndTime() {
return endTime;
}
void add(Transaction transaction) {
IntervalTypeCollector typeBuilder = getTypeBuilder(transaction.getTransactionType());
typeBuilder.add(transaction);
}
void flush(AggregateRepository aggregateRepository) throws Exception {
List overallAggregates = Lists.newArrayList();
List transactionAggregates = Lists.newArrayList();
ScratchBuffer scratchBuffer = new ScratchBuffer();
for (Entry e : typeCollectors.entrySet()) {
IntervalTypeCollector intervalTypeCollector = e.getValue();
overallAggregates.add(build(intervalTypeCollector.overallBuilder, scratchBuffer));
for (Entry f : intervalTypeCollector.transactionBuilders
.entrySet()) {
transactionAggregates.add(build(f.getValue(), scratchBuffer));
}
}
aggregateRepository.store(overallAggregates, transactionAggregates, endTime);
}
public @Nullable TransactionSummary getLiveOverallSummary(String transactionType) {
IntervalTypeCollector intervalTypeCollector = typeCollectors.get(transactionType);
if (intervalTypeCollector == null) {
return null;
}
AggregateBuilder aggregateBuilder = intervalTypeCollector.overallBuilder;
synchronized (aggregateBuilder) {
return aggregateBuilder.getLiveTransactionSummary();
}
}
public List getLiveTransactionSummaries(String transactionType) {
IntervalTypeCollector intervalTypeCollector = typeCollectors.get(transactionType);
if (intervalTypeCollector == null) {
return ImmutableList.of();
}
List transactionSummaries = Lists.newArrayList();
for (Entry entry : intervalTypeCollector.transactionBuilders
.entrySet()) {
AggregateBuilder aggregateBuilder = entry.getValue();
synchronized (aggregateBuilder) {
transactionSummaries.add(aggregateBuilder.getLiveTransactionSummary());
}
}
return transactionSummaries;
}
public @Nullable ErrorSummary getLiveOverallErrorSummary(String transactionType) {
IntervalTypeCollector intervalTypeCollector = typeCollectors.get(transactionType);
if (intervalTypeCollector == null) {
return null;
}
AggregateBuilder aggregateBuilder = intervalTypeCollector.overallBuilder;
synchronized (aggregateBuilder) {
return aggregateBuilder.getLiveErrorSummary();
}
}
public List getLiveTransactionErrorSummaries(String transactionType) {
IntervalTypeCollector intervalTypeCollector = typeCollectors.get(transactionType);
if (intervalTypeCollector == null) {
return ImmutableList.of();
}
List errorSummaries = Lists.newArrayList();
for (Entry entry : intervalTypeCollector.transactionBuilders
.entrySet()) {
AggregateBuilder aggregateBuilder = entry.getValue();
synchronized (aggregateBuilder) {
errorSummaries.add(aggregateBuilder.getLiveErrorSummary());
}
}
return errorSummaries;
}
public @Nullable Aggregate getLiveAggregate(String transactionType,
@Nullable String transactionName, long liveCaptureTime) throws IOException {
AggregateBuilder aggregateBuilder = getAggregateBuilder(transactionType, transactionName);
if (aggregateBuilder == null) {
return null;
}
synchronized (aggregateBuilder) {
long capturedAt = Math.min(liveCaptureTime, endTime);
return aggregateBuilder.build(capturedAt, new ScratchBuffer());
}
}
public @Nullable ErrorPoint getLiveErrorPoint(String transactionType,
@Nullable String transactionName, long liveCaptureTime) throws IOException {
AggregateBuilder aggregateBuilder = getAggregateBuilder(transactionType, transactionName);
if (aggregateBuilder == null) {
return null;
}
synchronized (aggregateBuilder) {
long capturedAt = Math.min(liveCaptureTime, endTime);
return aggregateBuilder.buildErrorPoint(capturedAt);
}
}
public @Nullable QueryAggregate getLiveQueryAggregate(String transactionType,
@Nullable String transactionName) throws IOException {
AggregateBuilder aggregateBuilder = getAggregateBuilder(transactionType, transactionName);
if (aggregateBuilder == null) {
return null;
}
String queriesJson;
synchronized (aggregateBuilder) {
queriesJson = aggregateBuilder.getQueriesJson();
}
if (queriesJson == null) {
return null;
}
return QueryAggregate.of(endTime, CharSource.wrap(queriesJson));
}
public @Nullable ProfileAggregate getLiveProfileAggregate(String transactionType,
@Nullable String transactionName) throws IOException {
AggregateBuilder aggregateBuilder = getAggregateBuilder(transactionType, transactionName);
if (aggregateBuilder == null) {
return null;
}
String profileJson;
synchronized (aggregateBuilder) {
profileJson = aggregateBuilder.getProfileJson();
}
if (profileJson == null) {
return null;
}
return ProfileAggregate.of(endTime, CharSource.wrap(profileJson));
}
void clear() {
typeCollectors.clear();
}
private IntervalTypeCollector getTypeBuilder(String transactionType) {
IntervalTypeCollector typeBuilder;
typeBuilder = typeCollectors.get(transactionType);
if (typeBuilder == null) {
typeBuilder = new IntervalTypeCollector(transactionType);
typeCollectors.put(transactionType, typeBuilder);
}
return typeBuilder;
}
private Aggregate build(AggregateBuilder aggregateBuilder, ScratchBuffer scratchBuffer)
throws IOException {
synchronized (aggregateBuilder) {
return aggregateBuilder.build(endTime, scratchBuffer);
}
}
private @Nullable AggregateBuilder getAggregateBuilder(String transactionType,
@Nullable String transactionName) {
IntervalTypeCollector intervalTypeCollector = typeCollectors.get(transactionType);
if (intervalTypeCollector == null) {
return null;
}
if (transactionName == null) {
return intervalTypeCollector.overallBuilder;
} else {
return intervalTypeCollector.transactionBuilders.get(transactionName);
}
}
private class IntervalTypeCollector {
private final String transactionType;
private final AggregateBuilder overallBuilder;
private final Map transactionBuilders = Maps.newConcurrentMap();
private IntervalTypeCollector(String transactionType) {
this.transactionType = transactionType;
overallBuilder =
new AggregateBuilder(transactionType, null, maxAggregateQueriesPerQueryType);
}
private void add(Transaction transaction) {
Profile profile = transaction.getProfile();
synchronized (overallBuilder) {
overallBuilder.add(transaction);
overallBuilder.addToTimers(transaction.getRootTimer());
overallBuilder.addToQueries(transaction.getQueries());
if (profile != null) {
overallBuilder.addToProfile(profile);
}
}
AggregateBuilder transactionBuilder =
transactionBuilders.get(transaction.getTransactionName());
if (transactionBuilder == null
&& transactionBuilders.size() < maxAggregateTransactionsPerTransactionType) {
transactionBuilder = new AggregateBuilder(transactionType,
transaction.getTransactionName(), maxAggregateQueriesPerQueryType);
transactionBuilders.put(transaction.getTransactionName(), transactionBuilder);
}
if (transactionBuilder == null) {
if (!maxAggregateTransactionsWarnLogged.getAndSet(true)) {
logger.warn("the max transaction names per transaction type was exceeded"
+ " during the current interval. consider increasing the limit under"
+ " Configuration > Advanced, or reducing the number of transaction"
+ " names by configuring instrumentation points under Configuration"
+ " > Instrumentation that override the transaction name.");
}
return;
}
synchronized (transactionBuilder) {
transactionBuilder.add(transaction);
transactionBuilder.addToTimers(transaction.getRootTimer());
transactionBuilder.addToQueries(transaction.getQueries());
if (profile != null) {
overallBuilder.addToProfile(profile);
transactionBuilder.addToProfile(profile);
}
}
}
}
}