order
This paper mainly studies the custom statsd index prefix of springboot2
background
micrometer is introduced in springboot2. The 1.x version of spring.metrics.export.statsd.prefix has been marked as obsolete in version 2, but the corresponding configuration items are not given in version 2.
FlavorStatsdLineBuilder
micrometer-registry-statsd-1.0.1-sources.jar!/io/micrometer/statsd/internal/FlavorStatsdLineBuilder.java
/** * A Statsd serializer for a particular {@link Meter} that formats the line in different * ways depending on the prevailing {@link StatsdFlavor}. * * @author Jon Schneider */ public class FlavorStatsdLineBuilder implements StatsdLineBuilder { private final Meter.Id id; private final StatsdFlavor flavor; private final HierarchicalNameMapper nameMapper; private final MeterRegistry.Config config; private final Function<NamingConvention, String> datadogTagString; private final Function<NamingConvention, String> telegrafTagString; public FlavorStatsdLineBuilder(Meter.Id id, StatsdFlavor flavor, HierarchicalNameMapper nameMapper, MeterRegistry.Config config) { this.id = id; this.flavor = flavor; this.nameMapper = nameMapper; this.config = config; // service:payroll,region:us-west this.datadogTagString = memoize(convention -> id.getTags().iterator().hasNext() ? id.getConventionTags(convention).stream() .map(t -> t.getKey() + ":" + t.getValue()) .collect(Collectors.joining(",")) : null ); // service=payroll,region=us-west this.telegrafTagString = memoize(convention -> id.getTags().iterator().hasNext() ? id.getConventionTags(convention).stream() .map(t -> t.getKey() + "=" + t.getValue()) .collect(Collectors.joining(",")) : null ); } @Override public String count(long amount, Statistic stat) { return line(Long.toString(amount), stat, "c"); } @Override public String gauge(double amount, Statistic stat) { return line(DoubleFormat.decimalOrNan(amount), stat, "g"); } @Override public String histogram(double amount) { return line(DoubleFormat.decimalOrNan(amount), null, "h"); } @Override public String timing(double timeMs) { return line(DoubleFormat.decimalOrNan(timeMs), null, "ms"); } private String line(String amount, @Nullable Statistic stat, String type) { switch (flavor) { case ETSY: return metricName(stat) + ":" + amount + "|" + type; case DATADOG: return metricName(stat) + ":" + amount + "|" + type + tags(stat, datadogTagString.apply(config.namingConvention()),":", "|#"); case TELEGRAF: default: return metricName(stat) + tags(stat, telegrafTagString.apply(config.namingConvention()),"=", ",") + ":" + amount + "|" + type; } } private String tags(@Nullable Statistic stat, String otherTags, String keyValueSeparator, String preamble) { String tags = of(stat == null ? null : "statistic" + keyValueSeparator + stat.getTagValueRepresentation(), otherTags) .filter(Objects::nonNull) .collect(Collectors.joining(",")); if(!tags.isEmpty()) tags = preamble + tags; return tags; } private String metricName(@Nullable Statistic stat) { switch (flavor) { case ETSY: return nameMapper.toHierarchicalName(stat != null ? id.withTag(stat) : id, config.namingConvention()); case DATADOG: case TELEGRAF: default: return config.namingConvention().name(id.getName(), id.getType(), id.getBaseUnit()); } } }
You can see that the count, gauge, histogram and timing methods all call the line method, while the line method calls the metricName to construct the indicator name, while the metricName is the tohierarchalname method of the hierarchalnamemapper (the flag is ESTY)
HierarchicalNameMapper
micrometer-core-1.0.1-sources.jar!/io/micrometer/core/instrument/util/HierarchicalNameMapper.java
/** * Defines the mapping between a combination of name + dimensional tags and a hierarchical name. * * @author Jon Schneider */ public interface HierarchicalNameMapper { /** * Sort tags alphabetically by key and append tag key values to the name with '.', e.g. * {@code http_server_requests.response.200.method.GET} */ HierarchicalNameMapper DEFAULT = (id, convention) -> { String tags = ""; if (id.getTags().iterator().hasNext()) { tags = "." + id.getConventionTags(convention).stream() .map(t -> t.getKey() + "." + t.getValue()) .map(nameSegment -> nameSegment.replace(" ", "_")) .collect(Collectors.joining(".")); } return id.getConventionName(convention) + tags; }; String toHierarchicalName(Meter.Id id, NamingConvention convention); }
The hierarchalnamemapper interface defines a DEFAULT implementation, which is used by DEFAULT in StatsdMetricsExportAutoConfiguration
- StatsdMetricsExportAutoConfiguration spring-boot-actuator-autoconfigure-2.0.0.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfiguration.java
@Bean @ConditionalOnMissingBean public HierarchicalNameMapper hierarchicalNameMapper() { return HierarchicalNameMapper.DEFAULT; }
custom
By customizing a hierarchical name mapper, you can customize the prefix of the statsd indicator. The example is as follows
@Bean public HierarchicalNameMapper hierarchicalNameMapper() { return new HierarchicalNameMapper(){ @Override public String toHierarchicalName(Meter.Id id, NamingConvention convention) { String tags = ""; if (id.getTags().iterator().hasNext()) { tags = "." + id.getConventionTags(convention).stream() .map(t -> t.getKey() + "." + t.getValue()) .map(nameSegment -> nameSegment.replace(" ", "_")) .collect(Collectors.joining(".")); } return "demo." + id.getConventionName(convention) + tags; } }; }
The DEFAULT method has been modified here, and a demo has been added to the return as a prefix, so the result is complete.
Summary
At present, spring boot 2 does not directly support specifying the prefix of statsd through the configuration file, but it can be implemented by customizing the hierarchical name mapper with a little code.