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

io.micrometer.core.instrument.config.MeterFilter Maven / Gradle / Ivy

There is a newer version: 1.13.0
Show newest version
/**
 * Copyright 2017 VMware, Inc.
 * 

* 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 *

* https://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 io.micrometer.core.instrument.config; import io.micrometer.core.instrument.*; import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; import io.micrometer.core.lang.Nullable; import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; import static java.util.stream.Collectors.toList; import static java.util.stream.StreamSupport.stream; /** * As requests are made of a {@link MeterRegistry} to create new metrics, allow for filtering out * the metric altogether, transforming its ID (name or tags) in some way, and transforming its * configuration. *

* All new metrics should pass through each {@link MeterFilter} in the order in which they were added. * * @author Jon Schneider * @author Clint Checketts * @author Johnny Lim */ public interface MeterFilter { /** * Add common tags that are applied to every meter created afterward. * * The common tags will not override tag values from a meter ID. They will also not override previously configured * common tag MeterFilters that have the same tag key. * * @param tags Common tags. * @return A common tag filter. */ static MeterFilter commonTags(Iterable tags) { return new MeterFilter() { @Override public Meter.Id map(Meter.Id id) { return id.replaceTags(Tags.concat(tags, id.getTagsAsIterable())); } }; } /** * Rename a tag key for every metric beginning with a given prefix. * * @param meterNamePrefix Apply filter to metrics that begin with this name. * @param fromTagKey Rename tags matching this key. * @param toTagKey Rename to this key. * @return A tag-renaming filter. */ static MeterFilter renameTag(String meterNamePrefix, String fromTagKey, String toTagKey) { return new MeterFilter() { @Override public Meter.Id map(Meter.Id id) { if (!id.getName().startsWith(meterNamePrefix)) return id; List tags = new ArrayList<>(); for (Tag tag : id.getTagsAsIterable()) { if (tag.getKey().equals(fromTagKey)) tags.add(Tag.of(toTagKey, tag.getValue())); else tags.add(tag); } return id.replaceTags(tags); } }; } /** * Suppress tags with given tag keys. * * @param tagKeys Keys of tags that should be suppressed. * @return A tag-suppressing filter. */ static MeterFilter ignoreTags(String... tagKeys) { return new MeterFilter() { @Override public Meter.Id map(Meter.Id id) { List tags = stream(id.getTagsAsIterable().spliterator(), false) .filter(t -> { for (String tagKey : tagKeys) { if (t.getKey().equals(tagKey)) return false; } return true; }).collect(toList()); return id.replaceTags(tags); } }; } /** * Replace tag values according to the provided mapping for all matching tag keys. This can be used * to reduce the total cardinality of a tag by mapping some portion of tag values to something else. * * @param tagKey The tag key for which replacements should be made * @param replacement The value to replace with * @param exceptions All matching tags with this value to retain its original value * @return A filter that replaces tag values. */ static MeterFilter replaceTagValues(String tagKey, Function replacement, String... exceptions) { return new MeterFilter() { @Override public Meter.Id map(Meter.Id id) { List tags = stream(id.getTagsAsIterable().spliterator(), false) .map(t -> { if (!t.getKey().equals(tagKey)) return t; for (String exception : exceptions) { if (t.getValue().equals(exception)) return t; } return Tag.of(tagKey, replacement.apply(t.getValue())); }) .collect(toList()); return id.replaceTags(tags); } }; } /** * Can be used to build a whitelist of metrics matching certain criteria. Opposite of {@link #deny(Predicate)}. * * @param iff When a meter id matches, allow its inclusion, otherwise deny. * @return A meter filter that whitelists metrics matching a predicate. */ static MeterFilter denyUnless(Predicate iff) { return new MeterFilter() { @Override public MeterFilterReply accept(Meter.Id id) { return iff.test(id) ? MeterFilterReply.NEUTRAL : MeterFilterReply.DENY; } }; } /** * When the given predicate is {@code true}, the meter should be present in published metrics. * * @param iff When a meter id matches, guarantee its inclusion in published metrics. * @return A filter that guarantees the inclusion of matching meters. */ static MeterFilter accept(Predicate iff) { return new MeterFilter() { @Override public MeterFilterReply accept(Meter.Id id) { return iff.test(id) ? MeterFilterReply.ACCEPT : MeterFilterReply.NEUTRAL; } }; } /** * When the given predicate is {@code true}, the meter should NOT be present in published metrics. * Opposite of {@link #denyUnless(Predicate)}. * * @param iff When a meter id matches, guarantee its exclusion in published metrics. * @return A filter that guarantees the exclusion of matching meters. */ static MeterFilter deny(Predicate iff) { return new MeterFilter() { @Override public MeterFilterReply accept(Meter.Id id) { return iff.test(id) ? MeterFilterReply.DENY : MeterFilterReply.NEUTRAL; } }; } /** * Include a meter in published metrics. Can be used as a subordinate action on another filter like * {@link #maximumAllowableTags}. * * @return A filter that guarantees the inclusion of all meters. */ static MeterFilter accept() { return MeterFilter.accept(id -> true); } /** * Reject a meter in published metrics. Can be used as a subordinate action on another filter like * {@link #maximumAllowableTags}. * * @return A filter that guarantees the exclusion of all meters. */ static MeterFilter deny() { return MeterFilter.deny(id -> true); } /** * Useful for cost-control in monitoring systems which charge directly or indirectly by the * total number of time series you generate. *

* While this filter doesn't discriminate between your most critical and less useful metrics in * deciding what to drop (all the metrics you intend to use should fit below this threshold), * it can effectively cap your risk of an accidentally high-cardinality metric costing too much. * * @param maximumTimeSeries The total number of unique name/tag permutations allowed before filtering kicks in. * @return A filter that globally limits the number of unique name and tag combinations. */ static MeterFilter maximumAllowableMetrics(int maximumTimeSeries) { return new MeterFilter() { private final Set ids = ConcurrentHashMap.newKeySet(); @Override public MeterFilterReply accept(Meter.Id id) { if (ids.size() > maximumTimeSeries) return MeterFilterReply.DENY; ids.add(id); return ids.size() > maximumTimeSeries ? MeterFilterReply.DENY : MeterFilterReply.NEUTRAL; } }; } /** * Places an upper bound on the number of tags produced by matching metrics. * * @param meterNamePrefix Apply filter to metrics that begin with this name. * @param tagKey The tag to place an upper bound on. * @param maximumTagValues The total number of tag values that are allowable. * @param onMaxReached After the maximum number of tag values have been seen, apply this filter. * @return A meter filter that limits the number of tags produced by matching metrics. */ static MeterFilter maximumAllowableTags(String meterNamePrefix, String tagKey, int maximumTagValues, MeterFilter onMaxReached) { return new MeterFilter() { private final Set observedTagValues = ConcurrentHashMap.newKeySet(); @Override public MeterFilterReply accept(Meter.Id id) { String value = matchNameAndGetTagValue(id); if (value != null) { if (!observedTagValues.contains(value)) { if (observedTagValues.size() >= maximumTagValues) { return onMaxReached.accept(id); } observedTagValues.add(value); } } return MeterFilterReply.NEUTRAL; } @Nullable private String matchNameAndGetTagValue(Meter.Id id) { return id.getName().startsWith(meterNamePrefix) ? id.getTag(tagKey) : null; } @Override public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { String value = matchNameAndGetTagValue(id); if (value != null) { if (!observedTagValues.contains(value)) { if (observedTagValues.size() >= maximumTagValues) { return onMaxReached.configure(id, config); } } } return config; } }; } /** * Meters that start with the provided name prefix should NOT be present in published metrics. * * @param prefix When a meter name starts with the prefix, guarantee its exclusion in published metrics. * @return A filter that guarantees the exclusion of matching meters. */ static MeterFilter denyNameStartsWith(String prefix) { return deny(id -> id.getName().startsWith(prefix)); } /** * Meters that start with the provided name should be present in published metrics. * * @param prefix When a meter name starts with the prefix, guarantee its inclusion in published metrics. * @return A filter that guarantees the inclusion of matching meters. * @since 1.2.0 */ static MeterFilter acceptNameStartsWith(String prefix) { return accept(id -> id.getName().startsWith(prefix)); } /** * Set a maximum expected value on any {@link Timer} whose name begins with the given prefix. * * @param prefix Apply the maximum only to timers whose name begins with this prefix. * @param max The maximum expected value of the timer. * @return A filter that applies a maximum expected value to a timer. */ static MeterFilter maxExpected(String prefix, Duration max) { return new MeterFilter() { @Override public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { if (id.getType() == Meter.Type.TIMER && id.getName().startsWith(prefix)) { return DistributionStatisticConfig.builder() .maximumExpectedValue((double) max.toNanos()) .build() .merge(config); } return config; } }; } /** * Set a maximum expected value on any {@link DistributionSummary} whose name begins with the given prefix. * * @deprecated Use {@link #maxExpected(String, double)} instead since 1.4.0. * @param prefix Apply the maximum only to distribution summaries whose name begins with this prefix. * @param max The maximum expected value of the distribution summary. * @return A filter that applies a maximum expected value to a distribution summary. */ @Deprecated static MeterFilter maxExpected(String prefix, long max) { return maxExpected(prefix, (double) max); } /** * Set a maximum expected value on any {@link DistributionSummary} whose name begins with the given prefix. * * @param prefix Apply the maximum only to distribution summaries whose name begins with this prefix. * @param max The maximum expected value of the distribution summary. * @return A filter that applies a maximum expected value to a distribution summary. * @since 1.4.0 */ static MeterFilter maxExpected(String prefix, double max) { return new MeterFilter() { @Override public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { if (id.getType() == Meter.Type.DISTRIBUTION_SUMMARY && id.getName().startsWith(prefix)) { return DistributionStatisticConfig.builder() .maximumExpectedValue(max) .build() .merge(config); } return config; } }; } /** * Set a minimum expected value on any {@link Timer} whose name begins with the given prefix. * * @param prefix Apply the minimum only to timers whose name begins with this prefix. * @param min The minimum expected value of the timer. * @return A filter that applies a minimum expected value to a timer. */ static MeterFilter minExpected(String prefix, Duration min) { return new MeterFilter() { @Override public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { if (id.getType() == Meter.Type.TIMER && id.getName().startsWith(prefix)) { return DistributionStatisticConfig.builder() .minimumExpectedValue((double) min.toNanos()) .build() .merge(config); } return config; } }; } /** * Set a minimum expected value on any {@link DistributionSummary} whose name begins with the given prefix. * * @deprecated Use {@link #minExpected(String, double)} instead since 1.4.0. * @param prefix Apply the minimum only to distribution summaries whose name begins with this prefix. * @param min The minimum expected value of the distribution summary. * @return A filter that applies a minimum expected value to a distribution summary. */ @Deprecated static MeterFilter minExpected(String prefix, long min) { return minExpected(prefix, (double) min); } /** * Set a minimum expected value on any {@link DistributionSummary} whose name begins with the given prefix. * * @param prefix Apply the minimum only to distribution summaries whose name begins with this prefix. * @param min The minimum expected value of the distribution summary. * @return A filter that applies a minimum expected value to a distribution summary. * @since 1.4.0 */ static MeterFilter minExpected(String prefix, double min) { return new MeterFilter() { @Override public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { if (id.getType() == Meter.Type.DISTRIBUTION_SUMMARY && id.getName().startsWith(prefix)) { return DistributionStatisticConfig.builder() .minimumExpectedValue(min) .build() .merge(config); } return config; } }; } /** * @param id Id with {@link MeterFilter#map} transformations applied. * @return After all transformations, should a real meter be registered for this id, or should it be no-op'd. */ default MeterFilterReply accept(Meter.Id id) { return MeterFilterReply.NEUTRAL; } /** * @param id Id to transform. * @return Transformations to any part of the id. */ default Meter.Id map(Meter.Id id) { return id; } /** * This is only called when filtering new timers and distribution summaries (i.e. those meter types * that use {@link DistributionStatisticConfig}). * * @param id Id with {@link MeterFilter#map} transformations applied. * @param config A histogram configuration guaranteed to be non-null. * @return Overrides to any part of the histogram config, when applicable. */ @Nullable default DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { return config; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy