Spring Boot Actuator, Micrometer e Prometheus

O Actuator é muito bom pra se a sua aplicação esta “UP” ou “DOWN”, mas pra monitorar mesmo, saber o consumo e fazer analise de capacidade de performance, você vai precisar colocar alguma coisa a mais, e é a ai que entra o Micrometer e o Prometheus.

Antes de prosseguir, tenha certeza que esta com o Actuator rodando, ele é um pré-requisito. Aqui temos um post falando sobre ele.

http://3.139.95.241/2021/05/04/spring-boot-actuator-o-que-e-como-melhorar/

Seguindo com o conteúdo deste post.

O que é o Micrometer?

Link oficial: https://micrometer.io/

Como eles dizem: “O Micrometer fornece uma fachada simples sobre os clientes de instrumentação para os sistemas de monitoramento mais populares, permitindo que você instrumentalize seu código de aplicativo baseado em JVM sem dependência de fornecedor. Pense SLF4J, mas para métricas.”

Resumindo: Desta forma, não importa qual é o seu servidor de métricas, você precisa codificar somente uma vez.

Nesse post, não vamos falar de métricas customizada ou próprias, vamos falar somente de exportas as que o Java já tem.

O Que é o Prometheus?

Link oficial: https://prometheus.io/

Como eles dizem: “O Prometheus é um kit de ferramentas de monitoramento e alerta de sistemas de código aberto … é um projeto autônomo de código aberto e mantido independentemente de qualquer empresa. …”

Resumindo: É a ferramenta de monitoração que você vai armazenar as suas coletas.

Porque Prometheus?

Um dia, vou escrever melhor sobre isso, mas em resumo. Prometheus tem muitos plugins de auto discovery o que permite “encontrar” as aplicações a serem monitoradas.

Desta forma, não precisa de ter alguém (“pessoinha”) para ficar criando “coleta” pra cada nova aplicação.

Como habilitar?

Seguimos a documentação https://micrometer.io/docs/registry/prometheus

Projetos Maven no pom.xml colocar a dependência:

<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Pra saber a versão corrente e mudar na properties: https://mvnrepository.com/artifact/io.micrometer/micrometer-registry-prometheus

Projetos Gradle, no build.gradle colocar a dependência:

dependencies {
  implementation 'io.micrometer:micrometer-registry-prometheus'
}

Pronto, se fizer isso, já tem as métricas sendo exportadas.

Testando as métricas do prometheus

Para saber as métricas expostas basta acessar o contexto /actuator/prometheus da sua aplicação

Pronto, feito isso, suas aplicações já estão compatíveis com exportarem informações ao Prometheus.

Se estiver usando Kubernetes, é importante cria essa classe de configuração do Spring Boot para diferenciar os dados por POD e aplicações.

package br.tec.escovabit.apphpa.configuration;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter;

@Configuration
public class MicrometerConfiguration {

    private static final String UNKNOW = "unknow";
    private static final List<String> NON_APPLICATION_ENDPOINTS = Arrays.asList("/swagger", "/**", "/v2/api-docs",
            "/webjars");
    private static final Logger LOGGER = Logger.getLogger(MicrometerConfiguration.class.getName());
    private static final String TAG_URI = "uri";

    @Bean
    public static MeterRegistryCustomizer<MeterRegistry> metricsCommonTags(
            @Value("${spring.application.name}") String applicationName) {

        return registry -> registry.config()
                .commonTags("host", getHostName(), "instance", getHostName(), "ip", getHostAddress(), "application",
                        applicationName)
                .meterFilter(denyFrameworkURIsFilter());
    }

    private static MeterFilter denyFrameworkURIsFilter() {
        return MeterFilter.deny(id -> isNonApplicationEndpoint(id.getTag(TAG_URI)));
    }

    private static boolean isNonApplicationEndpoint(String uri) {
        return uri != null
                && NON_APPLICATION_ENDPOINTS.stream().map(uri::startsWith).filter(i -> i).findFirst().orElse(false);
    }

    private static String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            LOGGER.log(Level.INFO, e.getMessage(), e);
            return UNKNOW;
        }
    }

    private static String getHostAddress() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            LOGGER.log(Level.INFO, e.getMessage(), e);
            return UNKNOW;
        }
    }
}

Nos vemos nos próximos posts.