本文主要研究下springboot2自定義statsd指標前綴java
springboot2引入了micrometer,1.x版本的spring.metrics.export.statsd.prefix在2版本中已經被標記爲廢棄,可是2版本沒有給出對應的配置項。git
micrometer-registry-statsd-1.0.1-sources.jar!/io/micrometer/statsd/internal/FlavorStatsdLineBuilder.javagithub
/** * 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()); } } }
能夠看到count、gauge、histogram、timing方法內部都調用了line方法,而line方法調用metricName來構造指標名稱,而metricName則是調用HierarchicalNameMapper的toHierarchicalName方法(
flavor爲ESTY
)
micrometer-core-1.0.1-sources.jar!/io/micrometer/core/instrument/util/HierarchicalNameMapper.javaspring
/** * 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); }
HierarchicalNameMapper接口定義了一個DEFAULT實現,而在StatsdMetricsExportAutoConfiguration則是默認使用這個DEFAULT實現
spring-boot-actuator-autoconfigure-2.0.0.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/metrics/export/statsd/StatsdMetricsExportAutoConfiguration.javaspringboot
@Bean @ConditionalOnMissingBean public HierarchicalNameMapper hierarchicalNameMapper() { return HierarchicalNameMapper.DEFAULT; }
經過自定義個HierarchicalNameMapper,就能夠自定義statsd指標的prefix,實例以下app
@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; } }; }
這裏修改了DEFAULT方法,在return那裏添加了一個demo做爲prefix,這樣就大功告成了。
springboot2目前雖然沒有經過配置文件直接支持指定statsd的prefix,可是能夠經過少量代碼自定義HierarchicalNameMapper來實現。ide