I. Effect
Login account + password
Monitoring service
View live logs
Nail notification
2. What is Spring Boot Admin?
Spring Boot Admin is an open source community project for managing and monitoring spring boot applications. The application, as the Spring Boot Admin Client, registers with the Spring Boot Admin Server (via HTTP) or uses the spring cloud Registry (e.g. Eureka, Consul) to discover. The UI is the Vue.js application, which shows some monitoring on the Actuator endpoint of Spring Boot Admin Client. The server adopts the mode of Spring WebFlux + Netty. Spring Boot Admin provides the following functions for registered applications:
-
Show health
-
Show details, such as
-
JVM and memory metrics
-
micrometer.io index
-
Data source indicators
-
Cache index
-
Show build information number
-
Follow and download log files
-
View the jvm system - and environment properties
-
View Spring Boot configuration properties
-
postable / env - and / refresh endpoint supporting Spring Cloud
-
Easy log level management
-
Interact with JMX beans
-
View thread dump
-
View HTTP traces
-
View auditevents
-
View HTTP endpoints
-
View scheduled tasks
-
View and delete active sessions (using spring session)
-
View Flyway / Liquibase database migration
-
Download heapdump
-
Status change notification (via email, Slack, Hipchat,...)
-
Event log for state changes (non persistent)
Three, principle
Using spring boot activator to monitor applications
IV. integrated Eureka Registration Center
1. Create Eureka server and google by yourself
2. Create spring boot admin
This is a Spring Boot Admin Server.
pom.xml
<!--?xml version="1.0" encoding="UTF-8"?--> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>2.1.6.RELEASE</version> <relativepath /> <!-- lookup parent from repository --> </parent> <packaging>jar</packaging> <artifactid>spring-boot-admin</artifactid> <name>spring-boot-admin</name> <description>Spring Boot Admin Server end</description> <properties> <java.version>1.8</java.version> <spring-boot-admin.version>2.1.6</spring-boot-admin.version> <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>de.codecentric</groupid> <artifactid>spring-boot-admin-starter-server</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-eureka-client</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-security</artifactid> </dependency> <dependency> <groupid>org.jolokia</groupid> <artifactid>jolokia-core</artifactid> </dependency> </dependencies> <dependencymanagement> <dependencies> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-dependencies</artifactid> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupid>de.codecentric</groupid> <artifactid>spring-boot-admin-dependencies</artifactid> <version>${spring-boot-admin.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencymanagement> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> </plugins> </build> </project>
application.yml
spring: application: name: admin-server server: port: 1300 eureka: client: registryFetchIntervalSeconds: 5 service-url: defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/ instance: leaseRenewalIntervalInSeconds: 10 health-check-url-path: /actuator/health management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS
Start class SpringbootAdminServerApplication
@SpringBootApplication @EnableAdminServer @EnableEurekaClient public class ScAdminServerApplication { public static void main(String[] args) { SpringApplication.run( ScAdminServerApplication.class, args ); } }
3. Monitored end
The monitored end needs to release the end point
application.yml
spring: application: name: admin-client eureka: instance: leaseRenewalIntervalInSeconds: 10 health-check-url-path: /actuator/health client: registryFetchIntervalSeconds: 5 service-url: defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/ management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS server: port: 8762
admin will pull the registration information from Eureka and take the initiative to register.
V. integrating Spring Security
There are many ways to authenticate and authorize in a Web application, so Spring Boot Admin does not provide a default method. By default, Spring Boot Admin server UI provides a login page and a logout button. We use Spring Security to implement the security authentication that requires user name and password login.
The following dependencies need to be added to the pom file of the springboot admin project:
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-security</artifactid> </dependency>
Configure the spring security user name and password in the application.yml configuration file of the spingboot admin worker. At this time, you need to bring the metadata map information when registering the service, as follows:
spring: security: user: name: "admin" password: "admin" eureka: instance: metadata-map: user.name: ${spring.security.user.name} user.password: ${spring.security.user.password} startup: ${random.int} #needed to trigger info and endpoint update after restart
Write a configuration class SecuritySecureConfig to inherit WebSecurityConfigurerAdapter. The configuration is as follows:
/** * security To configure * @author wangjiafang * @date 2019/10/10 */ @Configuration public class SecuritySecureConfig extends WebSecurityConfigurerAdapter { private final String adminContextPath; public SecuritySecureConfig(AdminServerProperties adminServerProperties) { this.adminContextPath = adminServerProperties.getContextPath(); } @Override protected void configure(HttpSecurity http) throws Exception { // @formatter:off SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); successHandler.setTargetUrlParameter("redirectTo"); successHandler.setDefaultTargetUrl(adminContextPath + "/"); http.authorizeRequests() .antMatchers(adminContextPath + "/assets/**").permitAll() .antMatchers(adminContextPath + "/login").permitAll() .anyRequest().authenticated() .and() .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and() .logout().logoutUrl(adminContextPath + "/logout").and() .httpBasic().and() .csrf() .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .ignoringRequestMatchers( new AntPathRequestMatcher(adminContextPath + "/instances", HttpMethod.POST.toString()), new AntPathRequestMatcher(adminContextPath + "/instances/*", HttpMethod.DELETE.toString()), new AntPathRequestMatcher(adminContextPath + "/actuator/**") ); // @formatter:on } }
If you visit http:localhost:1300 again, the login interface will appear. The password is configured in the configuration file. The account admin password is admin.
Six. Notice
Custom notification + nail notification
1. Create a nail robot, get the token, how to create a nail robot, please google
2. Download sdk
Nailing officially provides a unified SDK. Using the SDK, you can easily call the server API, but it is not put in the public maven warehouse. You need to make your own download Then import it to the project or upload it to your built nexus private server
3. Custom Notifier
By extending AbstractEventNotifier or AbstractStatusChangeNotifier. Write a custom notifier in the springboot admin server project:
import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiRobotSendRequest; import com.taobao.api.ApiException; 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.AbstractEventNotifier; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; /** * Nail notification * @author wangjiafang * @date 2019/10/10 */ @Component @Slf4j public class CustomNotifier extends AbstractEventNotifier { /** * Message template */ private static final String template = "service name:%s(%s) \n state:%s(%s) \n service ip:%s"; @Value("${spring.admin.ding-talk-token}") private String dingTalkToken; public CustomNotifier(InstanceRepository repository) { super(repository); } @Override protected Mono<void> doNotify(InstanceEvent event, Instance instance) { return Mono.fromRunnable(() -> { if (event instanceof InstanceStatusChangedEvent) { log.info("Instance {} ({}) is {}", instance.getRegistration().getName(), event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus()); String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(); String messageText = null; switch (status) { // Health examination failed case "DOWN": log.info("Send the notice of failing health examination!"); messageText = String.format(template, instance.getRegistration().getName(),event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(),"Health examination failed",instance.getRegistration().getServiceUrl()); this.sendMessage(messageText); break; // Service offline case "OFFLINE": log.info("Send service offline notification!"); messageText = String.format(template, instance.getRegistration().getName(),event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(),"Service offline",instance.getRegistration().getServiceUrl()); this.sendMessage(messageText); break; //Service on-line case "UP": log.info("Send service online notice!"); messageText = String.format(template, instance.getRegistration().getName(),event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(),"Service on-line",instance.getRegistration().getServiceUrl()); this.sendMessage(messageText); break; // Service unknown exception case "UNKNOWN": log.info("Send service unknown exception notification!"); messageText = String.format(template, instance.getRegistration().getName(),event.getInstance(), ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(),"Service unknown exception",instance.getRegistration().getServiceUrl()); this.sendMessage(messageText); break; default: break; } } else { log.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(), event.getType()); } }); } /** * send message * @param messageText */ private void sendMessage(String messageText){ DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?access_token="+dingTalkToken); OapiRobotSendRequest request = new OapiRobotSendRequest(); request.setMsgtype("text"); OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); text.setContent(messageText); request.setText(text); try { client.execute(request); } catch (ApiException e) { log.info("[ERROR] sendMessage", e); } } }
7. View real-time logs
To view the real-time log in the springbootadmin panel, you need to specify the log output address in the project. For example, my log is under / logs / project name / project name - info.log.
logging: file: /logs/${spring.application.name}/${spring.application.name}-info.log