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

org.glowroot.common.config.InstrumentationConfig Maven / Gradle / Ivy

There is a newer version: 0.9.28
Show 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.common.config;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Nullable;

import org.glowroot.agent.shaded.fasterxml.jackson.annotation.JsonIgnore;
import org.glowroot.agent.shaded.fasterxml.jackson.annotation.JsonInclude;
import org.glowroot.agent.shaded.fasterxml.jackson.annotation.JsonInclude.Include;
import org.glowroot.agent.shaded.google.common.base.Charsets;
import org.glowroot.agent.shaded.google.common.collect.ImmutableList;
import org.glowroot.agent.shaded.google.common.collect.Lists;
import org.glowroot.agent.shaded.google.common.hash.Hasher;
import org.glowroot.agent.shaded.google.common.hash.Hashing;
import org.immutables.value.Value;

@Value.Immutable
public abstract class InstrumentationConfig {

    public abstract String className();

    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String declaringClassName() {
        return "";
    }

    public abstract String methodName();

    // empty methodParameterTypes means match no-arg methods only
    public abstract ImmutableList methodParameterTypes();

    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String methodReturnType() {
        return "";
    }

    // currently unused, but will have a purpose someday, e.g. to capture all public methods
    @JsonInclude(value = Include.NON_EMPTY)
    public abstract ImmutableList methodModifiers();

    public abstract CaptureKind captureKind();

    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String transactionType() {
        return "";
    }

    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String transactionNameTemplate() {
        return "";
    }

    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String transactionUserTemplate() {
        return "";
    }

    @JsonInclude(value = Include.NON_EMPTY)
    public abstract Map transactionAttributeTemplates();

    // need to write zero since it is treated different from null
    @JsonInclude(value = Include.NON_NULL)
    public abstract @Nullable Integer transactionSlowThresholdMillis();

    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String traceEntryMessageTemplate() {
        return "";
    }

    // need to write zero since it is treated different from null
    @JsonInclude(value = Include.NON_NULL)
    public abstract @Nullable Integer traceEntryStackThresholdMillis();

    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public boolean traceEntryCaptureSelfNested() {
        return false;
    }

    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String timerName() {
        return "";
    }

    // this is only for plugin authors (to be used in glowroot.plugin.json)
    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String enabledProperty() {
        return "";
    }

    // this is only for plugin authors (to be used in glowroot.plugin.json)
    @Value.Default
    @JsonInclude(value = Include.NON_EMPTY)
    public String traceEntryEnabledProperty() {
        return "";
    }

    // this uses Guava's Hashing instead of json/md5 "cheat" like other configs, because it is used
    // by weaving, and using json/md5 would require pre-initialization tons of Jackson classes
    // see PreInitializeWeavingClassesTest.java
    @JsonIgnore
    @Value.Derived
    public String version() {
        Hasher hasher = Hashing.md5().newHasher()
                .putString(className(), Charsets.UTF_8)
                .putString(declaringClassName(), Charsets.UTF_8)
                .putString(methodName(), Charsets.UTF_8)
                .putInt(methodParameterTypes().size());
        for (String methodParameterType : methodParameterTypes()) {
            hasher.putString(methodParameterType, Charsets.UTF_8);
        }
        hasher.putString(methodReturnType(), Charsets.UTF_8);
        hasher.putInt(methodModifiers().size());
        for (MethodModifier methodModifier : methodModifiers()) {
            hasher.putString(methodModifier.name(), Charsets.UTF_8);
        }
        hasher.putString(captureKind().name(), Charsets.UTF_8);
        hasher.putString(transactionType(), Charsets.UTF_8);
        hasher.putString(transactionNameTemplate(), Charsets.UTF_8);
        hasher.putString(transactionUserTemplate(), Charsets.UTF_8);
        hasher.putInt(transactionAttributeTemplates().size());
        for (Entry entry : transactionAttributeTemplates().entrySet()) {
            hasher.putString(entry.getKey(), Charsets.UTF_8);
            hasher.putString(entry.getValue(), Charsets.UTF_8);
        }
        Integer transactionSlowThresholdMillis = transactionSlowThresholdMillis();
        if (transactionSlowThresholdMillis != null) {
            hasher.putInt(transactionSlowThresholdMillis);
        }
        hasher.putString(traceEntryMessageTemplate(), Charsets.UTF_8);
        Integer traceEntryStackThresholdMillis = traceEntryStackThresholdMillis();
        if (traceEntryStackThresholdMillis != null) {
            hasher.putInt(traceEntryStackThresholdMillis);
        }
        hasher.putBoolean(traceEntryCaptureSelfNested());
        hasher.putString(timerName(), Charsets.UTF_8);
        hasher.putString(enabledProperty(), Charsets.UTF_8);
        hasher.putString(traceEntryEnabledProperty(), Charsets.UTF_8);
        return hasher.hash().toString();
    }

    @JsonIgnore
    @Value.Derived
    public boolean isTimerOrGreater() {
        return captureKind() == CaptureKind.TIMER || captureKind() == CaptureKind.TRACE_ENTRY
                || captureKind() == CaptureKind.TRANSACTION;
    }

    @JsonIgnore
    @Value.Derived
    public boolean isTraceEntryOrGreater() {
        return captureKind() == CaptureKind.TRACE_ENTRY || captureKind() == CaptureKind.TRANSACTION;
    }

    @JsonIgnore
    @Value.Derived
    public boolean isTransaction() {
        return captureKind() == CaptureKind.TRANSACTION;
    }

    @JsonIgnore
    @Value.Derived
    public ImmutableList validationErrors() {
        List errors = Lists.newArrayList();
        if (className().isEmpty()) {
            errors.add("className is empty");
        }
        if (methodName().isEmpty()) {
            errors.add("methodName is empty");
        }
        if (isTimerOrGreater() && timerName().isEmpty()) {
            errors.add("timerName is empty");
        }
        if (captureKind() == CaptureKind.TRACE_ENTRY && traceEntryMessageTemplate().isEmpty()) {
            errors.add("traceEntryMessageTemplate is empty");
        }
        if (isTransaction() && transactionType().isEmpty()) {
            errors.add("transactionType is empty");
        }
        if (isTransaction() && transactionNameTemplate().isEmpty()) {
            errors.add("transactionNameTemplate is empty");
        }
        if (!timerName().matches("[a-zA-Z0-9 ]*")) {
            errors.add("timerName contains invalid characters: " + timerName());
        }
        return ImmutableList.copyOf(errors);
    }

    public enum MethodModifier {
        PUBLIC, STATIC, NOT_STATIC;
    }

    public enum CaptureKind {
        TRANSACTION, TRACE_ENTRY, TIMER, OTHER
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy