详解微服务监控(springboot admin server client、实时日志配置、动态修改日志级别、自定义服务通知实现等
1. 基本介绍
spring boot admin 分为 服务端 server 和被监控的客户端 client;
服务器端启动后,客户端端自动注册服务信息到服务器端(如果试spring cloud服务客户端不需要注册到spring boot admin 服务器端,正常注册到服务器中心如:nacos或者eureka,spring boot admin 服务器端自动从注册中心拉取 );
服务端提供监控的可视化界面UI,客户端通过暴露的监控点(actuator)提供应用的系统信息、详细的Health信息、日志、内存、线程、JVM信息、垃圾回收信息、各种配置信息比如数据源、缓存列表和命中率)等信息给服务端,还可以直接修改logger的level,服务器端通过文字和图表进行展示。
2.整合过程
客户端整合:
<!-- SpringBoot Web -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!-- SpringBoot Actuator -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- springcloud alibaba nacos discovery -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
management:endpoints:web:exposure:include: '*'
springboot-admin server (springbot-admin-ui)整合
<!-- SpringBoot Admin -->
<dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-server</artifactId><version>2.6.10</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
添加启动类注解:@EnableAdminServer
package com.wemedia.monitor;import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;/*** 启用Admin Server*/
@SpringBootApplication
@EnableAdminServer
@EnableDiscoveryClient
public class MonitorApplication {public static void main(String[] args) {SpringApplication.run(MonitorApplication.class, args);}}
给客户端与服务端都配置注册中心nacos地址
spring: application:# 应用名称name: xx-xxxx cloud:nacos:discovery:# 服务注册地址server-addr: 127.0.0.1:8848
配置 security权限
package com.wemedia.monitor.config;import com.wemedia.monitor.filter.CustomCsrfFilter;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import jakarta.servlet.DispatcherType;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;import java.util.UUID;/*** @auther* @description Spring Boot Admin的Security相关配置* **/
@Configuration(proxyBeanMethods = false)
public class SecuritySecureConfig {private final AdminServerProperties adminServer;private final SecurityProperties security;public SecuritySecureConfig(AdminServerProperties adminServer, SecurityProperties security) {this.adminServer = adminServer;this.security = security;}// @Bean
// public AdminServerProperties getAdminServer(){
// AdminServerProperties adminServer=new AdminServerProperties();
// return adminServer;
// }
// @Bean
// public SecurityProperties getSecurity(){
// return new SecurityProperties();
// }@Beanprotected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();successHandler.setTargetUrlParameter("redirectTo");successHandler.setDefaultTargetUrl(this.adminServer.path("/"));http.authorizeHttpRequests((authorizeRequests) -> authorizeRequests //.requestMatchers(new AntPathRequestMatcher(this.adminServer.path("/assets/**"))).permitAll().requestMatchers(new AntPathRequestMatcher(this.adminServer.path("/actuator/info"))).permitAll().requestMatchers(new AntPathRequestMatcher(adminServer.path("/actuator/health"))).permitAll().requestMatchers(new AntPathRequestMatcher(this.adminServer.path("/login"))).permitAll().dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll().anyRequest().authenticated()).formLogin((formLogin) -> formLogin.loginPage(this.adminServer.path("/login")).successHandler(successHandler)).logout((logout) -> logout.logoutUrl(this.adminServer.path("/logout"))).httpBasic(Customizer.withDefaults());http.addFilterAfter(new CustomCsrfFilter(), BasicAuthenticationFilter.class).csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()).ignoringRequestMatchers(new AntPathRequestMatcher(this.adminServer.path("/instances"), "POST"),new AntPathRequestMatcher(this.adminServer.path("/instances/*"), "DELETE"),new AntPathRequestMatcher(this.adminServer.path("/actuator/**"))));http.rememberMe((rememberMe) -> rememberMe.key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600));return http.build();}/*** 配置登录用户名和密码* @param passwordEncoder* @return*/@Beanpublic InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {UserDetails user = User.withUsername("admin").password(passwordEncoder.encode("admin123")).roles("USER").build();return new InMemoryUserDetailsManager(user);}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}
给微服务配置日志
logging:file:name: logs/${spring.application.name}/sys-info.loglevel:com.wemedia.user.feign: inforoot: debugconfig: classpath:logback-spring.xml
path:log: logs/${spring.application.name}/
访问spring boot admin 访问地址:
http://localhost:8888 账户密码: admin admin123
3.查看日志
4. 动态修改日志级别
5.自定义通知
在springboot-admin server模块实现自定义通知,当服务下线或异常,可以通过通知进行消息提醒用户
package com.wemedia.monitor.component;import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.notify.AbstractStatusChangeNotifier;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;/**** 自定义通知实现** 通过添加实现Notifier接口的Spring Beans来添加您自己的通知程序**/
@Component
public class MonitorNotify extends AbstractStatusChangeNotifier {public MonitorNotify(InstanceRepository repository) {super(repository);}@Overrideprotected Mono<Void> doNotify(InstanceEvent event, Instance instance) {return Mono.fromRunnable(() -> {if (event instanceof InstanceStatusChangedEvent){String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();switch (status){// 健康检查没通过case "DOWN":System.out.println("发送 健康检查没通过 的通知!");break;// 服务离线case "OFFLINE":System.out.println("发送 服务离线 的通知!");break;// 服务上线case "UP":System.out.println("发送 服务上线 的通知!");break;// 服务未知异常case "UNKNOWN":System.out.println("发送 服务未知异常 的通知!");break;default:break;}}});}
}
当停止服务,spring-admin控制台日志即可收到通知消息,如下:
6.结合nacos出现异常错误:com.alibaba.nacos.api.exception.NacosException: user not found! 需要在nacos管理界面上创建用户并授权才可以使用
给nacos登录用户授权: