diff --git a/rition-center/api/pom.xml b/rition-center/api/pom.xml index d581c1a..2b9e8e7 100644 --- a/rition-center/api/pom.xml +++ b/rition-center/api/pom.xml @@ -48,10 +48,5 @@ panel ${revision} - - - org.springframework.boot - spring-boot-starter-data-redis - \ No newline at end of file diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/dto/request/AlertRuleAddRequest.java b/rition-center/api/src/main/java/rition/backend/api/v1/dto/request/AlertRuleAddRequest.java index 7a40a35..d0715ec 100644 --- a/rition-center/api/src/main/java/rition/backend/api/v1/dto/request/AlertRuleAddRequest.java +++ b/rition-center/api/src/main/java/rition/backend/api/v1/dto/request/AlertRuleAddRequest.java @@ -22,7 +22,7 @@ public class AlertRuleAddRequest { /** * 阈值 */ - private String threshold; + private Double threshold; /** * 触发方法,实时计算或定时计算 diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/AlertResponse.java b/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/AlertResponse.java new file mode 100644 index 0000000..b81ed09 --- /dev/null +++ b/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/AlertResponse.java @@ -0,0 +1,34 @@ +package rition.backend.api.v1.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AlertResponse { + /** + * id + */ + private Long id; + + /** + * 出现警告的实例id + */ + private String instanceId; + + /** + * 触发的规则 + */ + private Long rule; + + /** + * 警告出现的时间 + */ + private Instant time; +} diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/ContractResponse.java b/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/ContractResponse.java new file mode 100644 index 0000000..67a8d1c --- /dev/null +++ b/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/ContractResponse.java @@ -0,0 +1,34 @@ +package rition.backend.api.v1.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ContractResponse { + /** + * id + */ + private Long id; + + /** + * 联系方式 + */ + private String contract; + + /** + * 联系方式类型 + */ + private Integer type; + + /** + * create_time + */ + private Instant createTime; +} \ No newline at end of file diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/MetricDataResponse.java b/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/MetricDataResponse.java index e9d6c26..3978fb3 100644 --- a/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/MetricDataResponse.java +++ b/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/MetricDataResponse.java @@ -2,13 +2,11 @@ package rition.backend.api.v1.dto.response; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.time.Instant; import java.util.Map; @Data @@ -25,6 +23,5 @@ public class MetricDataResponse { /** * create_time */ - @JsonFormat() - private Instant time; + private Long time; } diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/RuleResponse.java b/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/RuleResponse.java new file mode 100644 index 0000000..7c6c681 --- /dev/null +++ b/rition-center/api/src/main/java/rition/backend/api/v1/dto/response/RuleResponse.java @@ -0,0 +1,54 @@ +package rition.backend.api.v1.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class RuleResponse { + /** + * 规则id + */ + private Long id; + + /** + * 需要计算的指标项或者表达式 + */ + private String expression; + + /** + * 触发条件 + */ + private Integer condition; + + /** + * 阈值 + */ + private Double threshold; + + /** + * 触发方法,实时计算或定时计算 + */ + private Integer trigger; + + /** + * 规则描述 + */ + private String description; + + /** + * create_time + */ + private Instant createTime; + + /** + * update_time + */ + private Instant updateTime; +} diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/panel/AlertHistoryController.java b/rition-center/api/src/main/java/rition/backend/api/v1/panel/AlertHistoryController.java new file mode 100644 index 0000000..1141c58 --- /dev/null +++ b/rition-center/api/src/main/java/rition/backend/api/v1/panel/AlertHistoryController.java @@ -0,0 +1,33 @@ +package rition.backend.api.v1.panel; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import rition.backend.api.v1.dto.response.Response; +import rition.common.data.dto.PagingData; +import rition.common.data.entity.AlertEntity; +import rition.service.panel.AlertHistoryService; + +@RestController +@RequestMapping("/panel/alerts") +public class AlertHistoryController { + private final AlertHistoryService alertHistoryService; + + public AlertHistoryController(AlertHistoryService alertHistoryService) { + this.alertHistoryService = alertHistoryService; + } + + @GetMapping("/list") + public Response> getContractList( + @RequestParam(value = "instance_id", required = false) String instanceId, + @RequestParam(value = "page", required = false, defaultValue = "1") Integer page, + @RequestParam(value = "page_size", required = false, defaultValue = "10") Integer pageSize + ) { + + PagingData alertEntityPagingData = new PagingData<>(page, pageSize); + var result = alertHistoryService.getAlertHistory(instanceId, alertEntityPagingData); + + return Response.success(result); + } +} diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/panel/AlertRuleController.java b/rition-center/api/src/main/java/rition/backend/api/v1/panel/AlertRuleController.java index 6b66e62..bccb079 100644 --- a/rition-center/api/src/main/java/rition/backend/api/v1/panel/AlertRuleController.java +++ b/rition-center/api/src/main/java/rition/backend/api/v1/panel/AlertRuleController.java @@ -3,24 +3,63 @@ package rition.backend.api.v1.panel; import org.springframework.web.bind.annotation.*; import rition.backend.api.v1.dto.request.AlertRuleAddRequest; import rition.backend.api.v1.dto.response.Response; +import rition.backend.api.v1.dto.response.RuleResponse; +import rition.common.data.dto.service.panel.AlertRuleAddDto; +import rition.common.data.entity.RuleEntity; +import rition.service.panel.AlertRuleService; + +import java.util.ArrayList; +import java.util.List; @RestController -@RequestMapping("/rules") +@RequestMapping("/panel/rules") public class AlertRuleController { - @GetMapping("/list/{instanceId}") - public Response getAlertRuleList(@PathVariable("instanceId") String instanceId) { - return Response.success(); + private final AlertRuleService alertRuleService; + + public AlertRuleController(AlertRuleService alertRuleService) { + this.alertRuleService = alertRuleService; + } + + @GetMapping("/list") + public Response> getAlertRuleList() { + List ruleEntityList = alertRuleService.getRule(); + List ruleResponseList = new ArrayList<>(ruleEntityList.size()); + for (RuleEntity ruleEntity : ruleEntityList) { + RuleResponse response = new RuleResponse(); + response.setId(ruleEntity.getId()); + response.setExpression(ruleEntity.getExpression()); + response.setCondition(ruleEntity.getCondition()); + response.setThreshold(ruleEntity.getThreshold()); + response.setTrigger(ruleEntity.getTrigger()); + response.setDescription(ruleEntity.getDescription()); + response.setCreateTime(ruleEntity.getCreateTime()); + response.setUpdateTime(ruleEntity.getUpdateTime()); + + ruleResponseList.add(response); + } + + return Response.success(ruleResponseList); } - @PostMapping("/add/{instanceId}") - public Response addAlertRule(@PathVariable("instanceId") String instanceId, - @RequestBody AlertRuleAddRequest alertRuleAddRequest) { + @PostMapping("/add") + public Response addAlertRule(@RequestBody AlertRuleAddRequest alertRuleAddRequest) { + AlertRuleAddDto alertRuleAddDto = new AlertRuleAddDto(); + alertRuleAddDto.setInstanceId(alertRuleAddRequest.getInstanceId()); + alertRuleAddDto.setExpression(alertRuleAddRequest.getExpression()); + alertRuleAddDto.setCondition(alertRuleAddRequest.getCondition()); + alertRuleAddDto.setThreshold(alertRuleAddRequest.getThreshold()); + alertRuleAddDto.setTrigger(alertRuleAddRequest.getTrigger()); + alertRuleAddDto.setDescription(alertRuleAddRequest.getDescription()); + + alertRuleService.addAlertRule(alertRuleAddDto); + return Response.success(); } - @PostMapping("/delete/{instanceId}") - public Response deleteAlertRule(@PathVariable("instanceId") String instanceId, - @RequestParam("id") String alertRuleId) { + @PostMapping("/delete") + public Response deleteAlertRule(@RequestParam("id") Long alertRuleId) { + alertRuleService.deleteRule(alertRuleId); + return Response.success(); } } diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/panel/ContractController.java b/rition-center/api/src/main/java/rition/backend/api/v1/panel/ContractController.java index 62a5806..e209810 100644 --- a/rition-center/api/src/main/java/rition/backend/api/v1/panel/ContractController.java +++ b/rition-center/api/src/main/java/rition/backend/api/v1/panel/ContractController.java @@ -2,25 +2,56 @@ package rition.backend.api.v1.panel; import org.springframework.web.bind.annotation.*; import rition.backend.api.v1.dto.request.ContractAddRequest; +import rition.backend.api.v1.dto.response.ContractResponse; import rition.backend.api.v1.dto.response.Response; +import rition.common.data.dto.service.panel.ContractAddDto; +import rition.common.data.entity.ContractEntity; +import rition.service.panel.ContractService; + +import java.util.ArrayList; +import java.util.List; @RestController -@RequestMapping("/contract") +@RequestMapping("/panel/contract") public class ContractController { - @GetMapping("/list/{instanceId}") - public Response getContractList(@PathVariable("instanceId") String instanceId) { - return Response.success(); + private final ContractService contractService; + + public ContractController(ContractService contractService) { + this.contractService = contractService; + } + + @GetMapping("/list") + public Response> getContractList() { + List contractEntityList = contractService.getContractList(); + List responseList = new ArrayList<>(contractEntityList.size()); + for (var contractEntity : contractEntityList) { + ContractResponse response = new ContractResponse(); + response.setId(contractEntity.getId()); + response.setContract(contractEntity.getContract()); + response.setType(contractEntity.getType()); + response.setCreateTime(contractEntity.getCreateTime()); + + responseList.add(response); + } + + return Response.success(responseList); } - @PostMapping("/add/{instanceId}") - public Response addContract(@PathVariable("instanceId") String instanceId, - @RequestBody ContractAddRequest contractAddRequest) { + @PostMapping("/add") + public Response addContract(@RequestBody ContractAddRequest contractAddRequest) { + ContractAddDto contractAddDto = new ContractAddDto(); + contractAddDto.setContract(contractAddRequest.getContract()); + contractAddDto.setType(contractAddRequest.getType()); + + contractService.addContract(contractAddDto); + return Response.success(); } - @PostMapping("/delete/{instanceId}") - public Response deleteContract(@PathVariable("instanceId") String instanceId, - @RequestParam("id") String contractId) { + @PostMapping("/delete") + public Response deleteContract(@RequestParam("id") Long contractId) { + contractService.deleteContract(contractId); + return Response.success(); } } diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/panel/MetricsViewController.java b/rition-center/api/src/main/java/rition/backend/api/v1/panel/MetricsViewController.java index 60c5fb5..f72fa6b 100644 --- a/rition-center/api/src/main/java/rition/backend/api/v1/panel/MetricsViewController.java +++ b/rition-center/api/src/main/java/rition/backend/api/v1/panel/MetricsViewController.java @@ -1,34 +1,61 @@ package rition.backend.api.v1.panel; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.web.bind.annotation.*; import rition.backend.api.v1.dto.request.MetricDataRequest; import rition.backend.api.v1.dto.response.MetricDataResponse; import rition.backend.api.v1.dto.response.Response; +import rition.common.data.dto.service.MetricDataDto; import rition.common.data.entity.MetricRecordEntity; +import rition.common.data.enums.Constants; import rition.service.panel.MetricService; import java.time.Instant; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +@Slf4j @RestController @RequestMapping("/panel/metrics") public class MetricsViewController { private final MetricService metricService; + private final RedisTemplate redisTemplate; - public MetricsViewController(MetricService metricService) { + public MetricsViewController(MetricService metricService, RedisTemplate redisTemplate) { this.metricService = metricService; + this.redisTemplate = redisTemplate; } - @GetMapping("/list") + @PostMapping("/list") public Response> getMetrics(@RequestBody MetricDataRequest metricDataRequest) { + // 如果未给定范围参数,则使用最近一小时的数据 + if (metricDataRequest.getStart() == null || metricDataRequest.getEnd() == null) { + List recentMetricDataList = + redisTemplate.opsForList().range( + Constants.RedisKeys.RECENT_METRIC_CACHE, 0, Constants.MAX_METRIC_CACHE_NUM + ); + if (recentMetricDataList == null) { + return Response.success(new ArrayList<>()); + } + + List responseList = new ArrayList<>(recentMetricDataList.size()); + for (Object recentMetricData : recentMetricDataList) { + var data = (MetricDataDto) recentMetricData; + responseList.add(MetricDataResponse.builder() + .metricData(data.getData()) + .time(data.getTimestamp()) + .build()); + } + + return Response.success(responseList); + } + var entityResult = metricService.getMetricDataRange( metricDataRequest.getInstanceId(), - metricDataRequest.getMetricItems(), + this.filterMetricItems(metricDataRequest.getMetricItems()), Instant.ofEpochMilli(metricDataRequest.getStart()), Instant.ofEpochMilli(metricDataRequest.getEnd()) ); @@ -38,11 +65,52 @@ public class MetricsViewController { for (MetricRecordEntity entity : entityResult) { responseList.add(MetricDataResponse.builder() .metricData(entity.getMetricData()) - .time(entity.getTime()) + .time(entity.getTime().toEpochMilli()) .build() ); } return Response.success(responseList); } + + + private static final HashSet allowedMetricItems = new HashSet<>(22); + + static { + allowedMetricItems.add("up"); + allowedMetricItems.add("node_load5"); + allowedMetricItems.add("node_sockstat_TCP_tw"); + allowedMetricItems.add("node_cpu_seconds_total"); + allowedMetricItems.add("node_memory_Cached_bytes"); + allowedMetricItems.add("node_memory_Buffers_bytes"); + allowedMetricItems.add("node_memory_MemFree_bytes"); + allowedMetricItems.add("node_disk_read_bytes_total"); + allowedMetricItems.add("node_filesystem_free_bytes"); + allowedMetricItems.add("node_filesystem_size_bytes"); + allowedMetricItems.add("node_memory_MemTotal_bytes"); + allowedMetricItems.add("node_netstat_Tcp_CurrEstab"); + allowedMetricItems.add("node_filesystem_avail_bytes"); + allowedMetricItems.add("node_disk_written_bytes_total"); + allowedMetricItems.add("node_disk_reads_completed_total"); + allowedMetricItems.add("node_network_receive_drop_total"); + allowedMetricItems.add("node_disk_writes_completed_total"); + allowedMetricItems.add("node_network_receive_bytes_total"); + allowedMetricItems.add("node_network_transmit_drop_total"); + allowedMetricItems.add("node_network_transmit_bytes_total"); + allowedMetricItems.add("node_network_receive_packets_total"); + allowedMetricItems.add("node_network_transmit_packets_total"); + } + + private List filterMetricItems(List metricItems) { + List filteredMetricItems = new ArrayList<>(metricItems.size()); + for (String metricItem : metricItems) { + if (allowedMetricItems.contains(metricItem)) { + filteredMetricItems.add(metricItem); + } else { + log.warn("[MetricService]: 请求的指标值含有非允许的指标值:{}", metricItem); + } + } + + return filteredMetricItems; + } } diff --git a/rition-center/api/src/main/java/rition/backend/api/v1/panel/PanelController.java b/rition-center/api/src/main/java/rition/backend/api/v1/panel/PanelController.java deleted file mode 100644 index eda774f..0000000 --- a/rition-center/api/src/main/java/rition/backend/api/v1/panel/PanelController.java +++ /dev/null @@ -1,10 +0,0 @@ -package rition.backend.api.v1.panel; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/panel") -public class PanelController { - -} diff --git a/rition-center/api/src/main/java/rition/backend/configure/OpenAPIConfigure.java b/rition-center/api/src/main/java/rition/backend/configure/OpenAPIConfigure.java new file mode 100644 index 0000000..ce3681b --- /dev/null +++ b/rition-center/api/src/main/java/rition/backend/configure/OpenAPIConfigure.java @@ -0,0 +1,35 @@ +package rition.backend.configure; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.servers.Server; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; + +@Getter +@Component +@Configuration +public class OpenAPIConfigure { + private String serverUrl; + + @Value("${wusthelper.docs.server-url:/}") + public void setServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + } + + @Bean + public OpenAPI openAPI() { + var info = new Info() + .title("Rition-center") + .description("Rition-center api") + .version("v1"); + + return new OpenAPI() + .info(info); + } +} diff --git a/rition-center/api/src/main/java/rition/backend/configure/WebAppConfig.java b/rition-center/api/src/main/java/rition/backend/configure/WebMvcConfigure.java similarity index 70% rename from rition-center/api/src/main/java/rition/backend/configure/WebAppConfig.java rename to rition-center/api/src/main/java/rition/backend/configure/WebMvcConfigure.java index 72b7b6c..abc4376 100644 --- a/rition-center/api/src/main/java/rition/backend/configure/WebAppConfig.java +++ b/rition-center/api/src/main/java/rition/backend/configure/WebMvcConfigure.java @@ -5,6 +5,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import rition.backend.api.interceptor.ResponseIdInterceptor; import rition.backend.api.resolver.RequestIdArgumentResolver; @@ -12,24 +13,24 @@ import java.util.List; @Configuration @SpringBootConfiguration -public class WebAppConfig extends WebMvcConfigurationSupport { +public class WebMvcConfigure implements WebMvcConfigurer { private final RequestIdArgumentResolver requestIdArgumentResolver; private final ResponseIdInterceptor requestIdInterceptor; - public WebAppConfig(RequestIdArgumentResolver requestIdArgumentResolver, - ResponseIdInterceptor requestIdInterceptor) { + public WebMvcConfigure(RequestIdArgumentResolver requestIdArgumentResolver, + ResponseIdInterceptor requestIdInterceptor) { this.requestIdArgumentResolver = requestIdArgumentResolver; this.requestIdInterceptor = requestIdInterceptor; } @Override - protected void addArgumentResolvers(List argumentResolvers) { + public void addArgumentResolvers(List argumentResolvers) { argumentResolvers.add(requestIdArgumentResolver); } @Override - protected void addInterceptors(InterceptorRegistry registry) { + public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(requestIdInterceptor) .addPathPatterns("/**"); } diff --git a/rition-center/api/src/main/java/rition/backend/service/MetricDataCollectingService.java b/rition-center/api/src/main/java/rition/backend/service/MetricDataCollectingService.java index f350cec..1d499fe 100644 --- a/rition-center/api/src/main/java/rition/backend/service/MetricDataCollectingService.java +++ b/rition-center/api/src/main/java/rition/backend/service/MetricDataCollectingService.java @@ -6,6 +6,7 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import rition.common.data.dto.log.RequestProcessTraceRecord; import rition.common.data.dto.service.MetricDataDto; +import rition.common.data.enums.Constants; import rition.service.collector.MetricCollectingService; import java.util.Map; @@ -29,8 +30,6 @@ public class MetricDataCollectingService { this.redisTemplate = redisTemplate; } - private static final String PROCESS_TRACE_REDIS_KEY_FORMAT = "rition:request:trace:%s"; - /** * 接收处理好的监控指标数据,异步处理,请求发送后,处理状态使用requestId追踪,处理结果放置于redis * @@ -55,7 +54,7 @@ public class MetricDataCollectingService { } try { - redisTemplate.opsForValue().set(PROCESS_TRACE_REDIS_KEY_FORMAT.formatted(requestId), record); + redisTemplate.opsForValue().set(Constants.RedisKeys.PROCESS_TRACE.formatted(requestId), record); } catch (Exception e2) { log.error("请求结果保存出现异常: ", e2); log.error("请求结果:{}", record); diff --git a/rition-center/api/src/main/java/rition/backend/service/panel/PanelMetricService.java b/rition-center/api/src/main/java/rition/backend/service/panel/PanelMetricService.java new file mode 100644 index 0000000..bd41837 --- /dev/null +++ b/rition-center/api/src/main/java/rition/backend/service/panel/PanelMetricService.java @@ -0,0 +1,7 @@ +package rition.backend.service.panel; + +import org.springframework.stereotype.Service; + +@Service +public class PanelMetricService { +} diff --git a/rition-center/api/src/main/resources/application.yml b/rition-center/api/src/main/resources/application.yml index c5b4a68..59b7a05 100644 --- a/rition-center/api/src/main/resources/application.yml +++ b/rition-center/api/src/main/resources/application.yml @@ -11,3 +11,6 @@ spring: host: ${REDIS_HOST:127.0.0.1} port: ${REDIS_PORT:6379} password: ${REDIS_PASSWORD:Test2333!} +logging: + level: + rition: debug \ No newline at end of file diff --git a/rition-center/api/src/test/java/panel/MetricServiceTest.java b/rition-center/api/src/test/java/panel/MetricServiceTest.java new file mode 100644 index 0000000..7859f37 --- /dev/null +++ b/rition-center/api/src/test/java/panel/MetricServiceTest.java @@ -0,0 +1,39 @@ +package panel; + +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.AutoConfigureMybatis; +import org.mybatis.spring.boot.test.autoconfigure.MybatisTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; +import rition.backend.RitionBackendMain; +import rition.common.data.dao.mapper.MetricRecordMapper; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@MybatisTest +@ContextConfiguration(classes = RitionBackendMain.class) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +public class MetricServiceTest { + @Autowired + MetricRecordMapper metricRecordMapper; + + @Test + public void testGetMetricRecord() { + List metricItems = new ArrayList<>(); + metricItems.add("node_network_receive_packets_total"); + metricItems.add("node_sockstat_TCP_tw"); + var result = metricRecordMapper.getMetricDataGroupByHour( + "7273a1ea-0089-4674-b606-b1b8d809d866", + metricItems, + Instant.parse("2024-04-17T14:00:00.00Z"), + Instant.parse("2024-04-17T16:00:00.00Z") + ); + + System.out.println(Arrays.toString(result.toArray())); + } +} diff --git a/rition-center/common/src/main/java/rition/common/configure/RedisLuaConfigure.java b/rition-center/common/src/main/java/rition/common/configure/RedisLuaConfigure.java new file mode 100644 index 0000000..21a2ff3 --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/configure/RedisLuaConfigure.java @@ -0,0 +1,21 @@ +package rition.common.configure; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.scripting.support.ResourceScriptSource; + +@Configuration +public class RedisLuaConfigure { + @Bean(name = "constLenQueueRedisScript") + public RedisScript constLenQueueRedisScript() { + Resource luaResource = new ClassPathResource("redis/const_len_queue.lua"); + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setScriptSource(new ResourceScriptSource(luaResource)); + + return redisScript; + } +} diff --git a/rition-center/common/src/main/java/rition/common/data/dao/mapper/AlertMapper.java b/rition-center/common/src/main/java/rition/common/data/dao/mapper/AlertMapper.java new file mode 100644 index 0000000..b69bf72 --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/data/dao/mapper/AlertMapper.java @@ -0,0 +1,9 @@ +package rition.common.data.dao.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import rition.common.data.entity.AlertEntity; + +@Mapper +public interface AlertMapper extends BaseMapper { +} diff --git a/rition-center/common/src/main/java/rition/common/data/dao/mapper/ContractMapper.java b/rition-center/common/src/main/java/rition/common/data/dao/mapper/ContractMapper.java new file mode 100644 index 0000000..652a20d --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/data/dao/mapper/ContractMapper.java @@ -0,0 +1,7 @@ +package rition.common.data.dao.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import rition.common.data.entity.ContractEntity; + +public interface ContractMapper extends BaseMapper { +} diff --git a/rition-center/common/src/main/java/rition/common/data/dao/mapper/MetricRecordMapper.java b/rition-center/common/src/main/java/rition/common/data/dao/mapper/MetricRecordMapper.java index 3534439..ac7b762 100644 --- a/rition-center/common/src/main/java/rition/common/data/dao/mapper/MetricRecordMapper.java +++ b/rition-center/common/src/main/java/rition/common/data/dao/mapper/MetricRecordMapper.java @@ -19,4 +19,17 @@ public interface MetricRecordMapper extends BaseMapper { @Param("metricItems") List metricItems, @Param("startTime") Instant startTime, @Param("endTime") Instant endTime ); + + List getMetricDataGroupByMinute( + @Param("instanceId") String instanceId, + @Param("metricItems") List metricItems, + @Param("startTime") Instant startTime, @Param("endTime") Instant endTime + ); + + List getMetricDataGroupBySomeMinute( + @Param("minutes") Integer minutes, + @Param("instanceId") String instanceId, + @Param("metricItems") List metricItems, + @Param("startTime") Instant startTime, @Param("endTime") Instant endTime + ); } diff --git a/rition-center/common/src/main/java/rition/common/data/dao/mapper/RuleMapper.java b/rition-center/common/src/main/java/rition/common/data/dao/mapper/RuleMapper.java new file mode 100644 index 0000000..44e6156 --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/data/dao/mapper/RuleMapper.java @@ -0,0 +1,9 @@ +package rition.common.data.dao.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import rition.common.data.entity.RuleEntity; + +@Mapper +public interface RuleMapper extends BaseMapper { +} diff --git a/rition-center/common/src/main/java/rition/common/data/dto/PagingData.java b/rition-center/common/src/main/java/rition/common/data/dto/PagingData.java new file mode 100644 index 0000000..df4a11a --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/data/dto/PagingData.java @@ -0,0 +1,52 @@ +package rition.common.data.dto; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Collection; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PagingData { + private long currentPage; + private long pageSize; + private long totalPage; + + private long totalResult; + + private Collection data; + + public PagingData(long currentPage, long pageSize) { + this.currentPage = currentPage; + this.pageSize = pageSize; + } + + public PagingData copy() { + PagingData pagingData = new PagingData<>(); + + pagingData.setCurrentPage(this.getCurrentPage()); + pagingData.setPageSize(this.getPageSize()); + pagingData.setTotalPage(this.getTotalPage()); + pagingData.setTotalResult(this.getTotalResult()); + pagingData.setData(this.getData()); + + return pagingData; + } + + public static PagingData copyOnlyPagingValues(PagingData source) { + PagingData pagingData = new PagingData<>(); + + pagingData.setCurrentPage(source.getCurrentPage()); + pagingData.setPageSize(source.getPageSize()); + pagingData.setTotalPage(source.getTotalPage()); + pagingData.setTotalResult(source.getTotalResult()); + + return pagingData; + } +} + diff --git a/rition-center/common/src/main/java/rition/common/data/dto/service/AlertRuleDto.java b/rition-center/common/src/main/java/rition/common/data/dto/service/AlertRuleDto.java new file mode 100644 index 0000000..410f9c9 --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/data/dto/service/AlertRuleDto.java @@ -0,0 +1,54 @@ +package rition.common.data.dto.service; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class AlertRuleDto { + /** + * 规则id + */ + private Long id; + + /** + * 规则对应的实例id + */ + private String instanceId; + + /** + * 需要计算的指标项或者表达式 + */ + private String expression; + + /** + * 触发条件 + */ + private Integer condition; + + /** + * 阈值 + */ + private Double threshold; + + /** + * 触发方法,实时计算或定时计算 + */ + private Integer trigger; + + /** + * 规则描述 + */ + private String description; + + /** + * create_time + */ + private Instant createTime; +} diff --git a/rition-center/common/src/main/java/rition/common/data/dto/service/panel/AlertRuleAddDto.java b/rition-center/common/src/main/java/rition/common/data/dto/service/panel/AlertRuleAddDto.java new file mode 100644 index 0000000..64d27c7 --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/data/dto/service/panel/AlertRuleAddDto.java @@ -0,0 +1,36 @@ +package rition.common.data.dto.service.panel; + +import lombok.Data; + +@Data +public class AlertRuleAddDto { + /** + * 规则对应的实例id + */ + private String instanceId; + + /** + * 需要计算的指标项或者表达式 + */ + private String expression; + + /** + * 触发条件 + */ + private Integer condition; + + /** + * 阈值 + */ + private Double threshold; + + /** + * 触发方法,实时计算或定时计算 + */ + private Integer trigger; + + /** + * 规则描述 + */ + private String description; +} diff --git a/rition-center/common/src/main/java/rition/common/data/dto/service/panel/AlertRuleDto.java b/rition-center/common/src/main/java/rition/common/data/dto/service/panel/AlertRuleDto.java new file mode 100644 index 0000000..5006c36 --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/data/dto/service/panel/AlertRuleDto.java @@ -0,0 +1,36 @@ +package rition.common.data.dto.service.panel; + +import lombok.Data; + +@Data +public class AlertRuleDto { + /** + * 规则对应的实例id + */ + private String instanceId; + + /** + * 需要计算的指标项或者表达式 + */ + private String expression; + + /** + * 触发条件 + */ + private Integer condition; + + /** + * 阈值 + */ + private Double threshold; + + /** + * 触发方法,实时计算或定时计算 + */ + private Integer trigger; + + /** + * 规则描述 + */ + private String description; +} diff --git a/rition-center/common/src/main/java/rition/common/data/dto/service/panel/ContractAddDto.java b/rition-center/common/src/main/java/rition/common/data/dto/service/panel/ContractAddDto.java new file mode 100644 index 0000000..d3110f8 --- /dev/null +++ b/rition-center/common/src/main/java/rition/common/data/dto/service/panel/ContractAddDto.java @@ -0,0 +1,17 @@ +package rition.common.data.dto.service.panel; + +import lombok.Data; + +@Data +public class ContractAddDto { + + /** + * 联系方式 + */ + private String contract; + + /** + * 联系方式类型 + */ + private Integer type; +} diff --git a/rition-center/common/src/main/java/rition/common/data/entity/ContractEntity.java b/rition-center/common/src/main/java/rition/common/data/entity/ContractEntity.java index 4b03900..bef2b55 100644 --- a/rition-center/common/src/main/java/rition/common/data/entity/ContractEntity.java +++ b/rition-center/common/src/main/java/rition/common/data/entity/ContractEntity.java @@ -22,11 +22,6 @@ public class ContractEntity { */ private Long id; - /** - * 绑定的实例 - */ - private String instanceId; - /** * 联系方式 */ diff --git a/rition-center/common/src/main/java/rition/common/data/entity/RuleEntity.java b/rition-center/common/src/main/java/rition/common/data/entity/RuleEntity.java index a789de7..7795bfa 100644 --- a/rition-center/common/src/main/java/rition/common/data/entity/RuleEntity.java +++ b/rition-center/common/src/main/java/rition/common/data/entity/RuleEntity.java @@ -22,11 +22,6 @@ public class RuleEntity { */ private Long id; - /** - * 规则对应的实例id - */ - private String instanceId; - /** * 需要计算的指标项或者表达式 */ diff --git a/rition-center/common/src/main/java/rition/common/data/enums/Constants.java b/rition-center/common/src/main/java/rition/common/data/enums/Constants.java index 6936064..a1a8c69 100644 --- a/rition-center/common/src/main/java/rition/common/data/enums/Constants.java +++ b/rition-center/common/src/main/java/rition/common/data/enums/Constants.java @@ -9,4 +9,15 @@ public class Constants { public static final Integer NORMAL = 0; public static final Integer DELETED = 1; } + + public static class RedisKeys { + public static final String RULE_CACHE = "rition:cache:rule"; + public static final String RECENT_METRIC_CACHE = "rition:cache:metrics"; + public static final String PROCESS_TRACE = "rition:request:trace:%s"; + } + + /** + * 缓存最近一小时的数据 + */ + public static final int MAX_METRIC_CACHE_NUM = 3600/5; } diff --git a/rition-center/common/src/main/java/rition/common/exception/ServiceException.java b/rition-center/common/src/main/java/rition/common/exception/ServiceException.java index 874dfe9..d6c2e22 100644 --- a/rition-center/common/src/main/java/rition/common/exception/ServiceException.java +++ b/rition-center/common/src/main/java/rition/common/exception/ServiceException.java @@ -43,4 +43,14 @@ public class ServiceException extends RuntimeException { public static void error(int code) throws ServiceException { throw new ServiceException(code); } + + /** + * 直接按错误码抛出异常 + * + * @param code 错误码 + * @throws ServiceException . + */ + public static void error(ServiceCode code) throws ServiceException { + throw new ServiceException(code); + } } diff --git a/rition-center/common/src/main/java/rition/common/exception/code/ServiceCode.java b/rition-center/common/src/main/java/rition/common/exception/code/ServiceCode.java index ba592ad..2e0f888 100644 --- a/rition-center/common/src/main/java/rition/common/exception/code/ServiceCode.java +++ b/rition-center/common/src/main/java/rition/common/exception/code/ServiceCode.java @@ -13,7 +13,10 @@ public enum ServiceCode { ParamWrong(10_00_03, "参数错误"), PermissionDenied(10_00_04, "权限不足"), TokenInvalid(10_00_05, "用户凭据无效,登录态失效"), - UnknownErr(10_00_06, "服务器内部错误"); + UnknownErr(10_00_06, "服务器内部错误"), + + ContractTooManyData(11_00_00, "联系通知信息过多"), + ; private final int code; diff --git a/rition-center/common/src/main/resources/mapper/MetricRecordMapper.xml b/rition-center/common/src/main/resources/mapper/MetricRecordMapper.xml index 02badd8..c27b7d2 100644 --- a/rition-center/common/src/main/resources/mapper/MetricRecordMapper.xml +++ b/rition-center/common/src/main/resources/mapper/MetricRecordMapper.xml @@ -37,4 +37,40 @@ --> + + + + \ No newline at end of file diff --git a/rition-center/common/src/main/resources/redis/const_len_queue.lua b/rition-center/common/src/main/resources/redis/const_len_queue.lua new file mode 100644 index 0000000..aa74cf2 --- /dev/null +++ b/rition-center/common/src/main/resources/redis/const_len_queue.lua @@ -0,0 +1,7 @@ +local key = KEYS[1] +local max_len = tonumber(ARGV[1]) +local val = ARGV[2] +if (redis.call('llen', key) > max_len) then + redis.call('lpop', key) +end +redis.call('rpush', key, val) \ No newline at end of file diff --git a/rition-center/pom.xml b/rition-center/pom.xml index 6f5a375..1166bee 100644 --- a/rition-center/pom.xml +++ b/rition-center/pom.xml @@ -33,6 +33,8 @@ 3.0.3 3.5.16 3.5.6 + + 2.5.0 @@ -71,6 +73,23 @@ jackson-datatype-jsr310 + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${spring-doc.version} + + + org.springdoc + springdoc-openapi-starter-webmvc-api + ${spring-doc.version} + + com.github.yitter diff --git a/rition-center/service/collector/src/main/java/rition/service/collector/MetricCollectingService.java b/rition-center/service/collector/src/main/java/rition/service/collector/MetricCollectingService.java index 92eaebe..cec5ed7 100644 --- a/rition-center/service/collector/src/main/java/rition/service/collector/MetricCollectingService.java +++ b/rition-center/service/collector/src/main/java/rition/service/collector/MetricCollectingService.java @@ -2,12 +2,16 @@ package rition.service.collector; import com.github.yitter.idgen.YitIdHelper; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.RedisScript; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Service; +import rition.common.data.dao.mapper.MetricRecordMapper; import rition.common.data.dto.service.MetricDataDto; import rition.common.data.entity.MetricRecordEntity; +import rition.common.data.enums.Constants; import rition.service.collector.configure.CollectorServiceKafkaConfigure; -import rition.common.data.dao.mapper.MetricRecordMapper; import java.time.Instant; import java.util.ArrayList; @@ -25,13 +29,23 @@ public class MetricCollectingService { private final String collectedDataTopic; private final MetricRecordMapper metricRecordMapper; + private final RedisTemplate redisTemplate; + + private final RedisScript constLenQueueRedisScript; public MetricCollectingService(KafkaTemplate kafkaTemplate, CollectorServiceKafkaConfigure collectorServiceKafkaConfigure, - MetricRecordMapper metricRecordMapper) { + MetricRecordMapper metricRecordMapper, + RedisTemplate redisTemplate, + + @Qualifier("constLenQueueRedisScript") RedisScript constLenQueueRedisScript) { + this.kafkaTemplate = kafkaTemplate; this.collectedDataTopic = collectorServiceKafkaConfigure.getDataCollecting().getTopic(); this.metricRecordMapper = metricRecordMapper; + this.redisTemplate = redisTemplate; + + this.constLenQueueRedisScript = constLenQueueRedisScript; } private static final int METRIC_NUMS = 22; @@ -64,7 +78,7 @@ public class MetricCollectingService { // kafka发布 kafkaTemplate.send(this.collectedDataTopic, metricDataDto); - // 分批入库 + // 分批入库,只是针对大批量请求的处理 batchSaveEntityList.add(entity); if (turn >= DEFAULT_DB_BATCH_SIZE) { metricRecordMapper.insertBatchSomeColumn(batchSaveEntityList); @@ -74,6 +88,13 @@ public class MetricCollectingService { } else { turn++; } + + // 缓存最近数据 + redisTemplate.execute( + constLenQueueRedisScript, + List.of(Constants.RedisKeys.RECENT_METRIC_CACHE), + Constants.MAX_METRIC_CACHE_NUM, metricDataDto + ); } } diff --git a/rition-center/service/panel/src/main/java/rition/service/panel/AlertHistoryService.java b/rition-center/service/panel/src/main/java/rition/service/panel/AlertHistoryService.java new file mode 100644 index 0000000..b11d5a4 --- /dev/null +++ b/rition-center/service/panel/src/main/java/rition/service/panel/AlertHistoryService.java @@ -0,0 +1,48 @@ +package rition.service.panel; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.stereotype.Service; +import rition.common.data.dao.mapper.AlertMapper; +import rition.common.data.dto.PagingData; +import rition.common.data.entity.AlertEntity; +import rition.common.data.enums.Constants; + +@Service +public class AlertHistoryService { + private final AlertMapper alertMapper; + + public AlertHistoryService(AlertMapper alertMapper) { + this.alertMapper = alertMapper; + } + + /** + * 分页获取报警信息 + * + * @param instanceId 实例id + * @param pagingData 分页数据,查询完成后会对此对象进行修改 + * @return 分页数据,含结果,实际上与参数里的pagingData是同一个对象 + */ + public PagingData getAlertHistory(String instanceId, PagingData pagingData) { + LambdaQueryWrapper query; + if (instanceId != null) { + query = new LambdaQueryWrapper() + .eq(AlertEntity::getInstanceId, instanceId) + .eq(AlertEntity::getStatus, Constants.EntityCommonStatus.NORMAL); + } else { + query = new LambdaQueryWrapper() + .eq(AlertEntity::getStatus, Constants.EntityCommonStatus.NORMAL); + } + + Page page = new Page<>(pagingData.getCurrentPage(), pagingData.getPageSize()); + var result = alertMapper.selectPage(page, query); + + pagingData.setData(result.getRecords()); + pagingData.setTotalResult(result.getTotal()); + pagingData.setTotalPage(result.getPages()); + pagingData.setCurrentPage(result.getCurrent()); + pagingData.setPageSize(result.getSize()); + + return pagingData; + } +} diff --git a/rition-center/service/panel/src/main/java/rition/service/panel/AlertRuleService.java b/rition-center/service/panel/src/main/java/rition/service/panel/AlertRuleService.java new file mode 100644 index 0000000..bc0cad9 --- /dev/null +++ b/rition-center/service/panel/src/main/java/rition/service/panel/AlertRuleService.java @@ -0,0 +1,78 @@ +package rition.service.panel; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.github.yitter.idgen.YitIdHelper; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import rition.common.data.dao.mapper.RuleMapper; +import rition.common.data.dto.service.AlertRuleDto; +import rition.common.data.dto.service.panel.AlertRuleAddDto; +import rition.common.data.entity.RuleEntity; +import rition.common.data.enums.Constants; + +import java.time.Instant; +import java.util.List; + +@Service +public class AlertRuleService { + + private final RuleMapper ruleMapper; + private final RedisTemplate redisTemplate; + + public AlertRuleService(RuleMapper ruleMapper, + RedisTemplate redisTemplate) { + this.ruleMapper = ruleMapper; + this.redisTemplate = redisTemplate; + } + + public void addAlertRule(AlertRuleAddDto alertRuleAddDto) { + RuleEntity ruleEntity = new RuleEntity(); + ruleEntity.setId(YitIdHelper.nextId()); + ruleEntity.setExpression(alertRuleAddDto.getExpression()); + ruleEntity.setCondition(alertRuleAddDto.getCondition()); + ruleEntity.setThreshold(alertRuleAddDto.getThreshold()); + ruleEntity.setTrigger(alertRuleAddDto.getTrigger()); + ruleEntity.setDescription(alertRuleAddDto.getDescription()); + + var now = Instant.now(); + ruleEntity.setCreateTime(now); + ruleEntity.setUpdateTime(now); + ruleEntity.setStatus(Constants.EntityCommonStatus.NORMAL); + + ruleMapper.insert(ruleEntity); + + AlertRuleDto alertRuleDto = new AlertRuleDto(); + alertRuleDto.setId(ruleEntity.getId()); + alertRuleDto.setExpression(ruleEntity.getExpression()); + alertRuleDto.setCondition(ruleEntity.getCondition()); + alertRuleDto.setThreshold(ruleEntity.getThreshold()); + alertRuleDto.setTrigger(ruleEntity.getTrigger()); + alertRuleDto.setDescription(ruleEntity.getDescription()); + alertRuleDto.setCreateTime(now); + + // 规则缓存到redis + redisTemplate.opsForHash().put(Constants.RedisKeys.RULE_CACHE, alertRuleDto.getId(), alertRuleDto); + } + + public List getRule() { + var query = new LambdaQueryWrapper() + .eq(RuleEntity::getStatus, Constants.EntityCommonStatus.NORMAL); + + return ruleMapper.selectList(query); + } + + public int deleteRule(Long ruleId) { + var query = new LambdaUpdateWrapper() + .set(RuleEntity::getStatus, Constants.EntityCommonStatus.DELETED) + .eq(RuleEntity::getId, ruleId) + .eq(RuleEntity::getStatus, Constants.EntityCommonStatus.NORMAL); + var updatedRows = ruleMapper.update(query); + // 删除相应的缓存 + if (updatedRows != 0) { + redisTemplate.opsForHash().delete(Constants.RedisKeys.RULE_CACHE, ruleId); + } + + return updatedRows; + } +} diff --git a/rition-center/service/panel/src/main/java/rition/service/panel/ContractService.java b/rition-center/service/panel/src/main/java/rition/service/panel/ContractService.java new file mode 100644 index 0000000..b258753 --- /dev/null +++ b/rition-center/service/panel/src/main/java/rition/service/panel/ContractService.java @@ -0,0 +1,64 @@ +package rition.service.panel; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.github.yitter.idgen.YitIdHelper; +import org.springframework.stereotype.Service; +import rition.common.data.dao.mapper.ContractMapper; +import rition.common.data.dto.service.panel.ContractAddDto; +import rition.common.data.entity.ContractEntity; +import rition.common.data.enums.Constants; +import rition.common.exception.ServiceException; +import rition.common.exception.code.ServiceCode; + +import java.time.Instant; +import java.util.List; + +@Service +public class ContractService { + + private final ContractMapper contractMapper; + + public ContractService(ContractMapper contractMapper) { + this.contractMapper = contractMapper; + } + + public List getContractList() { + var query = new LambdaQueryWrapper() + .eq(ContractEntity::getStatus, Constants.EntityCommonStatus.NORMAL) + .last("limit 100"); + + return contractMapper.selectList(query); + } + + private static final int MAX_CONTRACT_NUM = 20; + + public void addContract(ContractAddDto contractAddDto) { + var countQuery = new LambdaQueryWrapper() + .eq(ContractEntity::getStatus, Constants.EntityCommonStatus.NORMAL); + var count = contractMapper.selectCount(countQuery); + if (count > MAX_CONTRACT_NUM) { + ServiceException.error(ServiceCode.ContractTooManyData); + } + + var now = Instant.now(); + var entity = ContractEntity.builder() + .id(YitIdHelper.nextId()) + .contract(contractAddDto.getContract()) + .type(contractAddDto.getType()) + .createTime(now) + .updateTime(now) + .status(Constants.EntityCommonStatus.NORMAL) + .build(); + + contractMapper.insert(entity); + } + + public void deleteContract(Long id) { + var query = new LambdaUpdateWrapper() + .set(ContractEntity::getStatus, Constants.EntityCommonStatus.DELETED) + .eq(ContractEntity::getId, id) + .eq(ContractEntity::getStatus, Constants.EntityCommonStatus.NORMAL); + contractMapper.update(query); + } +} diff --git a/rition-center/service/panel/src/main/java/rition/service/panel/MetricService.java b/rition-center/service/panel/src/main/java/rition/service/panel/MetricService.java index c20b5d2..426c834 100644 --- a/rition-center/service/panel/src/main/java/rition/service/panel/MetricService.java +++ b/rition-center/service/panel/src/main/java/rition/service/panel/MetricService.java @@ -1,13 +1,12 @@ package rition.service.panel; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import rition.common.data.dao.mapper.MetricRecordMapper; import rition.common.data.entity.MetricRecordEntity; import java.time.Instant; -import java.util.ArrayList; -import java.util.HashSet; import java.util.List; @Slf4j @@ -20,54 +19,35 @@ public class MetricService { this.metricRecordMapper = metricRecordMapper; } + private static final long HOUR = 3600 * 1000; + private static final long DAY = 24 * 3600 * 1000; + private static final long MONTH = 30L * 24 * 3600 * 1000; + + /** + * 按时间范围获取监测数据 + * + * @param instanceId 实例id + * @param metricItems 监测指标项 + * @param start 开始时间 + * @param end 结束时间 + * @return 监测指标数据,指标数据为给定的指标平均统计 + */ public List getMetricDataRange(String instanceId, List metricItems, Instant start, Instant end) { - var filteredMetricItems = this.filterMetricItems(metricItems); - if (filteredMetricItems.isEmpty()) { - return new ArrayList<>(); + // 时间跨度小于1小时:不按时间粒度获取 + // 时间跨度大于1小时:时间粒度为1分钟 + // 时间跨度超过一天:时间粒度为小时 + var diff = end.minusMillis(start.toEpochMilli()).toEpochMilli(); + if (diff < HOUR) { + var query = new LambdaQueryWrapper() + .eq(MetricRecordEntity::getInstanceId, instanceId) + .between(MetricRecordEntity::getTime, start, end); + return metricRecordMapper.selectList(query); + } else if (diff < DAY) { + return metricRecordMapper.getMetricDataGroupByMinute(instanceId, metricItems, start, end); + } else { + return metricRecordMapper.getMetricDataGroupByHour(instanceId, metricItems, start, end); } - - return metricRecordMapper.getMetricDataGroupByHour(instanceId, metricItems, start, end); - } - - private static final HashSet allowedMetricItems = new HashSet<>(22); - - static { - allowedMetricItems.add("up"); - allowedMetricItems.add("node_load5"); - allowedMetricItems.add("node_sockstat_TCP_tw"); - allowedMetricItems.add("node_cpu_seconds_total"); - allowedMetricItems.add("node_memory_Cached_bytes"); - allowedMetricItems.add("node_memory_Buffers_bytes"); - allowedMetricItems.add("node_memory_MemFree_bytes"); - allowedMetricItems.add("node_disk_read_bytes_total"); - allowedMetricItems.add("node_filesystem_free_bytes"); - allowedMetricItems.add("node_filesystem_size_bytes"); - allowedMetricItems.add("node_memory_MemTotal_bytes"); - allowedMetricItems.add("node_netstat_Tcp_CurrEstab"); - allowedMetricItems.add("node_filesystem_avail_bytes"); - allowedMetricItems.add("node_disk_written_bytes_total"); - allowedMetricItems.add("node_disk_reads_completed_total"); - allowedMetricItems.add("node_network_receive_drop_total"); - allowedMetricItems.add("node_disk_writes_completed_total"); - allowedMetricItems.add("node_network_receive_bytes_total"); - allowedMetricItems.add("node_network_transmit_drop_total"); - allowedMetricItems.add("node_network_transmit_bytes_total"); - allowedMetricItems.add("node_network_receive_packets_total"); - allowedMetricItems.add("node_network_transmit_packets_total"); - } - - public List filterMetricItems(List metricItems) { - List filteredMetricItems = new ArrayList<>(metricItems.size()); - for (String metricItem : metricItems) { - if (allowedMetricItems.contains(metricItem)) { - filteredMetricItems.add(metricItem); - } else { - log.warn("[MetricService]: 含有非允许的指标值:{}", metricItem); - } - } - - return filteredMetricItems; } } diff --git a/rition-center/service/panel/src/main/java/rition/service/panel/PanelService.java b/rition-center/service/panel/src/main/java/rition/service/panel/PanelService.java deleted file mode 100644 index 3a30061..0000000 --- a/rition-center/service/panel/src/main/java/rition/service/panel/PanelService.java +++ /dev/null @@ -1,7 +0,0 @@ -package rition.service.panel; - -import org.springframework.stereotype.Service; - -@Service -public class PanelService { -} diff --git a/rition-center/service/panel/src/main/resources/application-panel.yml b/rition-center/service/panel/src/main/resources/application-panel.yml index 4baa07c..fd21a84 100644 --- a/rition-center/service/panel/src/main/resources/application-panel.yml +++ b/rition-center/service/panel/src/main/resources/application-panel.yml @@ -4,9 +4,3 @@ spring: url: jdbc:mysql://127.0.0.1:3306/rition?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true username: root password: Test2333! -mybatis: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl