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/