Можно ли определить дополнительные теги для метрик Spring Boot 2 по умолчанию?
Недавно я перешел на Spring Boot 2
с 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;
}
}
Проблема в том, что мои метрики ведут себя правильно, и даже некоторые из метрик загрузки (по крайней мере, http.server.requests
) увидеть мои теги. Но jvm.*
, system.*
, tomcat.*
и многие другие до сих пор не имеют необходимых тегов.
4 ответа
Если вы ищете поддержку общих тегов, вы можете сделать это, зарегистрировав 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
подход, если нет никаких оснований придерживаться подхода.
2-е ОБНОВЛЕНИЕ:
Я посмотрел в подход и смог воспроизвести его с этой веткой.
Слишком поздно применять общие теги в @PostConstruct
так как некоторые показатели уже зарегистрированы. Причина по которой http.server.requests
работает то, что он будет зарегистрирован с первым запросом. Попробуйте поставить точку останова на точке применения фильтров, если вы заинтересованы в этом.
Вкратце, попробуйте описанный выше подход, который похож на готовую поддержку Spring Boot.
Для сервера:
(т.е.
@RestController
)
Чтобы добавить пользовательские теги метрик для приложения reactive-spring-boot в дополнение к тегам по умолчанию, предоставляемым платформой spring-boot.
предоставить один или несколько
@Beans
которые реализуют
WebFluxTagsContributor
ИЛИ
Чтобы заменить теги по умолчанию, укажите, что
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.percentile
или же
http.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"
вместе с существующими тегами по умолчанию.
Для клиента:
чтобы настроить теги, и в зависимости от вашего выбора клиента, вы можете предоставить
@Bean
который
implements RestTemplateExchangeTagsProvider
или же
WebClientExchangeTagsProvider
.
Есть удобные статические функции в
RestTemplateExchangeTags
и
WebClientExchangeTags
.
Ссылка:
Если вы используете spring-boot-actator и вам нужно добавить динамические теги к метрикам по умолчанию, просто определите be an-компонент WebMvcTagsProvider:
реализация WebMvcTagsProvider по умолчанию.
@author Джон Шнайдер
@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));
}
}
В ответ на комментарий под моим первоначальным вопросом, вот небольшой пример добавления пользовательских метрик:
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();
}
}