package io.dropwizard.metrics; import com.codahale.metrics.MetricAttribute; import com.codahale.metrics.MetricFilter; import com.codahale.metrics.ScheduledReporter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import io.dropwizard.util.Duration; import io.dropwizard.validation.MinDuration; import org.hibernate.validator.valuehandling.UnwrapValidatedValue; import javax.validation.Valid; import javax.validation.constraints.NotNull; import java.util.EnumSet; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; /** * A base {@link ReporterFactory} for configuring metric reporters. * <p/> * Configures options common to all {@link ScheduledReporter}s. * <p/> * <b>Configuration Parameters:</b> * <table> * <tr> * <td>Name</td> * <td>Default</td> * <td>Description</td> * </tr> * <tr> * <td>durationUnit</td> * <td>milliseconds</td> * <td>The unit to report durations as. Overrides per-metric duration units.</td> * </tr> * <tr> * <td>rateUnit</td> * <td>seconds</td> * <td>The unit to report rates as. Overrides per-metric rate units.</td> * </tr> * <tr> * <td>excludes</td> * <td>No excluded metrics.</td> * <td>Metrics to exclude from reports, by name. When defined, matching metrics will not be * reported. See {@link #getFilter()}.</td> * </tr> * <tr> * <td>includes</td> * <td>All metrics included.</td> * <td>Metrics to include in reports, by name. When defined, only these metrics will be * reported. See {@link #getFilter()}. Exclusion rules (excludes) take precedence, * so if a name matches both <i>excludes</i> and <i>includes</i>, it is excluded.</td> * </tr> * <tr> * <td>excludesAttributes</td> * <td>No excluded attributes.</td> * <td>Metric attributes to exclude from reports, by name (e.g `p98`, `m15_rate`, `stddev`). * When defined, matching metrics attributes will not be reported. See {@link MetricAttribute}</td> * </tr> * <tr> * <td>includesAttributes</td> * <td>All metrics attributes.</td> * <td>Metrics attributes to include in reports, by name (e.g `p98`, `m15_rate`, `stddev`). * When defined, only these attributes will be reported. See {@link MetricAttribute}. * Exclusion rules (excludes) take precedence, so if an attribute matches both <i>includesAttributes</i> * and <i>excludesAttributes</i>, it is excluded.</td> * </tr> * <tr> * <td>useRegexFilters</td> * <td>false</td> * <td>Indicates whether the values of the 'includes' and 'excludes' fields should be * treated as regular expressions or not.</td> * </tr> * <tr> * <td>frequency</td> * <td>none</td> * <td>The frequency to report metrics. Overrides the {@link * MetricsFactory#getFrequency() default}.</td> * </tr> * </table> */ public abstract class BaseReporterFactory implements ReporterFactory { private static final DefaultStringMatchingStrategy DEFAULT_STRING_MATCHING_STRATEGY = new DefaultStringMatchingStrategy(); private static final RegexStringMatchingStrategy REGEX_STRING_MATCHING_STRATEGY = new RegexStringMatchingStrategy(); private static final SubstringMatchingStrategy SUBSTRING_MATCHING_STRATEGY = new SubstringMatchingStrategy(); @NotNull private TimeUnit durationUnit = TimeUnit.MILLISECONDS; @NotNull private TimeUnit rateUnit = TimeUnit.SECONDS; @NotNull private ImmutableSet<String> excludes = ImmutableSet.of(); @NotNull private ImmutableSet<String> includes = ImmutableSet.of(); @Valid @MinDuration(0) @UnwrapValidatedValue private Optional<Duration> frequency = Optional.empty(); private boolean useRegexFilters = false; private boolean useSubstringMatching = false; private EnumSet<MetricAttribute> excludesAttributes = EnumSet.noneOf(MetricAttribute.class); private EnumSet<MetricAttribute> includesAttributes = EnumSet.allOf(MetricAttribute.class); public TimeUnit getDurationUnit() { return durationUnit; } @JsonProperty public void setDurationUnit(TimeUnit durationUnit) { this.durationUnit = durationUnit; } @JsonProperty public TimeUnit getRateUnit() { return rateUnit; } @JsonProperty public void setRateUnit(final TimeUnit rateUnit) { this.rateUnit = rateUnit; } @JsonProperty public ImmutableSet<String> getIncludes() { return includes; } @JsonProperty public void setIncludes(ImmutableSet<String> includes) { this.includes = includes; } @JsonProperty public ImmutableSet<String> getExcludes() { return excludes; } @JsonProperty public void setExcludes(ImmutableSet<String> excludes) { this.excludes = excludes; } @Override @JsonProperty public Optional<Duration> getFrequency() { return frequency; } @JsonProperty public void setFrequency(Optional<Duration> frequency) { this.frequency = frequency; } @JsonProperty public boolean getUseRegexFilters() { return useRegexFilters; } @JsonProperty public void setUseRegexFilters(boolean useRegexFilters) { this.useRegexFilters = useRegexFilters; } @JsonProperty public boolean getUseSubstringMatching() { return useSubstringMatching; } @JsonProperty public void setUseSubstringMatching(boolean useSubstringMatching) { this.useSubstringMatching = useSubstringMatching; } @JsonProperty public EnumSet<MetricAttribute> getExcludesAttributes() { return excludesAttributes; } @JsonProperty public void setExcludesAttributes(EnumSet<MetricAttribute> excludesAttributes) { this.excludesAttributes = excludesAttributes; } @JsonProperty public EnumSet<MetricAttribute> getIncludesAttributes() { return includesAttributes; } @JsonProperty public void setIncludesAttributes(EnumSet<MetricAttribute> includesAttributes) { this.includesAttributes = includesAttributes; } /** * Gets a {@link MetricFilter} that specifically includes and excludes configured metrics. * <p/> * Filtering works in 4 ways: * <dl> * <dt><i>unfiltered</i></dt> * <dd>All metrics are reported</dd> * <dt><i>excludes</i>-only</dt> * <dd>All metrics are reported, except those whose name is listed in <i>excludes</i>.</dd> * <dt><i>includes</i>-only</dt> * <dd>Only metrics whose name is listed in <i>includes</i> are reported.</dd> * <dt>mixed (both <i>includes</i> and <i>excludes</i></dt> * <dd>Only metrics whose name is listed in <i>includes</i> and * <em>not</em> listed in <i>excludes</i> are reported; * <i>excludes</i> takes precedence over <i>includes</i>.</dd> * </dl> * * @return the filter for selecting metrics based on the configured excludes/includes. * @see #getIncludes() * @see #getExcludes() */ @JsonIgnore public MetricFilter getFilter() { final StringMatchingStrategy stringMatchingStrategy = getUseRegexFilters() ? REGEX_STRING_MATCHING_STRATEGY : (getUseSubstringMatching() ? SUBSTRING_MATCHING_STRATEGY : DEFAULT_STRING_MATCHING_STRATEGY); return (name, metric) -> { // Include the metric if its name is not excluded and its name is included // Where, by default, with no includes setting, all names are included. return !stringMatchingStrategy.containsMatch(getExcludes(), name) && (getIncludes().isEmpty() || stringMatchingStrategy.containsMatch(getIncludes(), name)); }; } protected Set<MetricAttribute> getDisabledAttributes() { return ImmutableSet.copyOf(Sets.union( Sets.difference(EnumSet.allOf(MetricAttribute.class), getIncludesAttributes()), getExcludesAttributes())); } }