Chapter 11 Spring Boot Application Monitoring

Keywords: Spring Java shell JSON

Chapter 11 Spring Boot Application Monitoring

In the actual production system, how do we know that our application works well? We often need to monitor the actual operation of the system (various cpu, io, disk, db, business functions and other indicators). It takes us a lot of energy to do these things. In SpringBook, we don't need to face such a problem at all.

This chapter mainly introduces how to use Actuator to monitor Spring Boot application indicators, and how to monitor and manage our application through remote shell.

Introduction to 11.0 Actuator

Actuator is the introspection and monitoring function of the application system provided by spring boot. Actuator's introspection function of the application system itself can enable us to realize online operation and maintenance monitoring conveniently and quickly. This one smells like DevOps.

Through Actuator, we can use data indicators to measure the performance of our applications. For example, see how many threads the system runs, the situation of gc, the basic parameters of running, and so on.

spring-boot-actuator module provides a module to monitor and manage the production environment. It can use http, jmx, ssh, telnet to manage and monitor applications.

With the rise of Devops and the popularization of docker technology, micro-services will become more and more popular in some occasions. springboot, which can directly embed web servers into a jar package, is more in line with the trend of devops: it is very convenient to form a jar package and throw it on the server. It also saves more than half of the monitoring with its own Actuator.

11.1 Use Spring Boot Actuator to monitor applications

1. Use actuator

Adding starter dependencies

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

Restart the application. Spring Boot Actuator's automatic configuration function will automatically add Actuator Auditing information, health information and metrics gathering to the application.

Actuator mainly exposes the following functions:

HTTP method Route describe Sensitive information
GET /autoconfig View the usage of auto-configuration and display a report of auto-configuration, which shows all auto-configuration candidates and the reasons why they were or were not applied true
GET /configprops View configuration properties, including default configuration, and display a collated list of all @Configuration Properties true
GET /beans Beans and their relational lists, showing a complete list of all Spring Beans in an application true
GET /dump Print thread stack true
GET /env View all environment variables true
GET /env/{name} View specific variable values true
GET /health Look at the application health metrics. When accessing with an unauthenticated connection, a simple'status'is displayed, and when accessing with an authenticated connection, all the information details are displayed. false
GET /info View application information false
GET /mappings View all url maps, the collated list of all @RequestMapping paths true
GET /metrics View the Basic Indicators of Application true
GET /metrics/{name} View Specific Indicators true
POST /shutdown Close the application, allowing the application to close gracefully (not enabled by default) true
GET /trace View basic trace information, default to some of the latest HTTP requests true

These HTTP endpoints are accessed by the system root path by default. If we want to customize context-path, we can configure it as follows:

server.port=8888

#actuator
management.port=58888
management.context-path=/actuator

Restart the application and we will see the following logs:

01:23:38.033 [localhost-startStop-1] INFO  o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'springSecurityFilterChain' to: [/*] 
01:23:38.283 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/info || /actuator/info.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.284 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/trace || /actuator/trace.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.285 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/beans || /actuator/beans.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.286 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/configprops || /actuator/configprops.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.343 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/mappings || /actuator/mappings.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.348 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/health || /actuator/health.json],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(java.security.Principal) 
01:23:38.349 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/autoconfig || /actuator/autoconfig.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.352 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/heapdump || /actuator/heapdump.json],methods=[GET],produces=[application/octet-stream]}" onto public void org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint.invoke(boolean,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException,javax.servlet.ServletException 
01:23:38.353 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/dump || /actuator/dump.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.362 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/metrics/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String) 
01:23:38.362 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/metrics || /actuator/metrics.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.363 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/env/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String) 
01:23:38.363 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/env || /actuator/env.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke() 
01:23:38.364 [main] INFO  o.s.b.a.e.m.EndpointHandlerMapping - Mapped "{[/actuator/server || /actuator/server.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()

We can clearly see that Actuator provides HTTP Rest API (Endpoint) related to application running information monitoring.

For example, we visit http://localhost:58888/actuator/env The environment parameter information of the system is returned.

// 20170504001108
// http://localhost:58888/actuator/env

{
  "profiles": [

  ],
  "server.ports": {
    "local.management.port": 58888,
    "local.server.port": 8888
  },
  "servletContextInitParams": {

  },
  "systemProperties": {
    "java.runtime.name": "Java(TM) SE Runtime Environment",
    "sun.boot.library.path": "/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/jre/lib",
    "java.vm.version": "25.40-b25",
    "user.country.format": "CN",
   ......

    "server.port": "8888",
    "spring.jpa.hibernate.naming-strategy": "org.hibernate.cfg.ImprovedNamingStrategy",
    "spring.jpa.hibernate.ddl-auto": "update",
    "info.build.version": "1.0-SNAPSHOT",
    "management.context-path": "/actuator",
    "spring.datasource.url": "jdbc:mysql://localhost:3306/lightsword?useUnicode=true&characterEncoding=UTF8",
    "endpoints.metrics.enabled": "true",
    "endpoints.info.id": "info",
    "management.port": "58888",
    "spring.velocity.resourceLoaderPath": "classpath:/templates/",
    "spring.mvc.static-path-pattern": "/**",
    "spring.jpa.database": "MYSQL",
    "spring.datasource.min-idle": "0",
    "info.app.name": "ecs",
    "spring.datasource.max-active": "0",
    "spring.datasource.max-wait": "10000",
    "management.security.sessions": "stateless",
    "endpoints.metrics.id": "metrics",
    "management.security.roles": "ADMIN",
    "spring.application.name": "lightsword",
    "spring.datasource.max-idle": "0",
    "spring.datasource.password": "******",
    "endpoints.actuator.enabled": "true",
    "spring.datasource.username": "root",
    "spring.velocity.properties.input.encoding": "UTF-8",
    "logging.config": "classpath:logback-dev.groovy",
    "endpoints.info.enabled": "true",
    "spring.jpa.show-sql": "true",
    "spring.velocity.toolbox-config-location": "/WEB-INF/toolbox.xml",
    "info.build.artifactId": "lightsword",
    "spring.velocity.properties.output.encoding": "UTF-8",
    "spring.velocity.suffix": ".html",
    "spring.datasource.driverClassName": "com.mysql.jdbc.Driver",
    "spring.resources.static-locations": "classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/",
    "spring.velocity.charset": "UTF-8",
    "info.app.version": "1.0.0"
  }
}

Other endpoints are rich in system running data, and interested in running the engineering source code of this chapter to view the data structure information of endpoints.

At the same time, Actuator supports integration with security, which can be enabled in the following configuration:

# Enable security.
management.security.enabled=true
# Comma-separated list of roles that can access the management endpoint.
management.security.roles=ADMIN

If we use database-based user,role integration Security authentication, after testing, found here management.security.roles=ADMIN will not work.

If we want to configure a check to remove an item, such as not monitoring health.mail:

server:  
  port: 8888  
management:  
  port: 58888  
  health:  
    mail:  
      enabled: false

We can see that the path mapped on the 58888 port is also the server resource of the current application. for example http://localhost:58888/js/jsoneditor.js It can also be accessed. Follow-up visits http://localhost:8888/js/jsoneditor.js It's the same result.

The source code for Actuator automatic configuration is in org. spring framework. boot. actuate. autoconfigure. For a detailed and in-depth understanding of the principles, you can read the source code here.

The configuration of ACTUATOR in application.properties is as follows

# ----------------------------------------
# ACTUATOR PROPERTIES
# ----------------------------------------

# ENDPOINTS (AbstractEndpoint subclasses)
endpoints.enabled=true # Enable endpoints.
endpoints.sensitive= # Default endpoint sensitive setting.
endpoints.actuator.enabled=true # Enable the endpoint.
endpoints.actuator.path= # Endpoint URL path.
endpoints.actuator.sensitive=false # Enable security on the endpoint.
endpoints.auditevents.enabled= # Enable the endpoint.
endpoints.auditevents.path= # Endpoint path.
endpoints.auditevents.sensitive=false # Enable security on the endpoint.
endpoints.autoconfig.enabled= # Enable the endpoint.
endpoints.autoconfig.id= # Endpoint identifier.
endpoints.autoconfig.path= # Endpoint path.
endpoints.autoconfig.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.beans.enabled= # Enable the endpoint.
endpoints.beans.id= # Endpoint identifier.
endpoints.beans.path= # Endpoint path.
endpoints.beans.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.configprops.enabled= # Enable the endpoint.
endpoints.configprops.id= # Endpoint identifier.
endpoints.configprops.keys-to-sanitize=password,secret,key,token,.*credentials.*,vcap_services # Keys that should be sanitized. Keys can be simple strings that the property ends with or regex expressions.
endpoints.configprops.path= # Endpoint path.
endpoints.configprops.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.docs.curies.enabled=false # Enable the curie generation.
endpoints.docs.enabled=true # Enable actuator docs endpoint.
endpoints.docs.path=/docs #
endpoints.docs.sensitive=false #
endpoints.dump.enabled= # Enable the endpoint.
endpoints.dump.id= # Endpoint identifier.
endpoints.dump.path= # Endpoint path.
endpoints.dump.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.env.enabled= # Enable the endpoint.
endpoints.env.id= # Endpoint identifier.
endpoints.env.keys-to-sanitize=password,secret,key,token,.*credentials.*,vcap_services # Keys that should be sanitized. Keys can be simple strings that the property ends with or regex expressions.
endpoints.env.path= # Endpoint path.
endpoints.env.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.flyway.enabled= # Enable the endpoint.
endpoints.flyway.id= # Endpoint identifier.
endpoints.flyway.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.health.enabled= # Enable the endpoint.
endpoints.health.id= # Endpoint identifier.
endpoints.health.mapping.*= # Mapping of health statuses to HttpStatus codes. By default, registered health statuses map to sensible defaults (i.e. UP maps to 200).
endpoints.health.path= # Endpoint path.
endpoints.health.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.health.time-to-live=1000 # Time to live for cached result, in milliseconds.
endpoints.heapdump.enabled= # Enable the endpoint.
endpoints.heapdump.path= # Endpoint path.
endpoints.heapdump.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.hypermedia.enabled=false # Enable hypermedia support for endpoints.
endpoints.info.enabled= # Enable the endpoint.
endpoints.info.id= # Endpoint identifier.
endpoints.info.path= # Endpoint path.
endpoints.info.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.jolokia.enabled=true # Enable Jolokia endpoint.
endpoints.jolokia.path=/jolokia # Endpoint URL path.
endpoints.jolokia.sensitive=true # Enable security on the endpoint.
endpoints.liquibase.enabled= # Enable the endpoint.
endpoints.liquibase.id= # Endpoint identifier.
endpoints.liquibase.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.logfile.enabled=true # Enable the endpoint.
endpoints.logfile.external-file= # External Logfile to be accessed.
endpoints.logfile.path=/logfile # Endpoint URL path.
endpoints.logfile.sensitive=true # Enable security on the endpoint.
endpoints.loggers.enabled=true # Enable the endpoint.
endpoints.loggers.id= # Endpoint identifier.
endpoints.loggers.path=/logfile # Endpoint path.
endpoints.loggers.sensitive=true # Mark if the endpoint exposes sensitive information.
endpoints.mappings.enabled= # Enable the endpoint.
endpoints.mappings.id= # Endpoint identifier.
endpoints.mappings.path= # Endpoint path.
endpoints.mappings.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.metrics.enabled= # Enable the endpoint.
endpoints.metrics.filter.enabled=true # Enable the metrics servlet filter.
endpoints.metrics.filter.gauge-submissions=merged # Http filter gauge submissions (merged, per-http-method)
endpoints.metrics.filter.counter-submissions=merged # Http filter counter submissions (merged, per-http-method)
endpoints.metrics.id= # Endpoint identifier.
endpoints.metrics.path= # Endpoint path.
endpoints.metrics.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.shutdown.enabled= # Enable the endpoint.
endpoints.shutdown.id= # Endpoint identifier.
endpoints.shutdown.path= # Endpoint path.
endpoints.shutdown.sensitive= # Mark if the endpoint exposes sensitive information.
endpoints.trace.enabled= # Enable the endpoint.
endpoints.trace.filter.enabled=true # Enable the trace servlet filter.
endpoints.trace.id= # Endpoint identifier.
endpoints.trace.path= # Endpoint path.
endpoints.trace.sensitive= # Mark if the endpoint exposes sensitive information.

# ENDPOINTS CORS CONFIGURATION (EndpointCorsProperties)
endpoints.cors.allow-credentials= # Set whether credentials are supported. When not set, credentials are not supported.
endpoints.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
endpoints.cors.allowed-methods=GET # Comma-separated list of methods to allow. '*' allows all methods.
endpoints.cors.allowed-origins= # Comma-separated list of origins to allow. '*' allows all origins. When not set, CORS support is disabled.
endpoints.cors.exposed-headers= # Comma-separated list of headers to include in a response.
endpoints.cors.max-age=1800 # How long, in seconds, the response from a pre-flight request can be cached by clients.

# JMX ENDPOINT (EndpointMBeanExportProperties)
endpoints.jmx.domain= # JMX domain name. Initialized with the value of 'spring.jmx.default-domain' if set.
endpoints.jmx.enabled=true # Enable JMX export of all endpoints.
endpoints.jmx.static-names= # Additional static properties to append to all ObjectNames of MBeans representing Endpoints.
endpoints.jmx.unique-names=false # Ensure that ObjectNames are modified in case of conflict.

# JOLOKIA (JolokiaProperties)
jolokia.config.*= # See Jolokia manual

# MANAGEMENT HTTP SERVER (ManagementServerProperties)
management.add-application-context-header=false # Add the "X-Application-Context" HTTP header in each response.
management.address= # Network address that the management endpoints should bind to.
management.context-path= # Management endpoint context-path. For instance `/actuator`
management.cloudfoundry.enabled= # Enable extended Cloud Foundry actuator endpoints
management.cloudfoundry.skip-ssl-validation= # Skip SSL verification for Cloud Foundry actuator endpoint security calls
management.port= # Management endpoint HTTP port. Uses the same port as the application by default. Configure a different port to use management-specific SSL.
management.security.enabled=true # Enable security.
management.security.roles=ACTUATOR # Comma-separated list of roles that can access the management endpoint.
management.security.sessions=stateless # Session creating policy to use (always, never, if_required, stateless).
management.ssl.ciphers= # Supported SSL ciphers. Requires a custom management.port.
management.ssl.client-auth= # Whether client authentication is wanted ("want") or needed ("need"). Requires a trust store. Requires a custom management.port.
management.ssl.enabled= # Enable SSL support. Requires a custom management.port.
management.ssl.enabled-protocols= # Enabled SSL protocols. Requires a custom management.port.
management.ssl.key-alias= # Alias that identifies the key in the key store. Requires a custom management.port.
management.ssl.key-password= # Password used to access the key in the key store. Requires a custom management.port.
management.ssl.key-store= # Path to the key store that holds the SSL certificate (typically a jks file). Requires a custom management.port.
management.ssl.key-store-password= # Password used to access the key store. Requires a custom management.port.
management.ssl.key-store-provider= # Provider for the key store. Requires a custom management.port.
management.ssl.key-store-type= # Type of the key store. Requires a custom management.port.
management.ssl.protocol=TLS # SSL protocol to use. Requires a custom management.port.
management.ssl.trust-store= # Trust store that holds SSL certificates. Requires a custom management.port.
management.ssl.trust-store-password= # Password used to access the trust store. Requires a custom management.port.
management.ssl.trust-store-provider= # Provider for the trust store. Requires a custom management.port.
management.ssl.trust-store-type= # Type of the trust store. Requires a custom management.port.

# HEALTH INDICATORS
management.health.db.enabled=true # Enable database health check.
management.health.cassandra.enabled=true # Enable cassandra health check.
management.health.couchbase.enabled=true # Enable couchbase health check.
management.health.defaults.enabled=true # Enable default health indicators.
management.health.diskspace.enabled=true # Enable disk space health check.
management.health.diskspace.path= # Path used to compute the available disk space.
management.health.diskspace.threshold=0 # Minimum disk space that should be available, in bytes.
management.health.elasticsearch.enabled=true # Enable elasticsearch health check.
management.health.elasticsearch.indices= # Comma-separated index names.
management.health.elasticsearch.response-timeout=100 # The time, in milliseconds, to wait for a response from the cluster.
management.health.jms.enabled=true # Enable JMS health check.
management.health.ldap.enabled=true # Enable LDAP health check.
management.health.mail.enabled=true # Enable Mail health check.
management.health.mongo.enabled=true # Enable MongoDB health check.
management.health.rabbit.enabled=true # Enable RabbitMQ health check.
management.health.redis.enabled=true # Enable Redis health check.
management.health.solr.enabled=true # Enable Solr health check.
management.health.status.order=DOWN, OUT_OF_SERVICE, UP, UNKNOWN # Comma-separated list of health statuses in order of severity.

# INFO CONTRIBUTORS (InfoContributorProperties)
management.info.build.enabled=true # Enable build info.
management.info.defaults.enabled=true # Enable default info contributors.
management.info.env.enabled=true # Enable environment info.
management.info.git.enabled=true # Enable git info.
management.info.git.mode=simple # Mode to use to expose git information.

# TRACING (TraceProperties)
management.trace.include=request-headers,response-headers,cookies,errors # Items to be included in the trace.

# METRICS EXPORT (MetricExportProperties)
spring.metrics.export.aggregate.key-pattern= # Pattern that tells the aggregator what to do with the keys from the source repository.
spring.metrics.export.aggregate.prefix= # Prefix for global repository if active.
spring.metrics.export.delay-millis=5000 # Delay in milliseconds between export ticks. Metrics are exported to external sources on a schedule with this delay.
spring.metrics.export.enabled=true # Flag to enable metric export (assuming a MetricWriter is available).
spring.metrics.export.excludes= # List of patterns for metric names to exclude. Applied after the includes.
spring.metrics.export.includes= # List of patterns for metric names to include.
spring.metrics.export.redis.key=keys.spring.metrics # Key for redis repository export (if active).
spring.metrics.export.redis.prefix=spring.metrics # Prefix for redis repository if active.
spring.metrics.export.send-latest= # Flag to switch off any available optimizations based on not exporting unchanged metric values.
spring.metrics.export.statsd.host= # Host of a statsd server to receive exported metrics.
spring.metrics.export.statsd.port=8125 # Port of a statsd server to receive exported metrics.
spring.metrics.export.statsd.prefix= # Prefix for statsd exported metrics.
spring.metrics.export.triggers.*= # Specific trigger properties per MetricWriter bean name.

Auto-configuring HealthIndicators

Under the directory org. spring framework. boot. actuate. health, Spring Boot automatically matches the following HelthIndicators by default

Check Cassandra database is up.

Check low disk space.

Check that the database connection is normal

Check Elastic search cluster is up.

Check JMS broker is up.

Check mail server is up.

Check Mongo database is up.

Check Rabbit server is up.

Check Redis server is up.

Check Solr server is up.

Examples, such as Data Source Health Indicator, have the following health check code

        private void doDataSourceHealthCheck(Health.Builder builder) throws Exception {
        String product = getProduct();
        builder.up().withDetail("database", product);
        String validationQuery = getValidationQuery(product);
        if (StringUtils.hasText(validationQuery)) {
            try {
                // Avoid calling getObject as it breaks MySQL on Java 7
                List<Object> results = this.jdbcTemplate.query(validationQuery,
                        new SingleColumnRowMapper());
                Object result = DataAccessUtils.requiredSingleResult(results);
                builder.withDetail("hello", result);
            }
            catch (Exception ex) {
                builder.down(ex);
            }
        }
    }

The implementation logic is simple, which is to execute query once to see if the return is normal.

Customize Health Indicators

To customize a HealthIndicators, we just need to register a Spring bean, implement the HealthIndicator interface, implement its health() method, and return a HealthObject.

We can refer directly to the HealthIndicators that Spring Boot automatically configures by default and copy them.

A simple example code is as follows:

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class MyHealthIndicator 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();
    }

}

However, it should be noted that these HTTP Endpoints of Actuator are based on Spring MVC applications.

Write your own Endpoint

Just implement the Endpoint < T > interface. This interface is defined as follows:

package org.springframework.boot.actuate.endpoint;

public interface Endpoint<T> {
    String getId();

    boolean isEnabled();

    boolean isSensitive();

    T invoke();
}

Where the getId() method returns the path of the url.

We implement an Endpoint to get basic information about the current running server. The code is as follows:

package com.springboot.in.action.actuator

import java.net.InetAddress
import java.util

import org.springframework.boot.actuate.endpoint.Endpoint
import org.springframework.stereotype.Component

/**
  * Created by jack on 2017/5/3.
  */
@Component
class ServerEndpoint extends Endpoint[java.util.List[String]] {
  override def invoke(): java.util.List[String] = {
    val serverDetails = new util.ArrayList[String]
    try {
      serverDetails.add("Server IP Address : " + InetAddress.getLocalHost.getHostAddress)
      serverDetails.add("Server OS : " + System.getProperty("os.name").toLowerCase)
    } catch {
      case e: Exception =>
        e.printStackTrace()
    }
    serverDetails
  }

  override def getId: String = "server"
  override def isSensitive: Boolean = false
  override def isEnabled: Boolean = true
}

Redeploy, run, access http://localhost:58888/actuator/server We see the output as follows:

// 20170503235224
// http://localhost:58888/actuator/server

[
  "Server IP Address : 192.168.1.104",
  "Server OS : mac os x"
]

11.2 Spring Book Remote Shell

Spring Boot enables us to connect to running applications using ssh or telnet commands by integrating Java shell framework CRaSH.

Add the following dependencies to enable remote shell support:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-remote-shell</artifactId>
 </dependency>

If you want to use telnet access, you need to add additional dependencies of org.crsh:crsh.shell.telnet.

After configuration, restart the application. We'll see the startup log

01:00:42.611 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property auth.spring.roles=ADMIN from properties 
01:00:42.619 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=SSHPlugin,interface=SSHPlugin] 
01:00:42.621 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=SSHInlinePlugin,interface=CommandPlugin] 
01:00:42.623 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=KeyAuthenticationPlugin,interface=KeyAuthenticationPlugin] 
01:00:42.648 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=CronPlugin,interface=CronPlugin] 
01:00:42.657 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=MailPlugin,interface=MailPlugin] 
01:00:42.661 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=CRaSHShellFactory,interface=ShellFactory] 
01:00:42.663 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=GroovyLanguageProxy,interface=Language] 
01:00:42.680 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=JavaLanguage,interface=Language] 
01:00:42.687 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=ScriptLanguage,interface=Language] 
01:00:42.700 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=JaasAuthenticationPlugin,interface=AuthenticationPlugin] 
01:00:42.730 [main] INFO  org.crsh.plugin.PluginManager - Loaded plugin Plugin[type=SimpleAuthenticationPlugin,interface=AuthenticationPlugin] 
01:00:42.739 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property ssh.port=2000 from properties 
01:00:42.739 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property ssh.auth_timeout=600000 from properties 
01:00:42.740 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property ssh.idle_timeout=600000 from properties 
01:00:42.741 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property ssh.default_encoding=UTF-8 from properties 
01:00:42.742 [main] INFO  o.s.b.a.a.CrshAutoConfiguration$CrshBootstrapBean - Configuring property auth=spring from properties 
01:00:42.766 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=KeyAuthenticationPlugin,interface=KeyAuthenticationPlugin] 
01:00:42.766 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=JaasAuthenticationPlugin,interface=AuthenticationPlugin] 
01:00:42.766 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=SimpleAuthenticationPlugin,interface=AuthenticationPlugin] 
01:00:42.766 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=AuthenticationManagerAdapter,interface=AuthenticationPlugin] 
01:00:42.767 [main] INFO  org.crsh.ssh.SSHPlugin - Booting SSHD 
01:00:42.793 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=GroovyLanguageProxy,interface=Language] 
01:00:42.861 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=JavaLanguage,interface=Language] 
01:00:42.861 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=ScriptLanguage,interface=Language] 
01:00:42.871 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=CRaSHShellFactory,interface=ShellFactory] 
01:00:44.185 [main] INFO  o.a.sshd.common.util.SecurityUtils - Trying to register BouncyCastle as a JCE provider 
01:00:45.739 [main] INFO  o.a.sshd.common.util.SecurityUtils - Registration succeeded 
01:00:45.978 [main] INFO  org.crsh.ssh.term.SSHLifeCycle - About to start CRaSSHD 
01:00:46.070 [main] INFO  org.crsh.ssh.term.SSHLifeCycle - CRaSSHD started on port 2000 
01:00:46.070 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=SSHPlugin,interface=SSHPlugin] 
01:00:46.070 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=SSHInlinePlugin,interface=CommandPlugin] 
01:00:46.071 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=CronPlugin,interface=CronPlugin] 
01:00:46.071 [main] INFO  org.crsh.plugin.PluginManager - Initialized plugin Plugin[type=MailPlugin,interface=MailPlugin]

As can be seen from the sentence CRaSSHD started on port 2000, the port number that ssh defaults to listen on is 2000. SpringBoot's property configuration for remote shell s is in the org.springframework.boot.actuate.autoconfigure.ShellProperties class.

We can also configure our own port number in application.properties:

management.shell.ssh.port=2001

Execute the following commands

$ ssh -p 2000 user@localhost

We can connect our application to the shell terminal.

If we don't configure anything, using the default configuration, the default listening port of the remote shell is 2000, the default user name is user, the password is randomly generated, and it will be displayed in the output log.

If our application integrates Spring Security, remote shell uses the default system configuration.

management.shell.auth.spring.roles=ADMIN,USER
#spring, Integrated with spring security
management.shell.auth.type=spring

This configuration will use Spring Security's Authentication Manager to handle login responsibilities with the following code:

private static class AuthenticationManagerAdapter extends CRaSHPlugin<AuthenticationPlugin> implements AuthenticationPlugin<String> {
        private static final PropertyDescriptor<String> ROLES = PropertyDescriptor.create("auth.spring.roles", "ADMIN", "Comma separated list of roles required to access the shell");
        @Autowired
        private AuthenticationManager authenticationManager;
        @Autowired(
            required = false
        )
        @Qualifier("shellAccessDecisionManager")
        private AccessDecisionManager accessDecisionManager;
        private String[] roles;

        private AuthenticationManagerAdapter() {
            this.roles = new String[]{"ADMIN"};
        }

        public boolean authenticate(String username, String password) throws Exception {
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);

            Authentication token;
            try {
                token = this.authenticationManager.authenticate(token);
            } catch (AuthenticationException var6) {
                return false;
            }

            if(this.accessDecisionManager != null && token.isAuthenticated() && this.roles != null) {
                try {
                    this.accessDecisionManager.decide(token, this, SecurityConfig.createList(this.roles));
                } catch (AccessDeniedException var5) {
                    return false;
                }
            }

            return token.isAuthenticated();
        }

Refer specifically to the Javadoc of Crsh AutoConfiguration and Shell Properties.

If not, you will use a simple authentication strategy, and you may see information like this:

Using default password for shell access: ec03e16c-4cf4-49ee-b745-7c8255c1dd7e

If you want to specify a username and password in a simple authentication policy, you can configure it as follows

management.shell.auth.type=simple
management.shell.auth.simple.user.name=user
management.shell.auth.simple.user.password=123456

This security mechanism is the function of Spring security.

Linux and OSX users can directly use ssh to connect remote shell s. Windows users can download and install PuTTY, SecureCRT and other clients to achieve ssh connection.

Enter help to get a list of commands. Spring Boot provides metrics, beans, autoconfig, and endpoint commands. As follows

jack@jacks-MacBook-Air:~$ ssh -p 2000 user@localhost
Password authentication
Password: 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.6.RELEASE)

> help
Try one of these commands with the -h or --help switch:                       

NAME       DESCRIPTION                                                        
autoconfig Display auto configuration report from ApplicationContext          
beans      Display beans in ApplicationContext                                
cron       manages the cron plugin                                            
dashboard  a monitoring dashboard                                             
egrep      search file(s) for lines that match a pattern                      
endpoint   Invoke actuator endpoints                                          
env        display the term env                                               
filter     a filter for a stream of map                                       
java       various java language commands                                     
jmx        Java Management Extensions                                         
jul        java.util.logging commands                                         
jvm        JVM informations                                                   
less       opposite of more                                                   
mail       interact with emails                                               
man        format and display the on-line manual pages                        
metrics    Display metrics provided by Spring Boot                            
shell      shell related command                                              
sleep      sleep for some time                                                
sort       sort a map                                                         
system     vm system properties commands                                      
thread     JVM thread commands                                                
help       provides basic help                                                
repl       list the repl or change the current repl

For example, we would like to see which Endpoint s exist in the system. The direct command line operation is as follows

> endpoint
usage: endpoint [-h | --help] COMMAND [ARGS]

The most commonly used endpoint commands are:
   invoke           Invoke provided actuator endpoint
   list             List all available and enabled actuator endpoints



> endpoint list
serverEndpoint
requestMappingEndpoint
environmentEndpoint
healthEndpoint
beansEndpoint
infoEndpoint
metricsEndpoint
traceEndpoint
dumpEndpoint
autoConfigurationReportEndpoint
configurationPropertiesReportEndpoint

Connect to the ssh terminal, let's look at the logs printed in the background of the application.

02:06:04.657 [main] INFO  o.s.b.c.e.t.TomcatEmbeddedServletContainer - Tomcat started on port(s): 8888 (http) 
02:06:04.673 [main] INFO  scala.App - Started App in 52.422 seconds (JVM running for 56.978) 
02:06:13.105 [pool-6-thread-1] INFO  o.a.s.server.session.ServerSession - Server session created from /127.0.0.1:50538 
02:06:13.260 [pool-6-thread-1] INFO  o.a.s.server.session.ServerSession - Kex: server->client aes128-ctr hmac-sha2-256 none 
02:06:13.260 [pool-6-thread-1] INFO  o.a.s.server.session.ServerSession - Kex: client->server aes128-ctr hmac-sha2-256 none 
02:06:16.370 [pool-6-thread-1] INFO  o.a.s.s.s.ServerUserAuthService - Session user@/127.0.0.1:50538 authenticated

As you can see, ServerUserAuthService is responsible for authenticating the current login user and ServerSession is responsible for maintaining the current login session.

You can use Groovy or Java to write other shell commands (refer specifically to the CRaSH document), and Spring Book by default searches for commands along the following paths:

classpath*:/commands/**
classpath*:/crash/commands/**

If we want to change the search path, set the shell.command-path-patterns attribute.

Here is a'hello'command loaded from src/main/resources/commands/hello.java:

/**
 * Created by jack on 2017/5/4.
 */

package commands;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.crsh.cli.Command;
import org.crsh.cli.Usage;
import org.crsh.command.BaseCommand;
import org.crsh.command.InvocationContext;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;


@Usage("Test Command : hello say")
public class hello extends BaseCommand{
    @Usage("hello say")
    @Command
    public String say(InvocationContext context){
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) context.getAttributes().get("spring.beanfactory");

        for (String name : defaultListableBeanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
            context.getWriter().write(name);
            context.getWriter().write("\n");
        }

        return "Hello, Now Is " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }
}

To execute commands in remote ssh, the results are as follows

jack@jacks-MacBook-Air:~$ ssh -p 2000 user@localhost
Password authentication
Password: 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.6.RELEASE)

> help
Try one of these commands with the -h or --help switch:                                                                               

NAME       DESCRIPTION                                                                                                                
autoconfig Display auto configuration report from ApplicationContext                                                                  
beans      Display beans in ApplicationContext                                                                                        
cron       manages the cron plugin                                                                                                    
dashboard  a monitoring dashboard                                                                                                     
egrep      search file(s) for lines that match a pattern                                                                              
endpoint   Invoke actuator endpoints                                                                                                  
env        display the term env                                                                                                       
filter     a filter for a stream of map                                                                                               
hello      Test Command : hello say                                                                                                   
java       various java language commands                                                                                             
jmx        Java Management Extensions                                                                                                 
jul        java.util.logging commands                                                                                                 
jvm        JVM informations                                                                                                           
less       opposite of more                                                                                                           
mail       interact with emails                                                                                                       
man        format and display the on-line manual pages                                                                                
metrics    Display metrics provided by Spring Boot                                                                                    
shell      shell related command                                                                                                      
sleep      sleep for some time                                                                                                        
sort       sort a map                                                                                                                 
system     vm system properties commands                                                                                              
thread     JVM thread commands                                                                                                        
help       provides basic help                                                                                                        
repl       list the repl or change the current repl                                                                                   

> hello
usage: hello [-h | --help] COMMAND [ARGS]

The most commonly used hello commands are:
   say              hello say



> hello say
......

lightSwordHealthIndicator
serverEndpoint
globalExceptionHandlerAdvice
angularController
helloController
httpApiController
httpReportController
httpSuiteController
rootController
webMvcConfig
webSecurityConfig
dataInit
lightSwordUserDetailService
org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
authenticationManagerBuilder
enableGlobalAuthenticationAutowiredConfigurer
initializeUserDetailsBeanManagerConfigurer
initializeAuthenticationProviderBeanManagerConfigurer
org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration
delegatingApplicationListener
webSecurityExpressionHandler
springSecurityFilterChain
........

org.springframework.boot.autoconfigure.web.MultipartProperties
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration$RestTemplateConfiguration
restTemplateBuilder
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration
org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration$DatabaseShutdownExecutorJpaDependencyConfiguration
org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration
inMemoryDatabaseShutdownExecutor
loginFilter
org.springframework.orm.jpa.SharedEntityManagerCreator#0
Hello, Now Is 2017-05-04 02:29:38

In addition to creating new commands, you can also extend other features of the CRaSH shell. All Spring Beans that inherit org.crsh.plugin.CRaSHPlugin will automatically register with the shell, specifically viewing the CRaSH reference document [4].

Summary

This chapter sample engineering source code:

https://github.com/EasySpringBoot/lightsword/tree/spring_boot_actuator_and_remote_shell_2017.5.4

Reference material:
1.http://javabeat.net/spring-boot-actuator/
2.http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-remote-shell.html
3.https://my.oschina.net/zj0303/blog/708366
4.http://www.crashub.org/

Posted by englishman69 on Wed, 03 Jul 2019 15:34:47 -0700