第11章 Spring Boot应用监控
来源:互联网 发布:mac关闭某个程序 编辑:程序博客网 时间:2024/06/01 23:27
第11章 Spring Boot应用监控
在实际的生产系统中,我们怎样知道我们的应用运行良好呢?我们往往需要对系统实际运行的情况(各种cpu,io,disk,db,业务功能等指标)进行监控运维。这需要耗费我们不少精力来搞这些工作。在SpringBoot中,我们完全不需要面对这样的难题。
本章主要介绍使用Actuator对Spring Boot应用指标进行监控,以及通过远程shell监控与管理我们的应用。
11.0 Actuator简介
Actuator是spring boot提供的对应用系统的自省和监控功能,Actuator对应用系统本身的自省功能,可以让我们方便快捷的实现线上运维监控的工作。这个有点DevOps的味道。
通过Actuator,我们可以使用数据化的指标去度量我们的应用的运行情况。比如查看系统运行了多少线程,gc的情况,运行的基本参数等等
spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http、jmx、ssh、telnet等拉管理和监控应用。
随着devops的兴起,以及docker技术的普及,微服务在一定场合会越来越受欢迎。即使不说微服务,springboot这种可以直接内嵌web服务器打成一个jar包的方式,也更符合devops的趋势:打成个jar包,往服务器上一扔,十分方便,自带Actuator,把监控也给省了一大半,真正做到了可以把精力花在刀刃上。
11.1 使用Spring Boot Actuator监控应用
1.使用actuator
添加starter依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
重启应用。Spring Boot Actuator 的自动配置功能,会把Actuator的审计(Auditing)信息、健康(health)信息、各种度量数据采集(metrics gathering)会自动加到应用里面。
Actuator主要暴露的功能如下:
这些HTTP端点(Endpoint),默认是系统根路径访问的。如果我们想自定义context-path, 按照如下配置即可:
server.port=8888#actuatormanagement.port=58888management.context-path=/actuator
重启应用,我们将会看到如下日志:
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()
我们可以清楚的看到Actuator提供应用运行信息监控等相关的HTTP Rest API(Endpoint)。
例如,我们访问 http://localhost:58888/actuator/env , 返回了系统的环境参数信息
// 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" }}
其他的一些端点,都带有丰富的系统运行数据,感兴趣的可以运行本章节的工程源码,查看端点的数据结构信息。
同时,Actuator支持与security集成,按照如下配置即可启用:
# Enable security.management.security.enabled=true# Comma-separated list of roles that can access the management endpoint.management.security.roles=ADMIN
如果我们使用基于数据库的user,role集成Security的权限认证,经过测试,发现这里的management.security.roles=ADMIN将会不起作用。
如果我们想配置去掉某项的检查,比如不监控health.mail:
server: port: 8888 management: port: 58888 health: mail: enabled: false
我们可以看出这个58888端口映射的路径也是当前应用的服务器资源。例如http://localhost:58888/js/jsoneditor.js 也能访问到。跟访问 http://localhost:8888/js/jsoneditor.js 是一样的结果。
关于Actuator自动配置的源码在org.springframework.boot.actuate.autoconfigure中。想要详细深入的了解其中的原理,可以阅读这里的源码。
在application.properties中关于 ACTUATOR的配置如下
# ----------------------------------------# 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 endpointsmanagement.cloudfoundry.skip-ssl-validation= # Skip SSL verification for Cloud Foundry actuator endpoint security callsmanagement.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 INDICATORSmanagement.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.
自动配置的 HealthIndicators
在目录org.springframework.boot.actuate.health下面,Spring Boot 默认自动配了如下的HealthIndicators
- CassandraHealthIndicator
检查 Cassandra database is up.
- DiskSpaceHealthIndicator
检查 low disk space.
- DataSourceHealthIndicator
检查数据库连接是否正常
- ElasticsearchHealthIndicator
检查Elasticsearch cluster is up.
- JmsHealthIndicator
检查JMS broker is up.
- MailHealthIndicator
检查mail server is up.
- MongoHealthIndicator
检查Mongo database is up.
- RabbitHealthIndicator
检查Rabbit server is up.
- RedisHealthIndicator
检查Redis server is up.
- SolrHealthIndicator
检查Solr server is up.
举例说明,比如DataSourceHealthIndicator,其健康检查代码如下
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); } } }
实现逻辑很简单,就是执行一次query,看返回是否正常。
自定义 HealthIndicators
我们要自定义一个HealthIndicators,只需要注册一个Spring bean,实现HealthIndicator接口,实现其health()方法,返回一个 Health 对象即可。
我们可以直接参考Spring Boot 默认自动配置的那些HealthIndicators,仿照着写即可。
一个简单的示例代码如下:
import org.springframework.boot.actuate.health.Health;import org.springframework.boot.actuate.health.HealthIndicator;import org.springframework.stereotype.Component;@Componentpublic 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(); }}
不过有一点需要说明的是,Actuator 的这些HTTP Endpoints是基于 Spring MVC的应用的。
写一个自己的Endpoint
只需要实现Endpoint<T> 接口即可。这个接口的定义如下:
package org.springframework.boot.actuate.endpoint;public interface Endpoint<T> { String getId(); boolean isEnabled(); boolean isSensitive(); T invoke();}
其中,getId()方法返回的就是url的path。
我们来实现一个获取当前运行服务器的基本信息的Endpoint,代码如下:
package com.springboot.in.action.actuatorimport java.net.InetAddressimport java.utilimport org.springframework.boot.actuate.endpoint.Endpointimport org.springframework.stereotype.Component/** * Created by jack on 2017/5/3. */@Componentclass 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}
重新部署运行,访问 http://localhost:58888/actuator/server ,我们看到输出如下:
// 20170503235224// http://localhost:58888/actuator/server[ "Server IP Address : 192.168.1.104", "Server OS : mac os x"]
11.2 Spring Boot远程Shell
Spring Boot通过集成Java shell框架CRaSH,让我们可以使用ssh或telnet命令连接到运行的应用。
添加以下依赖即可启用远程shell支持:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-remote-shell</artifactId> </dependency>
如果想使用telnet访问,需要另外添加org.crsh:crsh.shell.telnet的依赖。
配置完毕,重启应用。我们会看到启动日志
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]
从CRaSSHD started on port 2000这句看出,ssh默认监听的端口号为2000。SpringBoot的关于remote shell的属性配置,在org.springframework.boot.actuate.autoconfigure.ShellProperties类里面。
我们也可以在application.properties里面自行配置端口号:
management.shell.ssh.port=2001
执行如下命令
$ ssh -p 2000 user@localhost
我们就可以在shell终端连接我们的应用了。
如果我们什么都不配置,使用默认的配置,远程shell默认监听端口为2000,默认用户名为user,密码为随机生成的,并且在输出日志中会显示。
如果我们应用集成了Spring Security,remote shell使用默认系统的配置。
management.shell.auth.spring.roles=ADMIN,USER#spring, Integrated with spring securitymanagement.shell.auth.type=spring
这样配置将使用Spring Security的AuthenticationManager处理登录职责,相关代码如下:
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(); }
具体参考CrshAutoConfiguration和ShellProperties的Javadoc。
如果不是,将使用一个简单的认证策略,你可能会看到类似这样的信息:
Using default password for shell access: ec03e16c-4cf4-49ee-b745-7c8255c1dd7e
如果想在简单的认证策略里指定用户名密码,按照如下配置即可
management.shell.auth.type=simplemanagement.shell.auth.simple.user.name=usermanagement.shell.auth.simple.user.password=123456
这个安全机制就是用的Spring security里面的功能。
Linux和OSX用户可以直接使用ssh连接远程shell,Windows用户可以下载并安装PuTTY,SecureCRT等客户端来实现ssh连接。
输入help可以获取命令列表,Spring Boot提供metrics,beans,autoconfig和endpoint命令。如下所示
jack@jacks-MacBook-Air:~$ ssh -p 2000 user@localhostPassword authenticationPassword: . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.4.6.RELEASE)> helpTry 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
比如,我们想看一下系统有那些Endpoint,直接命令行操作如下
> endpointusage: 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 listserverEndpointrequestMappingEndpointenvironmentEndpointhealthEndpointbeansEndpointinfoEndpointmetricsEndpointtraceEndpointdumpEndpointautoConfigurationReportEndpointconfigurationPropertiesReportEndpoint
连上ssh终端,我们看应用端的后台打印的日志
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
可以看出,ServerUserAuthService负责认证当前登录用户,ServerSession负责维护当前登录session。
你可以使用Groovy或Java编写其他的shell命令(具体参考CRaSH文档),Spring Boot默认会搜索以下路径的命令:
classpath*:/commands/**classpath*:/crash/commands/**
如果我们想改变搜索路径,设置shell.command-path-patterns属性即可。
下面是一个从src/main/resources/commands/hello.java加载的'hello'命令:
/** * 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()); }}
在远程ssh中执行命令,结果如下
jack@jacks-MacBook-Air:~$ ssh -p 2000 user@localhostPassword authenticationPassword: . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.4.6.RELEASE)> helpTry 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 > hellousage: hello [-h | --help] COMMAND [ARGS]The most commonly used hello commands are: say hello say> hello say......lightSwordHealthIndicatorserverEndpointglobalExceptionHandlerAdviceangularControllerhelloControllerhttpApiControllerhttpReportControllerhttpSuiteControllerrootControllerwebMvcConfigwebSecurityConfigdataInitlightSwordUserDetailServiceorg.springframework.security.config.annotation.authentication.configuration.AuthenticationConfigurationauthenticationManagerBuilderenableGlobalAuthenticationAutowiredConfigurerinitializeUserDetailsBeanManagerConfigurerinitializeAuthenticationProviderBeanManagerConfigurerorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurationdelegatingApplicationListenerwebSecurityExpressionHandlerspringSecurityFilterChain........org.springframework.boot.autoconfigure.web.MultipartPropertiesorg.springframework.boot.autoconfigure.web.WebClientAutoConfiguration$RestTemplateConfigurationrestTemplateBuilderorg.springframework.boot.autoconfigure.web.WebClientAutoConfigurationorg.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration$DatabaseShutdownExecutorJpaDependencyConfigurationorg.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfigurationinMemoryDatabaseShutdownExecutorloginFilterorg.springframework.orm.jpa.SharedEntityManagerCreator#0Hello, Now Is 2017-05-04 02:29:38
除了创建新命令,你也可以扩展CRaSH shell的其他特性,所有继承org.crsh.plugin.CRaSHPlugin的Spring Beans将自动注册到shell,具体可以查看CRaSH参考文档[4]。
小结
本章示例工程源代码:
https://github.com/EasySpringBoot/lightsword/tree/spring_boot_actuator_and_remote_shell_2017.5.4
参考资料:
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/
- 第11章 Spring Boot应用监控
- 《Spring Boot开发:从0到1》第11章 Spring Boot应用监控
- spring boot/cloud 应用监控
- spring-boot 之 使用Admin监控应用
- spring-boot 之 使用Admin监控应用
- spring-boot 之 使用Admin监控应用
- spring-boot 之 使用Admin监控应用
- 使用Spring Boot Actuator监控应用
- Spring Boot应用的健康监控
- spring-boot 之 使用Admin监控应用
- spring boot应用p6spy监控sql
- Spring Boot应用的健康监控
- Spring Boot应用的健康监控
- Spring Boot应用的健康监控
- Spring Boot 应用可视化监控(Prometheus + Grafana)
- spring boot(11)-druid监控
- spring boot(11)-druid监控
- 第10章 Spring Boot应用部署运维
- 8.6 Spring Boot集成Spring Security
- 8.7 Spring Boot集成日志
- 8.8 Spring Boot静态资源处理
- 【算法】CTR预估中的贝叶斯平滑方法(一)
- 接口测试工具-postman的简单使用
- 第11章 Spring Boot应用监控
- 第12章 Spring Boot与微服务
- 第13章 SpringBoot开发中的常见问题与解决方案
- 第10章 Spring Boot应用部署运维
- 附录
- 第9章 Spring Boot开发者工具
- vimのcopy和move的另一种方式
- 附录A 计算机的0和1
- 附录B 编程的本质