目录
自定义EndPoint
/beans
/health
/loggers
/info
/threaddump
Actuator模块可以采集应用内部运行信息暴露给外部,帮助我们监控和管理Spring Boot 应用,功能例如健康检查,运行指标收集,HTTP 跟踪,日志级别等
#开放所有端点
management.endpoints.web.exposure.include=*
#开放指定端点
management.endpoints.web.exposure.include=beans
或者
management.endpoint.beans.enabled=true
#开放所有 && 关闭某个
management.endpoints.web.exposure.exclude=beans
management.endpoints.web.exposure.include=*
默认情况下所有端点都暴露在“/actuator”路径下,可以自定义
#/actuator/xxx路徑,都变成/manage/xxx
management.endpoints.web.base-path=/manage
#管理端口调整
management.server.port=9999
今天记录我涉及的常用EndPoint,以后有用到其他的随时再记
GET | /actuator | 查看有哪些 Actuator endpoint 是开放的,和对应的路径 |
GET | /actuator/beans | 查看容器中的 bean |
GET | /actuator/health | 查看当前应用指标情况,实现HealthIndicator可以自定义指标项 |
GET | /actuator/loggers | 查看当前应用日志级别情况,可以运行时调整 |
GET | /actuator/info | 应用信息展示 |
GET | /actuator/threaddump | 当前应用线程栈dump,同 jstack |
如下代码
@Endpoint注解 定义一个监控端点类,id就是路径(/actuator/myendpoint)
@Component 扫描并交给容器管理
@ReadOperation 代表GET请求处理方法 ,@WriteOperation代表POST请求处理方法
@Endpoint(id = "myendpoint")
@Component
public class MyEndPoint implements ApplicationContextAware {
private ApplicationContext app;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.app = applicationContext;
}
@ReadOperation
public Map invokeGet() {
Map ret = new HashMap<>();
// 自定义监控逻辑
ret.put("type", "get");
ret.put("status", "okk");
ret.put("details", "nothing to do");
return ret;
}
@WriteOperation
public Map invokePost() {
Map ret = new HashMap<>();
// 自定义监控逻辑
ret.put("type", "post");
ret.put("status", "okk");
ret.put("details", "nothing to do");
return ret;
}
}
加载所有EndPoint并由DispatcherServlet路由的源码位置:org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration#webEndpointServletHandlerMapping
@Bean
@ConditionalOnMissingBean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties, Environment environment) {
List> allEndpoints = new ArrayList<>();
// 这里查询bean容器中所有注解了@Endpoint的类
Collection webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath);
boolean shouldRegisterLinksMapping = StringUtils.hasText(basePath)
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT);
// WebMvcEndpointHandlerMapping继承了AbstractHandlerMethodMapping
// 将每个Endpoint和其中的get/post方法封装为handlermethod,由springmvc在请求时路由
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
shouldRegisterLinksMapping);
}
返回当前应用所有父子容器中的bean信息,如下图
源码实现类为 org.springframework.boot.actuate.beans.BeansEndpoint,比较简单就是从ApplicationContext挨个取出BeanDefinition,把部分信息封装到Map返回
@Endpoint(id = "beans")
public class BeansEndpoint {
private final ConfigurableApplicationContext context;
public BeansEndpoint(ConfigurableApplicationContext context) {
this.context = context;
}
@ReadOperation
public ApplicationBeans beans() {
// 循环把父子容器的bean信息放到map中返回
Map contexts = new HashMap<>();
ConfigurableApplicationContext context = this.context;
while (context != null) {
contexts.put(context.getId(), ContextBeans.describing(context));
context = getConfigurableParent(context);
}
return new ApplicationBeans(contexts);
}
private static Map describeBeans(ConfigurableListableBeanFactory beanFactory) {
Map beans = new HashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
if (isBeanEligible(beanName, definition, beanFactory)) {
beans.put(beanName, describeBean(beanName, definition, beanFactory));
}
}
return beans;
}
}
各个组件的运行状况
内置了很多组件的检测器如下,
也可以自定义实现其他组件的健康检测类
@Component
public class RocketMQHealthIndicator extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
// 自定义逻辑
// 展示信息
builder.status(Status.UP);
builder.withDetail("aaaa", "aaaa");
builder.withDetail("bbbb", "bbbb");
builder.withDetail("cccc", "cccc");
}
}
查看当前应用日志级别情况,可以动态改变
如下应用层代码:
首先访问/actuator/loggers路径,可以得到如下结果,目前日志级别是INFO
执行输出test111方法如图:
访问POST请求如下,可以动态改变日志级别,改为DEBUG级别
访问后再次执行test111方法如图:无需重启应用,非常方便生产环境使用
自定义显示程序信息,有两种方式定制 info 信息
一种就是在application.properties配置文件中配置如下:
访问端点返回如下
另一种代码形式,实现InfoContributor接口
与jstack工具一样,展示当前应用所有线程堆栈