ruoyi-visual/ruoyi-monitor/Dockerfile
New file @@ -0,0 +1,17 @@ #FROM findepi/graalvm:java17-native FROM openjdk:17.0.2-oraclelinux8 MAINTAINER Lion Li RUN mkdir -p /ruoyi/monitor/logs WORKDIR /ruoyi/monitor ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" EXPOSE 9100 ADD ./target/ruoyi-monitor.jar ./app.jar ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar app.jar \ -XX:+HeapDumpOnOutOfMemoryError -Xlog:gc*,:time,tags,level -XX:+UseZGC ${JAVA_OPTS} ruoyi-visual/ruoyi-monitor/pom.xml
New file @@ -0,0 +1,74 @@ <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"> <parent> <groupId>org.dromara</groupId> <artifactId>ruoyi-visual</artifactId> <version>${revision}</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>ruoyi-monitor</artifactId> <description> ruoyi-monitor监控中心 </description> <dependencies> <!-- SpringBoot Admin --> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-server</artifactId> <version>${spring-boot-admin.version}</version> </dependency> <!-- SpringCloud Alibaba Nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- SpringCloud Alibaba Nacos Config --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>org.dromara</groupId> <artifactId>ruoyi-common-web</artifactId> </dependency> <!-- Spring Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project> ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/RuoYiMonitorApplication.java
New file @@ -0,0 +1,17 @@ package org.dromara.modules.monitor; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * 监控中心 * * @author ruoyi */ @SpringBootApplication public class RuoYiMonitorApplication { public static void main(String[] args) { SpringApplication.run(RuoYiMonitorApplication.class, args); System.out.println("(♥◠‿◠)ノ゙ 监控中心启动成功 ლ(´ڡ`ლ)゙ "); } } ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/config/AdminServerConfig.java
New file @@ -0,0 +1,31 @@ package org.dromara.modules.monitor.config; import de.codecentric.boot.admin.server.config.EnableAdminServer; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.task.TaskExecutorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; /** * springboot-admin server配置类 * * @author Lion Li */ @Configuration @EnableAdminServer public class AdminServerConfig { @Lazy @Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME) @ConditionalOnMissingBean(Executor.class) public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { return builder.build(); } } ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/config/WebSecurityConfigurer.java
New file @@ -0,0 +1,56 @@ package org.dromara.modules.monitor.config; import de.codecentric.boot.admin.server.config.AdminServerProperties; 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.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; /** * admin 监控 安全配置 * * @author Lion Li */ @EnableWebSecurity @Configuration public class WebSecurityConfigurer { private final String adminContextPath; public WebSecurityConfigurer(AdminServerProperties adminServerProperties) { this.adminContextPath = adminServerProperties.getContextPath(); } @Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); successHandler.setTargetUrlParameter("redirectTo"); successHandler.setDefaultTargetUrl(adminContextPath + "/"); return httpSecurity .headers((header) -> header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) .authorizeHttpRequests((authorize) -> authorize.requestMatchers( new AntPathRequestMatcher(adminContextPath + "/assets/**"), new AntPathRequestMatcher(adminContextPath + "/login"), new AntPathRequestMatcher("/actuator"), new AntPathRequestMatcher("/actuator/**") ).permitAll() .anyRequest().authenticated()) .formLogin((formLogin) -> formLogin.loginPage(adminContextPath + "/login").successHandler(successHandler)) .logout((logout) -> logout.logoutUrl(adminContextPath + "/logout")) .httpBasic(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable) .build(); } } ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/controller/PrometheusController.java
New file @@ -0,0 +1,67 @@ package org.dromara.modules.monitor.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * 对接 prometheus * * @author Lion Li */ @Slf4j @RestController @RequestMapping("/actuator/prometheus") public class PrometheusController { @Autowired private DiscoveryClient discoveryClient; /** * 从注册中心获取所有服务组装成 prometheus 的数据结构 */ @GetMapping("/sd") public List<Map<String, Object>> sd() { List<String> services = discoveryClient.getServices(); if (services == null || services.isEmpty()) { return new ArrayList<>(0); } List<Map<String, Object>> list = new ArrayList<>(); for (String service : services) { List<ServiceInstance> instances = discoveryClient.getInstances(service); List<String> targets = instances.stream().map(i -> i.getHost() + ":" + i.getPort()).collect(Collectors.toList()); Map<String, String> labels = new HashMap<>(2); // 数据来源(区分异地使用) // labels.put("__meta_datacenter", "beijing"); // 服务名 labels.put("__meta_prometheus_job", service); Map<String, Object> group = new HashMap<>(2); group.put("targets", targets); group.put("labels", labels); list.add(group); } return list; } /** * 接收 prometheus 报警消息 * * @param message 消息体 */ @PostMapping("/alerts") public ResponseEntity<Void> alerts(@RequestBody String message) { log.info("[prometheus] alert =>" + message); return ResponseEntity.ok().build(); } } ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/notifier/CustomNotifier.java
New file @@ -0,0 +1,43 @@ package org.dromara.modules.monitor.notifier; 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.domain.values.InstanceId; import de.codecentric.boot.admin.server.notify.AbstractEventNotifier; import io.micrometer.core.lang.NonNullApi; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; /** * 自定义事件通知处理 * * @author Lion Li */ @Slf4j @Component public class CustomNotifier extends AbstractEventNotifier { protected CustomNotifier(InstanceRepository repository) { super(repository); } @Override @SuppressWarnings("all") protected Mono<Void> doNotify(InstanceEvent event, Instance instance) { return Mono.fromRunnable(() -> { // 实例状态改变事件 if (event instanceof InstanceStatusChangedEvent) { String registName = instance.getRegistration().getName(); String instanceId = event.getInstance().getValue(); String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(); log.info("Instance Status Change: [{}],[{}],[{}]", registName, instanceId, status); } }); } } ruoyi-visual/ruoyi-monitor/src/main/resources/application.yml
New file @@ -0,0 +1,31 @@ # Tomcat server: port: 9100 # Spring spring: application: # 应用名称 name: ruoyi-monitor profiles: # 环境配置 active: @profiles.active@ --- # nacos 配置 spring: cloud: nacos: # nacos 服务地址 server-addr: @nacos.server@ discovery: # 注册组 group: @nacos.discovery.group@ namespace: ${spring.profiles.active} config: # 配置组 group: @nacos.config.group@ namespace: ${spring.profiles.active} config: import: - optional:nacos:application-common.yml - optional:nacos:${spring.application.name}.yml ruoyi-visual/ruoyi-monitor/src/main/resources/banner.txt
New file @@ -0,0 +1,10 @@ Spring Boot Version: ${spring-boot.version} Spring Application Name: ${spring.application.name} _ _ _ (_) (_)| | _ __ _ _ ___ _ _ _ ______ _ __ ___ ___ _ __ _ | |_ ___ _ __ | '__|| | | | / _ \ | | | || ||______|| '_ ` _ \ / _ \ | '_ \ | || __| / _ \ | '__| | | | |_| || (_) || |_| || | | | | | | || (_) || | | || || |_ | (_) || | |_| \__,_| \___/ \__, ||_| |_| |_| |_| \___/ |_| |_||_| \__| \___/ |_| __/ | |___/ ruoyi-visual/ruoyi-monitor/src/main/resources/logback-plus.xml
New file @@ -0,0 +1,28 @@ <?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <!-- 日志存放路径 --> <property name="log.path" value="logs/${project.artifactId}" /> <!-- 日志输出格式 --> <property name="console.log.pattern" value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/> <!-- 控制台输出 --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${console.log.pattern}</pattern> <charset>utf-8</charset> </encoder> </appender> <include resource="logback-common.xml" /> <include resource="logback-logstash.xml" /> <!-- 开启 skywalking 日志收集 --> <include resource="logback-skylog.xml" /> <!--系统操作日志--> <root level="info"> <appender-ref ref="console" /> </root> </configuration>