6

最近我切换到Spring Boot 2with Micrometer。当我得到这些闪亮的新指标时,我与我们的 DevOps 人员进行了交谈,我们开始将它们导出到Telegraf.

为了区分不同的应用程序和应用程序节点,我们决定使用标签。这对于自定义指标非常有效,但现在我开始考虑预定义的指标。为了对默认指标实现相同的效果,我还需要能够为它们添加额外的标签。

有可能实现这一目标吗?我这样做对吗?

编辑:我尝试了下一种方法:

@Component
public class MyMetricsImpl implements MyMetrics {

    @Autowired
    protected MyProperties myProperties;
    @Autowired
    protected MeterRegistry meterRegistry;

    @PostConstruct
    public void initialize() {
        this.meterRegistry.config()
                .commonTags(commonTags());
    }

    @Override
    public List<Tag> commonTags() {
        List<Tag> tags = new ArrayList<>();
        tags.add(Tag.of("application", myProperties.getApplicationName()));
        tags.add(Tag.of("node", myProperties.getNodeName()));
        return tags;
    }
}

问题是我的指标表现正确,甚至一些 Boot 的指标(至少http.server.requests)看到我的标签。但是jvm.*,system.*tomcat.*许多其他人仍然没有所需的标签。

4

4 回答 4

5

对于服务器:(
@RestController
除了 spring-boot 框架提供的默认标签之外,为响应式spring-boot 应用程序添加自定义指标标签。
提供一个或多个@Beans实现WebFluxTagsContributor
OR
要替换默认标签,请提供一个@Beanthat implements WebFluxTagsProvider。用作答案之一的
参考实现。参考:Spring-WebMVC

以下实施是常规的。

import io.micrometer.core.instrument.Tag
import org.springframework.boot.actuate.metrics.web.reactive.server.WebFluxTagsContributor
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange

@Component
class CustomWebClientExchangeTagsProvider implements WebFluxTagsContributor {

    final KEY = "key"

    /**
     * Provides tags to be associated with metrics for the given {@code exchange}.
     * @param exchange the exchange
     * @param ex the current exception (maybe {@code null})
     * @return tags to associate with metrics for the request and response exchange
     */
    @Override
    Iterable<Tag> httpRequestTags(ServerWebExchange exchange, Throwable ex) {
        String apiKey = exchange.request.queryParams[KEY] ?: "default_api_key"
        HttpStatus status = exchange.response.statusCode ?: HttpStatus.INTERNAL_SERVER_ERROR
        HttpMethod method = exchange.request.method ?: HttpMethod.OPTIONS
        String group = (status.value() >= 500 ? "5XX" : (status.value() >= 400) ? "4XX" : (status.value() >= 300) ? "3XX" : "NONE")

        Tag statusTag = Tag.of("status", status.value().toString())
        Tag methodTag = Tag.of("method", method.toString())
        Tag apiKeyTag = Tag.of(KEY, apiKey)
        Tag groupTag = Tag.of("group", group)

        return Arrays.asList(statusTag, methodTag, apiKeyTag, groupTag)
    }
}

指标标签:

验证客户端:公制http.client.requests.percentilehttp.client.requests.

http://localhost:8010/metrics/http.client.requests

验证服务器:

http://localhost:8010/metrics/http.server.requests

同样,将为http.server.requests.percentile指标添加标签

{
    "name": "http.server.requests",
    "description": null,
    "base_unit": "milliseconds",
    "measurements": [
        {
            "statistic": "COUNT",
            "value": 17.0
        },
        {
            "statistic": "TOTAL_TIME",
            "value": 8832.186054
        },
        {
            "statistic": "MAX",
            "value": 6.514132
        }
    ],
    "available_tags": [
        {
            "tag": "exception",
            "values": [
                "None",
                "ResponseStatusException"
            ]
        },
        {
            "tag": "method",
            "values": [
                "GET"
            ]
        },
        {
            "tag": "application",
            "values": [
                "myapplication"
            ]
        },
        {
            "tag": "uri",
            "values": [
                "/myapplication/v1/abcd",
                "/manage/metrics/{requiredMetricName}",
                "/manage",
                "/manage/metrics",
                "/myapplication/v1/windows",
                "/**"
            ]
        },
        {
            "tag": "outcome",
            "values": [
                "CLIENT_ERROR",
                "SERVER_ERROR",
                "SUCCESS"
            ]
        },
        {
            "tag": "key",
            "values": [
                "default_api_key",
                "[abcd]"
            ]
        },
        {
            "tag": "status",
            "values": [
                "404",
                "200",
                "502"
            ]
        },
        {
            "tag": "group",
            "values": [
                "4XX",
                "NONE",
                "5XX"
            ]
        }
    ]
}

或者

如果您正在使用prometheus
,您可以验证自定义标签如下

http://localhost:8010/prometheus

客户:

http_client_requests_seconds_count{application="myapplication",clientName="myhostname.com",method="POST",outcome="CLIENT_ERROR",status="403",uri="/urlIamTryingToHit/v1/list",} 1.0

没有为客户端添加,因此没有自定义标签,只有 spring-boot 提供的现有标签。

服务器:

http_server_requests_seconds_sum{application="myapplication",exception="None",group="4XX",key="default_api_key",method="GET",outcome="CLIENT_ERROR",status="404",uri="/manage/metrics/{requiredMetricName}",} 0.004154207

我们可以观察group="4XX", key="default_api_key", method="GET",status="404"以及现有的默认标签。


对于客户端:
要自定义标签,根据您选择的客户端,您可以提供@Beanthatimplements RestTemplateExchangeTagsProviderWebClientExchangeTagsProvider. 和
中有方便的静态函数。参考:RestTemplateExchangeTagsWebClientExchangeTags

于 2021-03-24T12:06:13.780 回答
5

如果您正在寻找通用标签支持,您可以通过注册MeterFilter来实现它。

有关示例,请参见此提交此分支。

即将推出的 Spring Boot 2.1.0.M1中,您可以使用以下属性:

management.metrics.tags.*= # Common tags that are applied to every meter.

有关详细信息,请参阅参考


更新:

随着问题的更新,我使用这种MeterFilter基于方法的方法检查了更新的问题,并确认它的工作方式如下:

要求:http://localhost:8080/actuator/metrics/jvm.gc.memory.allocated

回复:

{
  "name" : "jvm.gc.memory.allocated",
  "measurements" : [ {
    "statistic" : "COUNT",
    "value" : 1.98180864E8
  } ],
  "availableTags" : [ {
    "tag" : "stack",
    "values" : [ "prod" ]
  }, {
    "tag" : "region",
    "values" : [ "us-east-1" ]
  } ]
}

我没有检查更新问题中提供的方法,但MeterFilter除非有任何理由坚持使用该方法,否则我只会使用基于验证的方法。


第二次更新:

我研究了这种方法,并能够用这个分支重现它。

@PostConstruct由于一些指标已经注册,因此应用通用标签为时已晚。起作用的原因http.server.requests是它将在第一个请求中注册。如果您对它感兴趣,请尝试在过滤器的应用程序点上放置一个断点。

简而言之,尝试上述方法,它类似于即将推出的 Spring Boot 开箱即用支持。

于 2018-07-27T12:34:51.233 回答
1

如果您使用 spring-boot-actuator 并且需要将动态标签添加到默认指标,只需定义一个 WebMvcTagsProvider bean:WebMvcTagsProvider
的默认实现。
@作者乔恩·施耐德
@since 2.0.0

public class DefaultWebMvcTagsProvider implements WebMvcTagsProvider {

@Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler,
        Throwable exception) {
    return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response), WebMvcTags.exception(exception),
            WebMvcTags.status(response), WebMvcTags.outcome(response));
}

@Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
    return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, null));
}

}

于 2020-05-08T12:19:23.003 回答
0

为了回应我原来的问题下的评论,这里是添加自定义指标的一个小例子:

package io.github.stepio.examples.metrics;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class MyImportantComponent {

    protected static final String CONNECTIONS_CURRENT = "connections.created";
    protected static final String CONNECTIONS_IDLE = "connections.idle";
    protected static final String CONNECTIONS_MAX = "connections.max";

    protected static final String PREFIX_REQUESTS_FOR_SERVICE = "requests";

    protected static final String SERVICE = "service";

    protected AtomicInteger connectionMax = new AtomicInteger();

    @Autowired
    protected MeterRegistry meterRegistry;

    @Override
    public List<Tag> tags() {
        return new ArrayList<>();
    }

    @Override
    public void trackConnectorsCurrent(AtomicInteger counter) {
        this.meterRegistry.gauge(CONNECTIONS_CURRENT, tags(), counter);
    }

    @Override
    public void trackConnectorsIdle(Collection<?> collection) {
        this.meterRegistry.gaugeCollectionSize(CONNECTIONS_IDLE, tags(), collection);
    }

    @Override
    public void submitConnectorsMax(final int value) {
        this.meterRegistry.gauge(CONNECTIONS_MAX, tags(), this.connectionMax).set(value);
    }

    @Override
    public void incrementRequestsForService(String serviceName) {
        this.meterRegistry.counter(PREFIX_REQUESTS_FOR_SERVICE, tags(SERVICE, serviceName)).increment();
    }

}
于 2019-01-27T17:41:18.367 回答