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

org.glowroot.agent.fat.storage.TracePointQueryBuilder Maven / Gradle / Ivy

There is a newer version: 0.9.24
Show newest version
/*
 * Copyright 2013-2016 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.fat.storage;

import java.util.List;
import java.util.Locale;

import javax.annotation.Nullable;

import org.glowroot.agent.shaded.google.common.base.Strings;
import org.glowroot.agent.shaded.google.common.collect.ImmutableList;
import org.glowroot.agent.shaded.google.common.collect.Lists;
import org.checkerframework.checker.tainting.qual.Untainted;
import org.immutables.value.Value;

import org.glowroot.agent.shaded.glowroot.common.live.LiveTraceRepository.TraceKind;
import org.glowroot.agent.shaded.glowroot.common.live.LiveTraceRepository.TracePointFilter;
import org.glowroot.agent.shaded.glowroot.common.live.StringComparator;
import org.glowroot.agent.shaded.glowroot.common.util.Styles;
import org.glowroot.agent.shaded.glowroot.storage.repo.TraceRepository.TraceQuery;

class TracePointQueryBuilder {

    private final TraceKind traceKind;
    private final TraceQuery query;
    private final TracePointFilter filter;
    private final int limit;

    TracePointQueryBuilder(TraceKind traceKind, TraceQuery query, TracePointFilter filter,
            int limit) {
        this.traceKind = traceKind;
        this.query = query;
        this.filter = filter;
        this.limit = limit;
    }

    // capture time lower bound is non-inclusive so that aggregate data intervals can be mapped
    // to their trace points (aggregate data intervals are non-inclusive on lower bound and
    // inclusive on upper bound)
    ParameterizedSql getParameterizedSql() {
        ParameterizedSqlBuilder builder = new ParameterizedSqlBuilder();
        builder.appendText("select trace.id, trace.capture_time, trace.duration_nanos, trace.error"
                + " from trace");
        ParameterizedSql criteria = getAttributeCriteria();
        if (criteria == null) {
            builder.appendText(" where");
        } else {
            builder.appendText(", trace_attribute attr where attr.trace_id = trace.id"
                    + " and attr.capture_time > ? and attr.capture_time <= ? and" + criteria.sql());
            builder.addArg(query.from());
            builder.addArg(query.to());
            builder.addArgs(criteria.args());

        }
        builder.appendText(" trace.capture_time > ? and trace.capture_time <= ?");
        builder.addArg(query.from());
        builder.addArg(query.to());
        appendTraceKindCriteria(builder);
        appendTransactionTypeCriteria(builder);
        appendTransactionNameCriteria(builder);
        appendDurationNanosCriteria(builder);
        appendHeadlineCriteria(builder);
        appendErrorCriteria(builder);
        appendUserCriteria(builder);
        appendOrderByAndLimit(builder);
        return builder.build();
    }

    private @Nullable ParameterizedSql getAttributeCriteria() {
        String sql = "";
        List args = Lists.newArrayList();
        String attributeName = filter.attributeName();
        if (!Strings.isNullOrEmpty(attributeName)) {
            sql += " upper(attr.name) = ? and";
            args.add(attributeName.toUpperCase(Locale.ENGLISH));
        }
        StringComparator attributeValueComparator = filter.attributeValueComparator();
        String attributeValue = filter.attributeValue();
        if (attributeValueComparator != null && !Strings.isNullOrEmpty(attributeValue)) {
            sql += " upper(attr.value) " + attributeValueComparator.getComparator() + " ? and";
            args.add(attributeValueComparator.formatParameter(attributeValue));
        }
        if (sql.equals("")) {
            return null;
        } else {
            return ImmutableParameterizedSql.of(sql, args);
        }
    }

    private void appendTraceKindCriteria(ParameterizedSqlBuilder builder) {
        if (traceKind == TraceKind.SLOW) {
            builder.appendText(" and trace.slow = ?");
            builder.addArg(true);
        } else {
            // TraceKind.ERROR
            builder.appendText(" and trace.error = ?");
            builder.addArg(true);
        }
    }

    private void appendTransactionTypeCriteria(ParameterizedSqlBuilder builder) {
        builder.appendText(" and trace.transaction_type = ?");
        builder.addArg(query.transactionType());
    }

    private void appendTransactionNameCriteria(ParameterizedSqlBuilder builder) {
        String transactionName = query.transactionName();
        if (transactionName != null) {
            builder.appendText(" and trace.transaction_name = ?");
            builder.addArg(transactionName);
        }
    }

    private void appendDurationNanosCriteria(ParameterizedSqlBuilder builder) {
        long durationNanosLow = filter.durationNanosLow();
        if (durationNanosLow > 0) {
            builder.appendText(" and trace.duration_nanos >= ?");
            builder.addArg(durationNanosLow);
        }
        Long durationNanosHigh = filter.durationNanosHigh();
        if (durationNanosHigh != null) {
            builder.appendText(" and trace.duration_nanos <= ?");
            builder.addArg(durationNanosHigh);
        }
    }

    private void appendHeadlineCriteria(ParameterizedSqlBuilder builder) {
        StringComparator headlineComparator = filter.headlineComparator();
        String headline = filter.headline();
        if (headlineComparator != null && !Strings.isNullOrEmpty(headline)) {
            builder.appendText(
                    " and upper(trace.headline) " + headlineComparator.getComparator() + " ?");
            builder.addArg(headlineComparator.formatParameter(headline));
        }
    }

    private void appendErrorCriteria(ParameterizedSqlBuilder builder) {
        StringComparator errorComparator = filter.errorMessageComparator();
        String error = filter.errorMessage();
        if (errorComparator != null && !Strings.isNullOrEmpty(error)) {
            builder.appendText(
                    " and upper(trace.error_message) " + errorComparator.getComparator() + " ?");
            builder.addArg(errorComparator.formatParameter(error));
        }
    }

    private void appendUserCriteria(ParameterizedSqlBuilder builder) {
        StringComparator userComparator = filter.userComparator();
        String user = filter.user();
        if (userComparator != null && !Strings.isNullOrEmpty(user)) {
            builder.appendText(" and upper(trace.user) " + userComparator.getComparator() + " ?");
            builder.addArg(userComparator.formatParameter(user));
        }
    }

    private void appendOrderByAndLimit(ParameterizedSqlBuilder builder) {
        builder.appendText(" order by trace.duration_nanos");
        if (limit != 0) {
            // +1 is to identify if limit was exceeded
            builder.appendText(" desc limit ?");
            builder.addArg(limit + 1);
        }
    }

    @Value.Immutable
    @Styles.AllParameters
    abstract static class ParameterizedSql {

        abstract @Untainted String sql();
        abstract ImmutableList args();

        Object[] argsAsArray() {
            return args().toArray(new Object[args().size()]);
        }
    }

    private static class ParameterizedSqlBuilder {

        private @Untainted String sql = "";
        private final List args = Lists.newArrayList();

        private void appendText(@Untainted String sql) {
            this.sql += sql;
        }

        public void addArg(Object arg) {
            args.add(arg);
        }

        public void addArgs(List args) {
            this.args.addAll(args);
        }

        private ParameterizedSql build() {
            return ImmutableParameterizedSql.of(sql, args);
        }
    }
}