赞
踩
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- Spring Boot Admin 是一个管理和监控Spring Boot 应用程序的开源软件。每个应用都认为是一个客户端,通过HTTP或者使用 Eureka注册到admin server中进行展示,Spring Boot Admin UI部分使用AngularJs将数据展示在前端。
- Spring Boot Admin 是一个针对spring-boot的actuator接口进行UI美化封装的监控工具。他可以:在列表中浏览所有被监控spring-boot项目的基本信息,详细的Health信息、内存信息、JVM信息、垃圾回收信息、各种配置信息(比如数据源、缓存列表和命中率)等,还可以直接修改logger的level。
<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
<version>1.5.6</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
{ "_links":{ "self":{ "href":"http://localhost:8080/actuator", "templated":false }, "health":{ "href":"http://localhost:8080/actuator/health", "templated":false }, "health-path":{ "href":"http://localhost:8080/actuator/health/{*path}", "templated":true }, "info":{ "href":"http://localhost:8080/actuator/info", "templated":false } } }
"health":{
"href":"http://localhost:8080/actuator/health",
"templated":false
},
# actuator 监控配置
management:
endpoints:
web:
exposure:
#默认值访问health,info端点 用*可以暴露全部端点
include: "*"
endpoint:
health:
show-details: always #获得健康检查中所有指标的详细信息
- never:不显示细节;
- when-authorized:详细信息只显示给授权用户,可以使用management.endpoint.health.roles配置授权角色;
- always:详细信息显示给所有用户
- 传统的management.security管理已被标记为不推荐,现在一般使用单独启用并暴露
- 禁用的端点将从应用程序上下文中完全删除,如果只想公开端点(对外暴露),需要使用include和exclude属性属性
server: port: 8080 spring: application: name: test-actuator-server group: com.demo.test management: server: port: 8081 #actuator访问端口默认与server.port相同,为了安全通过此处可以指定端口 endpoints: web: exposure: include: "*" # 暴露所有端口,默认info, health exclude: aaa #排除端点,exclude优先于include #默认情况下访问"服务域名:端口号/actuator/指定端点",通过该配置修改/actuator base-path: /monitor #修改/actuator为/monitor,此时再去访问就需要"服务域名:端口号/monitor/指定端点" #将指定端点映射到指定路径 path-mapping: health: healthcheck # 将 health 端点重新映射为 healthcheck enabled-by-default: true # 启用所有端口
# 禁用HTTP端点。如果不希望通过HTTP公开端点,则可以将管理端口设置为-1
management.port: -1
# 端点为不带任何参数的读取操作自动缓存响应,下面的示例将beans端点缓存的生存时间设置为10秒
management.endpoint.beans.cache.time-to-live: 10s
# 暴露所有端点。*在YAML中有特殊的含义,所以如果要包含(或排除)所有端点,请务必添加引号
management.endpoints.web.exposure.include: "*"
# 设置端点是否启用的默认值。示例为禁用所有的端点
management.endpoints.enabled-by-default: false
- 如果没有设置 management.server.port,management.endpoints.web.base-path是相对于server.servlet.context-path的;
- 如果设置了 management.server.port,management.endpoints.web.base-path是相对于management.server.servlet.context-path的;
management.server.port: 8081
management.server.address: 192.168.1.11
server.port: 8443
server.ssl.enabled: true
server.ssl.key-store: classpath:store.jks
server.ssl.key-password: secret
management.server.port: 8080
management.server.ssl.enabled: false
server.port: 8443
server.ssl.enabled: true
server.ssl.key-store: classpath:main.jks
server.ssl.key-password: secret
management.server.port: 8080
management.server.ssl.enabled: true
management.server.ssl.key-store: classpath:management.jks
management.server.ssl.key-password: secret
- /autoconfig:更名为 /conditions;
- /docs:被废弃;
- /trace:更名为 /httptrace;
- /dump:更名为 /threaddump
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
{
"blog-url": "http://blog.battcn.com",
"author": "Levin",
"version": "0.0.1-SNAPSHOT"
}
- never:不显示细节(默认)
- when-authorized:详细信息只显示给授权用户,可以使用management.endpoint.health.roles配置授权角色;
- always:详细信息显示给所有用户
management:
endpoints:
web:
exposure:
include: "*" # 暴露所有端口,默认info, health
enabled-by-default: true # 启用所有端口
endpoint:
health:
show-details: always #配置显示health健康信息,默认never不显示,always为显示所有
{ "status":"UP", "components":{ #diskSpace:表示硬盘空间, "diskSpace":{ "status":"UP",#up表示正常上线状态 "details":{ "total":472506167296, #硬盘总容量 "free":49352339456, #空闲容量 "threshold":10485760,#线程占用率 "exists":true } }, #客户端与服务的是否可以通信 "ping":{ "status":"UP" } } }
{ "status":"UP", "details":{ "diskSpace":{ "status":"UP", "details":{ "total":472506167296, "free":49352318976, "threshold":10485760 } }, "influxDb":{ "status":"UP", "details":{ "version":"1.8.10" } }, "refreshScope":{ "status":"UP" }, "hystrix":{ "status":"UP" }, "redis":{ "status":"UP", "details":{ "version":"5.0.7" } } } }
package com.battcn.health; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; /** * <p>自定义健康端点</p> * * @author Levin * @since 2018/5/24 0024 */ @Component("my1") public class MyHealthIndicator implements HealthIndicator { private static final String VERSION = "v1.0.0"; @Override public Health health() { int code = check(); if (code != 0) { Health.down().withDetail("code", code).withDetail("version", VERSION).build(); } return Health.up().withDetail("code", code) .withDetail("version", VERSION).up().build(); } private int check() { return 0; } }
{ "status": "UP", "details": { "my1": { "status": "UP", "details": { "code": 0, "version": "v1.0.0" } }, "diskSpace": { "status": "UP", "details": { "total": 100944310272, "free": 55071866880, "threshold": 10485760 } } } }
package com.battcn.health; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; import org.springframework.stereotype.Component; /** * <p>自定义健康端点</p> * <p>功能更加强大一点,DataSourceHealthIndicator / RedisHealthIndicator 都是这种写法</p> * * @author Levin * @since 2018/5/24 0024 */ @Component("my2") public class MyAbstractHealthIndicator extends AbstractHealthIndicator { private static final String VERSION = "v1.0.0"; @Override protected void doHealthCheck(Health.Builder builder) throws Exception { int code = check(); if (code != 0) { builder.down().withDetail("code", code).withDetail("version", VERSION).build(); } builder.withDetail("code", code) .withDetail("version", VERSION).up().build(); } private int check() { return 0; } }
{
"status": "UP",
"details": {
"my2": {
"status": "UP",
"details": {
"code": 0,
"version": "v1.0.0"
}
},
"my1": {...},
"diskSpace": {...}
}
}
@Endpoint 构建 rest api 的唯一路径
@ReadOperation GET请求,响应状态为 200 如果没有返回值响应 404(资源未找到)
@WriteOperation POST请求,响应状态为 200 如果没有返回值响应 204(无响应内容)
@DeleteOperation DELETE请求,响应状态为 200 如果没有返回值响应 204(无响应内容)
- 自定义端点类,通过@Endpoint注解修饰类,通过的id属性指定端点路径
- 通过@ReadOperation注解修饰自定义端点类中返回端点指标信息的方法
- 将端点类注入到容器中
package com.battcn.endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import java.util.HashMap; import java.util.Map; /** * <p>@Endpoint 是构建 rest 的唯一路径 </p> * 不同请求的操作,调用时缺少必需参数,或者使用无法转换为所需类型的参数,则不会调用操作方法,响应状态将为400(错误请求) * <P>@ReadOperation = GET 响应状态为 200 如果没有返回值响应 404(资源未找到) </P> * <P>@WriteOperation = POST 响应状态为 200 如果没有返回值响应 204(无响应内容) </P> * <P>@DeleteOperation = DELETE 响应状态为 200 如果没有返回值响应 204(无响应内容) </P> * * @author Levin * @since 2018/5/24 0024 */ @Endpoint(id = "battcn") public class MyEndPoint { @ReadOperation public Map<String, String> hello() { Map<String, String> result = new HashMap<>(); result.put("author", "Levin"); result.put("age", "24"); result.put("email", "1837307557@qq.com"); return result; } }
package com.battcn; import com.battcn.endpoint.MyEndPoint; import org.springframework.boot.SpringApplication; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author Levin */ @SpringBootApplication public class Chapter13Application { public static void main(String[] args) { SpringApplication.run(Chapter13Application.class, args); } @Configuration static class MyEndpointConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnEnabledEndpoint public MyEndPoint myEndPoint() { return new MyEndPoint(); } } }
{
"author": "Levin",
"age": "24",
"email": "1837307557@qq.com"
}
{
"contexts":{
"test-actuator-server":{
"positiveMatches":Object{...},
"negativeMatches":Object{...},
"unconditionalClasses":Array[12]
}
}
}
#配置文件中配置日志记录路径,文件名
logging:
file:
name: e:/logs/test-actuator.log
{ "names":[ "http.server.requests", "jvm.buffer.count", "jvm.buffer.memory.used", "jvm.buffer.total.capacity", "jvm.classes.loaded", "jvm.classes.unloaded", "jvm.gc.live.data.size", "jvm.gc.max.data.size", "jvm.gc.memory.allocated", "jvm.gc.memory.promoted", "jvm.gc.pause", "jvm.memory.committed", "jvm.memory.max", "jvm.memory.used", "jvm.threads.daemon", "jvm.threads.live", "jvm.threads.peak", "jvm.threads.states", "logback.events", "process.cpu.usage", "process.start.time", "process.uptime", "system.cpu.count", "system.cpu.usage", "tomcat.sessions.active.current", "tomcat.sessions.active.max", "tomcat.sessions.alive.max", "tomcat.sessions.created", "tomcat.sessions.expired", "tomcat.sessions.rejected" ] }
{
"name":"system.cpu.count",
"description":"The number of processors available to the Java virtual machine",
"baseUnit":null,
"measurements":[
{
"statistic":"VALUE",
"value":8
}
],
"availableTags":[
]
}
- 服务优雅关闭需要配置 server.shutown 服务的关闭方式,默认immediate直接关闭,需要设置为graceful
- 然后访问"http://localhost:8080/actuator/shutdown" 注意点该接口需要post访问
- 此时如果关闭服务,会先判断是否有访问,如果有会等访问执行完毕后再关闭
- 引入Actuator依赖,配置开启端点,
- ymal配置开启端点,显示health端点详情
- 通过定时任务,定时请求health端点,获取相关组件状态,判断状态是否全部UP
- 将获取到的状态存储到redis,并设置失效时间
5.上层定时查询redis获取状态并展示
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management: endpoint: metrics: enabled: true prometheus: enabled: true health: show-details: always endpoints: web: exposure: include: - prometheus - health metrics: export: prometheus: enabled: true tags: application: ${spring.application.name}
- serverStateReportExecute()定时任务方法是入口
package com.roamblue.psb.adapter.service.impl; import com.alibaba.fastjson.JSON; import com.roamblue.psb.adapter.bean.response.HealthData; import com.roamblue.psb.adapter.bean.response.ServerStatusReportResp; import com.roamblue.psb.adapter.service.IServerStatusReportService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Service public class ServerStatusReportServiceImpl implements IServerStatusReportService { @Autowired private RedisTemplate<String, String> redisTemplate; @Autowired private RestTemplate restTemplate; @Value("${report.flag}") private Boolean reportFlag; private static final String UP_STATUS_KEY = "UP"; private static final String REPORT_PATH = "http://localhost:8080/actuator/health"; private static final String STATUS_KEY = "public:server:psb:status"; private static final String START_INFO_KEY = "public:server:psb:info"; private static boolean START_INFO_FLAG = true; public String queryActuatorHealthInfo() { ResponseEntity<String> responseEntity = restTemplate.exchange(REPORT_PATH, HttpMethod.GET, null, String.class); return responseEntity.getBody(); } /** * 请求 "http://localhost:8080/actuator/health" 获取相关组件状态 * 判断是否存在非UP状态的,如果存在返回err **/ private ServerStatusReportResp checkHealthInfo(String healthInfoStr) { return Optional.ofNullable(healthInfoStr) .map(infoStr -> JSON.parseObject(infoStr, HealthData.class)) .filter(health -> !UP_STATUS_KEY.equals(health.getStatus())) .map(HealthData::getDetails) .map(Map::entrySet) .map(entrySet -> { return entrySet.stream() .filter(entry -> !entry.getValue().toString().contains(UP_STATUS_KEY)) .map(entry -> entry.getKey()) .collect(Collectors.joining(",")); }) .map(downDetailStr -> ServerStatusReportResp.error(downDetailStr)) .orElseGet(ServerStatusReportResp::ok); } @Override @Scheduled(fixedRate = 590000) public void serverStateReportExecute() { if (!reportFlag) { return; } String reportDesc = this.queryActuatorHealthInfo(); ServerStatusReportResp resp = this.checkHealthInfo(reportDesc); if (START_INFO_FLAG) { redisTemplate.opsForValue().set(START_INFO_KEY, JSON.toJSONString(resp)); START_INFO_FLAG = false; } redisTemplate.opsForValue().set(STATUS_KEY, resp.toString(), 60 * 10, TimeUnit.SECONDS); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。