Atuador de inicialização por mola

Atuador de inicialização por mola

1. Visão geral

Neste artigo, vamos apresentar o Spring Boot Actuator. We’ll cover the basics first, then discuss in detail what’s available in Spring Boot 1.x vs 2.x.

Aprenderemos como usar, configurar e estender essa ferramenta de monitoramento no Spring Boot 1.x. Em seguida, discutiremos como fazer o mesmo usando Boot 2.xe WebFlux aproveitando o modelo de programação reativa.

O Spring Boot Actuator está disponível desde abril de 2014, juntamente com o primeiro lançamento do Spring Boot.

Com orelease of Spring Boot 2, o Atuador foi reprojetado e novos pontos de extremidade interessantes foram adicionados.

Este guia está dividido em 3 seções principais:

Leitura adicional:

Configurar um aplicativo Web de inicialização Spring

Algumas das configurações mais úteis para um aplicativo Spring Boot.

Read more

Criando um Starter personalizado com Spring Boot

Um guia rápido e prático para criar iniciantes personalizados do Spring Boot.

Read more

Testando no Spring Boot

Aprenda como o Spring Boot suporta testes, para escrever testes de unidade com eficiência.

Read more

2. O que é um atuador?

Em essência, o Atuador traz recursos prontos para produção em nossa aplicação.

Monitorar nosso aplicativo, reunir métricas, entender o tráfego ou o estado de nosso banco de dados torna-se trivial com essa dependência.

O principal benefício desta biblioteca é que podemos obter ferramentas de nível de produção sem precisar implementar esses recursos.

O atuador é usado principalmente paraexpose operational information about the running application - saúde, métricas, informações, despejo, env, etc. Ele usa pontos de extremidade HTTP ou beans JMX para nos permitir interagir com ele.

Uma vez que essa dependência está no caminho de classe, vários pontos de extremidade estão disponíveis para nós imediatamente. Como na maioria dos módulos Spring, podemos configurá-lo ou ampliá-lo facilmente de várias maneiras.

2.1. Começando

Para habilitar o Spring Boot Actuator, só precisamos adicionar a dependênciaspring-boot-actuator ao nosso gerenciador de pacotes. No Maven:


    org.springframework.boot
    spring-boot-starter-actuator

Observe que isso permanece válido, independentemente da versão de inicialização, pois as versões são especificadas na Lista de materiais (BOM) do Spring Boot.

3. Atuador Spring Boot 1.x

No Atuador 1.x, segue um modelo R / W, o que significa que podemos ler ou escrever nele. E.g. podemos recuperar métricas ou a saúde de nosso aplicativo. Como alternativa, poderíamos encerrar nosso aplicativo normalmente ou alterar nossa configuração de log.

Para fazê-lo funcionar, o Actuator exige que o Spring MVC exponha seus pontos de extremidade por meio de HTTP. Nenhuma outra tecnologia é suportada.

3.1. Pontos finais

No 1.x, o Atuador traz seu próprio modelo de segurança. Ele aproveita as construções do Spring Security, mas precisa ser configurado independentemente do resto do aplicativo.

Além disso, a maioria dos terminais são confidenciais - o que significa que não são totalmente públicos, ou em outras palavras, a maioria das informações será omitida - enquanto alguns não são, por exemplo, /info.

Aqui estão alguns dos pontos de extremidade mais comuns que o Boot fornece imediatamente:

  • /health - Mostra informações de saúde do aplicativo (um‘status' simples quando acessado por uma conexão não autenticada ou detalhes completos da mensagem quando autenticado); não é sensível por padrão

  • /info – Exibe informações arbitrárias do aplicativo; não sensível por padrão

  • /metrics – Mostra informações de 'métricas' para o aplicativo atual; também é sensível por padrão

  • /trace – Exibe informações de rastreamento (por padrão, as últimas solicitações HTTP)

Podemos encontrar a lista completa de endpoints existentes emon the official docs.

3.2. Configurando Endpoints Existentes

Cada terminal pode ser personalizado com propriedades usando o seguinte formato:endpoints.[endpoint name].[property to customize]

Três propriedades estão disponíveis:

  • id – pelo qual este endpoint será acessado via HTTP

  • enabled - se verdadeiro, pode ser acessado de outra forma não

  • sensitive - se verdadeiro, então precisa de autorização para mostrar informações cruciais sobre HTTP

Por exemplo, adicionar as seguintes propriedades personalizará o endpoint /beans:

endpoints.beans.id=springbeans
endpoints.beans.sensitive=false
endpoints.beans.enabled=true

3.3. /health Endpoint

The /health endpoint is used to check the health or state of the running application. Geralmente é exercido pelo software de monitoramento para nos alertar se a instância em execução cair ou não estiver íntegra por outros motivos. E.g. Problemas de conectividade com nosso banco de dados, falta de espaço em disco ...

Por padrão, apenas as informações de integridade são mostradas para acesso não autorizado por HTTP:

{
    "status" : "UP"
}

Essas informações de saúde são coletadas de todos os beans que implementam a interfaceHealthIndicator configurada em nosso contexto de aplicativo.

Algumas informações retornadas porHealthIndicator são confidenciais por natureza - mas podemos configurarendpoints.health.sensitive=false para expor informações mais detalhadas, como espaço em disco, conectividade do agente de mensagens, verificações personalizadas, etc.

Também poderíamosimplement our own custom health indicator - que pode coletar qualquer tipo de dados de saúde personalizados específicos para o aplicativo e expô-los automaticamente por meio do endpoint/health:

@Component
public class HealthCheck implements HealthIndicator {

    @Override
    public Health health() {
        int errorCode = check(); // perform some specific health check
        if (errorCode != 0) {
            return Health.down()
              .withDetail("Error Code", errorCode).build();
        }
        return Health.up().build();
    }

    public int check() {
        // Our logic to check health
        return 0;
    }
}

Veja como a saída ficaria:

{
    "status" : "DOWN",
    "myHealthCheck" : {
        "status" : "DOWN",
        "Error Code" : 1
     },
     "diskSpace" : {
         "status" : "UP",
         "free" : 209047318528,
         "threshold" : 10485760
     }
}

3.4. /info Endpoint

Também podemos personalizar os dados mostrados pelo endpoint/info - por exemplo:

info.app.name=Spring Sample Application
info.app.description=This is my first spring boot application
info.app.version=1.0.0

E a saída da amostra:

{
    "app" : {
        "version" : "1.0.0",
        "description" : "This is my first spring boot application",
        "name" : "Spring Sample Application"
    }
}

3.5. /metrics Endpoint

The metrics endpoint publishes information about OS, JVM as well as application level metrics. Uma vez ativado, obtemos informações como memória, heap, processadores, threads, classes carregadas, classes descarregadas, pools de threads, além de algumas métricas HTTP.

Esta é a aparência da saída deste endpoint fora da caixa:

{
    "mem" : 193024,
    "mem.free" : 87693,
    "processors" : 4,
    "instance.uptime" : 305027,
    "uptime" : 307077,
    "systemload.average" : 0.11,
    "heap.committed" : 193024,
    "heap.init" : 124928,
    "heap.used" : 105330,
    "heap" : 1764352,
    "threads.peak" : 22,
    "threads.daemon" : 19,
    "threads" : 22,
    "classes" : 5819,
    "classes.loaded" : 5819,
    "classes.unloaded" : 0,
    "gc.ps_scavenge.count" : 7,
    "gc.ps_scavenge.time" : 54,
    "gc.ps_marksweep.count" : 1,
    "gc.ps_marksweep.time" : 44,
    "httpsessions.max" : -1,
    "httpsessions.active" : 0,
    "counter.status.200.root" : 1,
    "gauge.response.root" : 37.0
}

Para reunir métricas personalizadas, temos suporte para 'medidores', ou seja, instantâneos de valor único de dados e 'contadores', ou seja, incrementing/decrementing metrics.

Vamos implementar nossas próprias métricas personalizadas no endpoint/metrics. Por exemplo, vamos personalizar o fluxo de login para registrar uma tentativa de login bem ou malsucedida:

@Service
public class LoginServiceImpl {

    private final CounterService counterService;

    public LoginServiceImpl(CounterService counterService) {
        this.counterService = counterService;
    }

    public boolean login(String userName, char[] password) {
        boolean success;
        if (userName.equals("admin") && "secret".toCharArray().equals(password)) {
            counterService.increment("counter.login.success");
            success = true;
        }
        else {
            counterService.increment("counter.login.failure");
            success = false;
        }
        return success;
    }
}

Aqui está a aparência da saída:

{
    ...
    "counter.login.success" : 105,
    "counter.login.failure" : 12,
    ...
}

Observe que as tentativas de login e outros eventos relacionados à segurança estão disponíveis imediatamente no Actuator como eventos de auditoria.

3.6. Criação de um novo endpoint

Além de usar os endpoints existentes fornecidos pelo Spring Boot, também podemos criar um totalmente novo.

Em primeiro lugar, precisamos que o novo endpoint implemente a interfaceEndpoint<T>:

@Component
public class CustomEndpoint implements Endpoint> {

    @Override
    public String getId() {
        return "customEndpoint";
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public boolean isSensitive() {
        return true;
    }

    @Override
    public List invoke() {
        // Custom logic to build the output
        List messages = new ArrayList();
        messages.add("This is message 1");
        messages.add("This is message 2");
        return messages;
    }
}

Para acessar este novo endpoint, seuid é usado para mapeá-lo, ou seja, poderíamos exercitá-lo atingindo/customEndpoint.

Resultado:

[ "This is message 1", "This is message 2" ]

3.7. Personalização adicional

Por motivos de segurança, podemos escolher expor os pontos de extremidade do atuador em uma porta não padrão - a propriedademanagement.port pode ser facilmente usada para configurar isso.

Além disso, como já mencionamos, no 1.x. O Atuador configura seu próprio modelo de segurança, com base no Spring Security, mas independente do restante do aplicativo. Portanto, podemos alterar a propriedademanagement.address para restringir onde os pontos de extremidade podem ser acessados ​​pela rede:

#port used to expose actuator
management.port=8081

#CIDR allowed to hit actuator
management.address=127.0.0.1

#Whether security should be enabled or disabled altogether
management.security.enabled=false

Além disso, todos os terminais integrados, exceto/info, são sensíveis por padrão. Se o aplicativo estiver usando o Spring Security - podemos proteger esses pontos finais definindo as propriedades de segurança padrão - nome de usuário, senha e função - no arquivo application.properties:

security.user.name=admin
security.user.password=secret
management.security.role=SUPERUSER

4. Atuador Spring Boot 2.x

O Atuador 2.x mantém sua intenção fundamental, mas simplifica seu modelo, amplia seus recursos e incorpora melhores padrões.

Em primeiro lugar, esta versão se torna independente de tecnologia. Além disso, simplifica seu modelo de segurança, mesclando-o com o aplicativo.

Por último, entre as várias mudanças, é importante ter em mente que algumas delas estão quebrando. Isso inclui solicitações / respostas HTTP, bem como APIs Java.

Além disso, a versão mais recente suporta agora o modelo CRUD, em oposição ao antigo modelo RW (leitura / gravação).

4.1. Suporte de Tecnologia

Com sua segunda versão principal, o Actuator agora é independente de tecnologia, enquanto no 1.x estava vinculado ao MVC, portanto, à API do Servlet.

No 2.x, o atuador define seu modelo, conectável e extensível, sem depender do MVC para isso.

Portanto, com este novo modelo, podemos tirar proveito do MVC, bem como do WebFlux como uma tecnologia da web subjacente.

Além disso, as tecnologias futuras podem ser adicionadas implementando os adaptadores certos.

Por fim, o JMX permanece suportado para expor pontos de extremidade sem nenhum código adicional.

4.2. Mudanças Importantes

Ao contrário das versões anteriores,Actuator comes with most endpoints disabled.

Assim, os únicos dois disponíveis por padrão são/healthe/info.

Gostaríamos de habilitar todos eles, poderíamos definirmanagement.endpoints.web.exposure.include=*. Alternativamente, poderíamos listar os endpoints que deveriam ser habilitados.

Actuator agora compartilha a configuração de segurança com as regras de segurança regulares do aplicativo. Portanto, o modelo de segurança é dramaticamente simplificado.

Portanto, para ajustar as regras de segurança do atuador, poderíamos apenas adicionar uma entrada para/actuator/**:

@Bean
public SecurityWebFilterChain securityWebFilterChain(
  ServerHttpSecurity http) {
    return http.authorizeExchange()
      .pathMatchers("/actuator/**").permitAll()
      .anyExchange().authenticated()
      .and().build();
}

Podemos encontrar mais detalhes embrand new Actuator official docs.

Além disso,by default, all Actuator endpoints are now placed under the /actuator path.

Da mesma forma que na versão anterior, podemos ajustar este caminho, usando a nova propriedademanagement.endpoints.web.base-path.

4.3. Endpoints predefinidos

Vamos dar uma olhada em alguns endpoints disponíveis, a maioria deles já estavam disponíveis no 1.x.

No entanto,some endpoints have been added, some removed and some have been restructured:

  • /auditevents – lista os eventos relacionados à auditoria de segurança, como login / logout do usuário. Além disso, podemos filtrar por principal ou tipo, entre outros campos

  • /beans – returns todos os beans disponíveis em nossoBeanFactory. Ao contrário de/auditevents, não oferece suporte para filtragem

  • /conditions – anteriormente conhecido como /autoconfig, cria um relatório de condições em torno da configuração automática

  • /configprops – nos permite buscar todos os feijões@ConfigurationProperties

  • /env – retorna as propriedades do ambiente atual. Além disso, podemos recuperar propriedades únicas

  • /flyway – fornece detalhes sobre nossas migrações de banco de dados Flyway

  • /health – resume o estado de saúde de nosso aplicativo

  • /heapdump – constrói e retorna um despejo de heap da JVM usado por nosso aplicativo

  • /info – retorna informações gerais. Pode ser dados personalizados, informações de compilação ou detalhes sobre a confirmação mais recente

  • /liquibase – be comporta como/flyway, mas para Liquibase

  • /logfile – retorna logs de aplicativo comuns

  • /loggers – nos permite consultar e modificar o nível de registro de nosso aplicativo

  • /metrics – detalha as métricas de nosso aplicativo. Isso pode incluir métricas genéricas e personalizadas

  • /prometheus – retorna métricas como a anterior, mas formatadas para funcionar com um servidor Prometheus

  • /scheduledtasks – fornece detalhes sobre cada tarefa agendada em nosso aplicativo

  • /sessions – lista as sessões HTTP, uma vez que estamos usando Spring Session

  • /shutdown – executa um desligamento normal do aplicativo

  • /threaddump – despeja as informações de encadeamento da JVM subjacente

4.4. Indicadores de saúde

Assim como na versão anterior, podemos adicionar indicadores personalizados facilmente. Ao contrário de outras APIs, as abstrações para criar pontos de extremidade de integridade personalizados permanecem inalteradas. No entanto,a new interface ReactiveHealthIndicator has been added to implement reactive health checks.

Vamos dar uma olhada em uma verificação de integridade reativa personalizada simples:

@Component
public class DownstreamServiceHealthIndicator implements ReactiveHealthIndicator {

    @Override
    public Mono health() {
        return checkDownstreamServiceHealth().onErrorResume(
          ex -> Mono.just(new Health.Builder().down(ex).build())
        );
    }

    private Mono checkDownstreamServiceHealth() {
        // we could use WebClient to check health reactively
        return Mono.just(new Health.Builder().up().build());
    }
}

A handy feature of health indicators is that we can aggregate them as part of a hierarchy. Portanto, seguindo o exemplo anterior, poderíamos agrupar todos os serviços downstream em uma categoriadownstream-services. Esta categoria seria íntegra, desde que todos osservice aninhados fossem alcançáveis.

Verificações de integridade compostas estão presentes em 1.x aCompositeHealthIndicator. Além disso, em 2.x podemos usarCompositeReactiveHealthIndicator para sua contraparte reativa.

Ao contrário do Spring Boot 1.x, o sinalizadorendpoints. .sensitive foi removido. Para ocultar o relatório de integridade completo, podemos aproveitar as vantagens do novomanagement.endpoint.health.show-details.. Esse sinalizador é falso por padrão.

4.5. Métricas no Spring Boot 2

In Spring Boot 2.0, the in-house metrics were replaced with Micrometer support. Portanto, podemos esperar mudanças significativas. Se nosso aplicativo estava usando serviços métricos comoGaugeService or CounterService, eles não estarão mais disponíveis.

Em vez disso, devemos interagir comMicrometer diretamente. No Spring Boot 2.0, teremos um bean do tipoMeterRegistry autoconfigurado para nós.

Além disso, o micrômetro agora faz parte das dependências do atuador. Por isso, devemos continuar, desde que a dependência do Atuador esteja no caminho de classe.

Além disso, obteremos uma resposta completamente nova do endpoint/metrics:

{
  "names": [
    "jvm.gc.pause",
    "jvm.buffer.memory.used",
    "jvm.memory.used",
    "jvm.buffer.count",
    // ...
  ]
}

Como podemos observar no exemplo anterior, não há métricas reais como chegamos no 1.x.

Para obter o valor real de uma métrica específica, agora podemos navegar até a métrica desejada, ou seja,/actuator/metrics/jvm.gc.pausee obter uma resposta detalhada:

{
  "name": "jvm.gc.pause",
  "measurements": [
    {
      "statistic": "Count",
      "value": 3.0
    },
    {
      "statistic": "TotalTime",
      "value": 7.9E7
    },
    {
      "statistic": "Max",
      "value": 7.9E7
    }
  ],
  "availableTags": [
    {
      "tag": "cause",
      "values": [
        "Metadata GC Threshold",
        "Allocation Failure"
      ]
    },
    {
      "tag": "action",
      "values": [
        "end of minor GC",
        "end of major GC"
      ]
    }
  ]
}

Como podemos ver, as métricas agora são muito mais completas. Incluindo não apenas valores diferentes, mas também alguns metadados associados.

4.6. Personalizando o Endpoint/info

O ponto final de/info permanece inalterado. As before, we can add git details using the Maven or Gradle respective dependency:


    pl.project13.maven
    git-commit-id-plugin

Da mesma forma,we could also include build information including name, group, and version using the Maven or Gradle plugin:


    org.springframework.boot
    spring-boot-maven-plugin
    
        
            
                build-info
            
        
    

4.7. Criação de um endpoint personalizado

Como apontamos anteriormente, podemos criar pontos de extremidade personalizados. No entanto, o Spring Boot 2 redesenhou a maneira de conseguir isso para apoiar o novo paradigma agnóstico da tecnologia.

Let’s create an Actuator endpoint to query, enable and disable feature flags in our application:

@Component
@Endpoint(id = "features")
public class FeaturesEndpoint {

    private Map features = new ConcurrentHashMap<>();

    @ReadOperation
    public Map features() {
        return features;
    }

    @ReadOperation
    public Feature feature(@Selector String name) {
        return features.get(name);
    }

    @WriteOperation
    public void configureFeature(@Selector String name, Feature feature) {
        features.put(name, feature);
    }

    @DeleteOperation
    public void deleteFeature(@Selector String name) {
        features.remove(name);
    }

    public static class Feature {
        private Boolean enabled;

        // [...] getters and setters
    }

}

Para obter o ponto final, precisamos de um bean. Em nosso exemplo, estamos usando@Component para isso. Além disso, precisamos decorar este bean com@Endpoint.

O caminho de nosso endpoint é determinado pelo parâmetroid de@Endpoint, em nosso caso, ele encaminhará solicitações para/actuator/features.

Quando estiver pronto, podemos começar a definir operações usando:

  • @ReadOperation – será mapeado para HTTPGET

  • @WriteOperation - será mapeado para HTTPPOST

  • @DeleteOperation - será mapeado para HTTPDELETE

Quando executamos o aplicativo com o ponto de extremidade anterior, o Spring Boot o registrará.

Uma maneira rápida de verificar isso seria verificar os logs:

[...].WebFluxEndpointHandlerMapping: Mapped "{[/actuator/features/{name}],
  methods=[GET],
  produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features],
  methods=[GET],
  produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}],
  methods=[POST],
  consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}],
  methods=[DELETE]}"[...]

Nos logs anteriores, podemos ver como o WebFlux está expondo nosso novo terminal. Mudaríamos para MVC, ele simplesmente delegará essa tecnologia sem ter que alterar nenhum código.

Além disso, temos algumas considerações importantes a serem lembradas com essa nova abordagem:

  • Não há dependências com o MVC

  • Todos os metadados presentes como métodos antes de (sensitive, enabled…) não existir mais. Podemos, no entanto, habilitar ou desabilitar o endpoint usando@Endpoint(id = “features”, enableByDefault = false)

  • Ao contrário do 1.x, não há mais necessidade de estender uma determinada interface

  • Em contraste com o antigo modelo de leitura / gravação, agora podemos definirDELETE operações usando@DeleteOperation

4.8. Estendendo Endpoints Existentes

Vamos imaginar que queremos ter certeza de que a instância de produção de nosso aplicativo nunca será uma versãoSNAPSHOT. Decidimos fazer isso alterando o código de status HTTP do endpoint do atuador que retorna essas informações, ou seja,/info. se nosso aplicativo for umSNAPSHOT. Obteríamos um código de statusHTTP diferente.

We can easily extend the behavior of a predefined endpoint using the @EndpointExtension annotations, ou suas especializações mais concretas@EndpointWebExtension ou@EndpointJmxExtension:

@Component
@EndpointWebExtension(endpoint = InfoEndpoint.class)
public class InfoWebEndpointExtension {

    private InfoEndpoint delegate;

    // standard constructor

    @ReadOperation
    public WebEndpointResponse info() {
        Map info = this.delegate.info();
        Integer status = getStatus(info);
        return new WebEndpointResponse<>(info, status);
    }

    private Integer getStatus(Map info) {
        // return 5xx if this is a snapshot
        return 200;
    }
}

4.9. Habilitar todos os terminais

In order to access the actuator endpoints using HTTP, we need to both enable and expose them. Por padrão, todos os terminais, exceto/shutdown, estão habilitados. Apenas os pontos de extremidade/healthe/info são expostos por padrão.

Precisamos adicionar a seguinte configuração para expor todos os pontos de extremidade:

management.endpoints.web.exposure.include=*

Para habilitar explicitamente um endpoint específico (por exemplo/shutdown), we use:

management.endpoint.shutdown.enabled=true

Para expor todos os endpoints ativados, exceto um (por exemplo/loggers), usamos:

management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=loggers

5. Sumário

Neste artigo, falamos sobre o Spring Boot Actuator. Começamos a definir o que o Atuador significa e o que ele faz para nós.

Em seguida, focamos no Atuador para a versão atual do Spring Boot, 1.x. discutindo como usá-lo, ajustá-lo e ampliá-lo.

Em seguida, discutimos o Atuador no Spring Boot 2. Nós nos concentramos no que há de novo e aproveitamos o WebFlux para expor nosso endpoint.

Além disso, falamos sobre as importantes mudanças de segurança que podemos encontrar nesta nova iteração. Discutimos alguns pontos de extremidade populares e como eles também mudaram.

Por fim, demonstramos como personalizar e estender o Atuador.

Como sempre, podemos encontrar o código usado neste artigo no GitHub paraSpring Boot 1.x eSpring Boot 2.x.