1、新增功能探针联动处置、心跳在线检测
2、syslog-consumer模块拆分 syslog-consumer-rule模块实现日志数据消费、解析、泛化入库。
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# ============================================
|
||||
# Syslog Consumer 部署配置
|
||||
# ============================================
|
||||
# 使用方法: docker compose -f docker-compose-consumer.yaml up -d
|
||||
# ============================================
|
||||
|
||||
|
||||
services:
|
||||
# ============================================
|
||||
# Syslog Consumer - 数据消费服务 (平台端)
|
||||
# ============================================
|
||||
syslog-consumer:
|
||||
build:
|
||||
context: ./syslog-consumer
|
||||
dockerfile: Dockerfile
|
||||
image: syslog-consumer:1.2.0
|
||||
container_name: syslog-consumer
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# 环境配置
|
||||
- SPRING_PROFILES_ACTIVE=dev
|
||||
- TZ=Asia/Shanghai
|
||||
# 数据库配置
|
||||
- spring.datasource.url=jdbc:postgresql://117.72.68.72:54329/ecosys
|
||||
- spring.datasource.username=postgres
|
||||
- spring.datasource.password=TnLanWaidYSwTSG5
|
||||
- spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
# HikariCP 连接池配置
|
||||
- spring.datasource.hikari.maximum-pool-size=50
|
||||
- spring.datasource.hikari.minimum-idle=5
|
||||
- spring.datasource.hikari.connection-timeout=30000
|
||||
- spring.datasource.hikari.idle-timeout=600000
|
||||
- spring.datasource.hikari.max-lifetime=900000
|
||||
- spring.datasource.hikari.pool-name=HikariPool-SyslogConsumer
|
||||
- spring.datasource.hikari.auto-commit=false
|
||||
- spring.datasource.hikari.schema=public
|
||||
# Redis配置
|
||||
- spring.redis.host=192.168.222.131
|
||||
- spring.redis.port=6379
|
||||
- spring.redis.password=
|
||||
- spring.redis.database=0
|
||||
- spring.redis.timeout=2000
|
||||
- spring.cache.redis.time-to-live=600000
|
||||
# Kafka配置
|
||||
- spring.kafka.consumer.bootstrap-servers=192.168.222.130:9092
|
||||
- spring.kafka.consumer.group-id=test-group-app
|
||||
- spring.kafka.consumer.auto-offset-reset=latest
|
||||
- spring.kafka.consumer.enable-auto-commit=false
|
||||
- spring.kafka.consumer.topic=test-topic
|
||||
- spring.kafka.consumer.max-poll-records=1000
|
||||
- spring.kafka.listener.ack-mode=manual
|
||||
- spring.kafka.listener.concurrency=2
|
||||
- spring.kafka.listener.type=batch
|
||||
# InfluxDB配置
|
||||
- influxdb.url=http://192.168.222.131:8086
|
||||
- influxdb.token=3Tvu-IZWtaY03UDkbUDlufD0kxn85keo9LhYQcv2Cxk0LJmXqqHkNVrO664DbaJAYwoGI7UIg904KqZC7Q_ZFA==
|
||||
- influxdb.org=yelang
|
||||
- influxdb.bucket=yelangbucket
|
||||
- influxdb.batch.size=1000
|
||||
- influxdb.flush.interval=1000
|
||||
- influxdb.connection.timeout=30s
|
||||
- influxdb.connection.read-timeout=30s
|
||||
- influxdb.connection.write-timeout=60s
|
||||
# Elasticsearch配置
|
||||
- spring.elasticsearch.uris=http://192.168.1.174:9200
|
||||
- spring.elasticsearch.username=CONTAINER_NAME
|
||||
- spring.elasticsearch.password=t2NZCiajmdazxBrF
|
||||
- spring.elasticsearch.connection-timeout=10s
|
||||
- spring.elasticsearch.socket-timeout=30s
|
||||
# API配置
|
||||
- interlocking.api-key=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
- interlocking.api.base-url=http://192.168.222.131:8089/xdrservice/interlocking
|
||||
# 探针心跳配置
|
||||
- probe.heartbeat.enabled=true
|
||||
- probe.heartbeat.offline-threshold-minutes=10
|
||||
- probe.status.check.cron=0 */10 * * * ?
|
||||
- probe.heartbeat.tenant-id=000000
|
||||
- probe.heartbeat.history.keep-days=10
|
||||
- probe.heartbeat.history.cleanup-enabled=true
|
||||
- probe.history.cleanup.cron=0 0 1 * * ?
|
||||
# 告警健康检查配置
|
||||
- alarm.health-check.alarm-hours=4
|
||||
- alarm.health-check.alarm-visit-hours=2
|
||||
- alarm.health-check.enabled=true
|
||||
# 关联分析规则配置
|
||||
- analysis.realtime.enabled=true
|
||||
- analysis.realtime.check-interval-seconds=10
|
||||
# 分区表检查配置
|
||||
- partition.check.tomorrow.enabled=true
|
||||
- partition.check.future.days=7
|
||||
- partition.auto.create=true
|
||||
# 定时任务配置
|
||||
- spring.task.scheduling.pool.size=10
|
||||
# 日志配置
|
||||
- logging.level.com.common.schedule=INFO
|
||||
- logging.level.com.common.service=INFO
|
||||
# ETL配置
|
||||
- etl.batch.page-size=1000
|
||||
- etl.batch.insert-batch-size=500
|
||||
- etl.schedule.cron=0 0 2 * * ?
|
||||
# JVM配置
|
||||
- JAVA_OPTS=-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200
|
||||
ports:
|
||||
- "8089:8089"
|
||||
volumes:
|
||||
- /home/syslog/logs:/app/logs
|
||||
networks:
|
||||
- xdr-network
|
||||
|
||||
|
||||
# ============================================
|
||||
# 网络配置
|
||||
# ============================================
|
||||
networks:
|
||||
xdr-network:
|
||||
driver: bridge
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
# ============================================
|
||||
# Syslog Consumer 部署配置
|
||||
# ============================================
|
||||
# 使用方法: docker-compose -f docker-compose-consumer.yaml up -d
|
||||
# ============================================
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# ============================================
|
||||
# Syslog Consumer - 数据消费服务 (平台端)
|
||||
# ============================================
|
||||
syslog-consumer:
|
||||
build:
|
||||
context: ./syslog-consumer
|
||||
dockerfile: Dockerfile
|
||||
container_name: xdr-syslog-consumer
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# 环境配置
|
||||
- SPRING_PROFILES_ACTIVE=prod
|
||||
- TZ=Asia/Shanghai
|
||||
# 数据库配置
|
||||
- spring.datasource.url=jdbc:postgresql://117.72.68.72:54329/ecosys
|
||||
- spring.datasource.username=postgres
|
||||
- spring.datasource.password=TnLanWaidYSwTSG5
|
||||
- spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
# HikariCP 连接池配置
|
||||
- spring.datasource.hikari.maximum-pool-size=50
|
||||
- spring.datasource.hikari.minimum-idle=5
|
||||
- spring.datasource.hikari.connection-timeout=30000
|
||||
- spring.datasource.hikari.idle-timeout=600000
|
||||
- spring.datasource.hikari.max-lifetime=900000
|
||||
- spring.datasource.hikari.pool-name=HikariPool-SyslogConsumer
|
||||
- spring.datasource.hikari.auto-commit=false
|
||||
- spring.datasource.hikari.schema=public
|
||||
# Redis配置
|
||||
- spring.redis.host=127.0.0.1
|
||||
- spring.redis.port=6379
|
||||
- spring.redis.password=
|
||||
- spring.redis.database=0
|
||||
- spring.redis.timeout=2000
|
||||
- spring.cache.redis.time-to-live=600000
|
||||
# Kafka配置
|
||||
- spring.kafka.consumer.bootstrap-servers=192.168.222.130:9092
|
||||
- spring.kafka.consumer.group-id=test-group-app
|
||||
- spring.kafka.consumer.auto-offset-reset=latest
|
||||
- spring.kafka.consumer.enable-auto-commit=false
|
||||
- spring.kafka.consumer.topic=test-topic
|
||||
- spring.kafka.consumer.max-poll-records=1000
|
||||
- spring.kafka.listener.ack-mode=manual
|
||||
- spring.kafka.listener.concurrency=2
|
||||
- spring.kafka.listener.type=batch
|
||||
# InfluxDB配置
|
||||
- influxdb.url=http://192.168.222.131:8086
|
||||
- influxdb.token=3Tvu-IZWtaY03UDkbUDlufD0kxn85keo9LhYQcv2Cxk0LJmXqqHkNVrO664DbaJAYwoGI7UIg904KqZC7Q_ZFA==
|
||||
- influxdb.org=yelang
|
||||
- influxdb.bucket=yelangbucket
|
||||
- influxdb.batch.size=1000
|
||||
- influxdb.flush.interval=1000
|
||||
- influxdb.connection.timeout=30s
|
||||
- influxdb.connection.read-timeout=30s
|
||||
- influxdb.connection.write-timeout=60s
|
||||
# Elasticsearch配置
|
||||
- spring.elasticsearch.uris=http://192.168.1.174:9200
|
||||
- spring.elasticsearch.username=CONTAINER_NAME
|
||||
- spring.elasticsearch.password=t2NZCiajmdazxBrF
|
||||
- spring.elasticsearch.connection-timeout=10s
|
||||
- spring.elasticsearch.socket-timeout=30s
|
||||
# API配置
|
||||
- interlocking.api-key=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
- interlocking.api.base-url=http://localhost:8089/xdrservice/interlocking
|
||||
# 探针心跳配置
|
||||
- probe.heartbeat.enabled=true
|
||||
- probe.heartbeat.offline-threshold-minutes=10
|
||||
- probe.status.check.cron=0 */10 * * * ?
|
||||
- probe.heartbeat.tenant-id=000000
|
||||
- probe.heartbeat.history.keep-days=10
|
||||
- probe.heartbeat.history.cleanup-enabled=true
|
||||
- probe.history.cleanup.cron=0 0 1 * * ?
|
||||
# 告警健康检查配置
|
||||
- alarm.health-check.alarm-hours=4
|
||||
- alarm.health-check.alarm-visit-hours=2
|
||||
- alarm.health-check.enabled=true
|
||||
# 关联分析规则配置
|
||||
- analysis.realtime.enabled=true
|
||||
- analysis.realtime.check-interval-seconds=10
|
||||
# 分区表检查配置
|
||||
- partition.check.tomorrow.enabled=true
|
||||
- partition.check.future.days=7
|
||||
- partition.auto.create=true
|
||||
# 定时任务配置
|
||||
- spring.task.scheduling.pool.size=10
|
||||
# 日志配置
|
||||
- logging.level.com.common.schedule=INFO
|
||||
- logging.level.com.common.service=INFO
|
||||
# ETL配置
|
||||
- etl.batch.page-size=1000
|
||||
- etl.batch.insert-batch-size=500
|
||||
- etl.schedule.cron=0 0 2 * * ?
|
||||
# JVM配置
|
||||
- JAVA_OPTS=-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200
|
||||
ports:
|
||||
- "8089:8089"
|
||||
volumes:
|
||||
- syslog-consumer-logs:/app/logs
|
||||
networks:
|
||||
- xdr-network
|
||||
|
||||
# ============================================
|
||||
# PostgreSQL 数据库 (可选,如已存在可注释掉)
|
||||
# ============================================
|
||||
postgres:
|
||||
image: postgres:14-alpine
|
||||
container_name: xdr-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: ecosys
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: TnLanWaidYSwTSG5
|
||||
TZ: Asia/Shanghai
|
||||
ports:
|
||||
- "54329:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- xdr-network
|
||||
|
||||
# ============================================
|
||||
# 网络配置
|
||||
# ============================================
|
||||
networks:
|
||||
xdr-network:
|
||||
driver: bridge
|
||||
|
||||
# ============================================
|
||||
# 卷配置
|
||||
# ============================================
|
||||
volumes:
|
||||
syslog-consumer-logs:
|
||||
driver: local
|
||||
postgres_data:
|
||||
driver: local
|
||||
@@ -0,0 +1,116 @@
|
||||
# ============================================
|
||||
# Syslog Consumer 部署配置
|
||||
# ============================================
|
||||
# 使用方法: docker compose -f docker-compose-consumer.yaml up -d
|
||||
# ============================================
|
||||
|
||||
|
||||
services:
|
||||
# ============================================
|
||||
# Syslog Consumer - 数据消费服务 (平台端)
|
||||
# ============================================
|
||||
syslog-consumer:
|
||||
build:
|
||||
context: ./syslog-consumer
|
||||
dockerfile: Dockerfile
|
||||
image: syslog-consumer:1.0.1
|
||||
container_name: syslog-consumer
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# 环境配置
|
||||
- SPRING_PROFILES_ACTIVE=dev
|
||||
- TZ=Asia/Shanghai
|
||||
# 数据库配置
|
||||
- spring.datasource.url=jdbc:postgresql://117.72.68.72:54329/ecosys
|
||||
- spring.datasource.username=postgres
|
||||
- spring.datasource.password=TnLanWaidYSwTSG5
|
||||
- spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
# HikariCP 连接池配置
|
||||
- spring.datasource.hikari.maximum-pool-size=50
|
||||
- spring.datasource.hikari.minimum-idle=5
|
||||
- spring.datasource.hikari.connection-timeout=30000
|
||||
- spring.datasource.hikari.idle-timeout=600000
|
||||
- spring.datasource.hikari.max-lifetime=900000
|
||||
- spring.datasource.hikari.pool-name=HikariPool-SyslogConsumer
|
||||
- spring.datasource.hikari.auto-commit=false
|
||||
- spring.datasource.hikari.schema=public
|
||||
# Redis配置
|
||||
- spring.redis.host=192.168.222.131
|
||||
- spring.redis.port=6379
|
||||
- spring.redis.password=
|
||||
- spring.redis.database=0
|
||||
- spring.redis.timeout=2000
|
||||
- spring.cache.redis.time-to-live=600000
|
||||
# Kafka配置
|
||||
- spring.kafka.consumer.bootstrap-servers=192.168.222.130:9092
|
||||
- spring.kafka.consumer.group-id=test-group-app
|
||||
- spring.kafka.consumer.auto-offset-reset=latest
|
||||
- spring.kafka.consumer.enable-auto-commit=false
|
||||
- spring.kafka.consumer.topic=test-topic
|
||||
- spring.kafka.consumer.max-poll-records=1000
|
||||
- spring.kafka.listener.ack-mode=manual
|
||||
- spring.kafka.listener.concurrency=2
|
||||
- spring.kafka.listener.type=batch
|
||||
# InfluxDB配置
|
||||
- influxdb.url=http://192.168.222.131:8086
|
||||
- influxdb.token=3Tvu-IZWtaY03UDkbUDlufD0kxn85keo9LhYQcv2Cxk0LJmXqqHkNVrO664DbaJAYwoGI7UIg904KqZC7Q_ZFA==
|
||||
- influxdb.org=yelang
|
||||
- influxdb.bucket=yelangbucket
|
||||
- influxdb.batch.size=1000
|
||||
- influxdb.flush.interval=1000
|
||||
- influxdb.connection.timeout=30s
|
||||
- influxdb.connection.read-timeout=30s
|
||||
- influxdb.connection.write-timeout=60s
|
||||
# Elasticsearch配置
|
||||
- spring.elasticsearch.uris=http://192.168.1.174:9200
|
||||
- spring.elasticsearch.username=CONTAINER_NAME
|
||||
- spring.elasticsearch.password=t2NZCiajmdazxBrF
|
||||
- spring.elasticsearch.connection-timeout=10s
|
||||
- spring.elasticsearch.socket-timeout=30s
|
||||
# API配置
|
||||
- interlocking.api-key=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
- interlocking.api.base-url=http://192.168.222.131:8089/xdrservice/interlocking
|
||||
# 探针心跳配置
|
||||
- probe.heartbeat.enabled=true
|
||||
- probe.heartbeat.offline-threshold-minutes=10
|
||||
- probe.status.check.cron=0 */10 * * * ?
|
||||
- probe.heartbeat.tenant-id=000000
|
||||
- probe.heartbeat.history.keep-days=10
|
||||
- probe.heartbeat.history.cleanup-enabled=true
|
||||
- probe.history.cleanup.cron=0 0 1 * * ?
|
||||
# 告警健康检查配置
|
||||
- alarm.health-check.alarm-hours=4
|
||||
- alarm.health-check.alarm-visit-hours=2
|
||||
- alarm.health-check.enabled=true
|
||||
# 关联分析规则配置
|
||||
- analysis.realtime.enabled=true
|
||||
- analysis.realtime.check-interval-seconds=10
|
||||
# 分区表检查配置
|
||||
- partition.check.tomorrow.enabled=true
|
||||
- partition.check.future.days=7
|
||||
- partition.auto.create=true
|
||||
# 定时任务配置
|
||||
- spring.task.scheduling.pool.size=10
|
||||
# 日志配置
|
||||
- logging.level.com.common.schedule=INFO
|
||||
- logging.level.com.common.service=INFO
|
||||
# ETL配置
|
||||
- etl.batch.page-size=1000
|
||||
- etl.batch.insert-batch-size=500
|
||||
- etl.schedule.cron=0 0 2 * * ?
|
||||
# JVM配置
|
||||
- JAVA_OPTS=-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200
|
||||
ports:
|
||||
- "8089:8089"
|
||||
volumes:
|
||||
- /home/syslog/logs:/app/logs
|
||||
networks:
|
||||
- xdr-network
|
||||
|
||||
|
||||
# ============================================
|
||||
# 网络配置
|
||||
# ============================================
|
||||
networks:
|
||||
xdr-network:
|
||||
driver: bridge
|
||||
@@ -13,7 +13,6 @@ docker build -t syslog-consumer:v1.X.X .
|
||||
--3.停止容器 并删除
|
||||
docker stop ct-syslog-consumer && docker rm ct-syslog-consumer
|
||||
|
||||
|
||||
--4.运行docker 文件
|
||||
docker run --restart unless-stopped -e TZ=Asia/Shanghai -d --name ct-syslog-consumer -p 8089:8089 -v /home/syslog/logs:/app/logs --privileged=true syslog-consumer:v1.X.X
|
||||
众诚CMD:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<name>syslog-consumer</name>
|
||||
<artifactId>syslog-consumer</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<influxdb-client.version>6.9.0</influxdb-client.version>
|
||||
|
||||
+4
-1
@@ -5,6 +5,7 @@ import com.common.util.SyslogParser;
|
||||
import com.config.AppConfig;
|
||||
import com.influxdb.client.domain.WritePrecision;
|
||||
import com.influxdb.client.write.Point;
|
||||
import com.influxdb.client.WriteApi;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -277,7 +278,9 @@ public class SysLogProcessor {
|
||||
.addField("receive_time", mapdev.get("receive_time")) // 添加字段
|
||||
.addField("uuid", sysLogUUID)
|
||||
.time(System.currentTimeMillis(), WritePrecision.MS) ;// 毫秒级时间戳
|
||||
influxClient.writePointBlocking(point);
|
||||
//influxClient.writePointBlocking(point);
|
||||
///写入单点(异步,立即返回)
|
||||
influxClient.writePoint(point);
|
||||
|
||||
System.out.println("influxdb wirte syslog ,value:"+ record.key());
|
||||
// 日志信息插入pg XdrHoneypot 表
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.common.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 探针心跳状态实体类
|
||||
* 对应表: device_collect_heartbeat
|
||||
*/
|
||||
@Data
|
||||
public class DeviceCollectHeartbeat {
|
||||
|
||||
/** 自增主键 */
|
||||
private Long id;
|
||||
|
||||
/** 探针唯一标识(由探针上报) */
|
||||
private String collectId;
|
||||
|
||||
/** 探针名称(可选) */
|
||||
private String collectName;
|
||||
|
||||
/** 探针IP(支持IPv6) */
|
||||
private String deviceIp;
|
||||
|
||||
/** 探针版本 */
|
||||
private String appVersion;
|
||||
|
||||
/** 最后一次心跳时间(毫秒精度) */
|
||||
private LocalDateTime lastHeartbeat;
|
||||
|
||||
/** 累计心跳次数(可监控丢包率) */
|
||||
private Long heartbeatCount;
|
||||
|
||||
/** 在线状态:online / offline */
|
||||
private String status;
|
||||
|
||||
/** 连续心跳失败次数(平台侧计算) */
|
||||
private Integer failCount;
|
||||
|
||||
/** 最后更新时间 */
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
|
||||
|
||||
public DeviceCollectHeartbeat() {
|
||||
this.heartbeatCount = 1L;
|
||||
this.status = "online";
|
||||
this.failCount = 0;
|
||||
this.updateTime = LocalDateTime.now();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新心跳
|
||||
*/
|
||||
public void updateHeartbeat() {
|
||||
this.lastHeartbeat = LocalDateTime.now();
|
||||
this.heartbeatCount = (this.heartbeatCount == null ? 1L : this.heartbeatCount + 1);
|
||||
this.status = "online";
|
||||
this.failCount = 0;
|
||||
this.updateTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记为离线
|
||||
*/
|
||||
public void markOffline() {
|
||||
this.status = "offline";
|
||||
this.failCount = (this.failCount == null ? 1 : this.failCount + 1);
|
||||
this.updateTime = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复在线
|
||||
*/
|
||||
public void markOnline() {
|
||||
this.status = "online";
|
||||
this.failCount = 0;
|
||||
this.updateTime = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.common.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 探针心跳历史记录实体类
|
||||
* 对应表: device_collect_heartbeat_history
|
||||
*/
|
||||
@Data
|
||||
public class DeviceCollectHeartbeatHistory {
|
||||
|
||||
/** 自增主键 */
|
||||
private Long id;
|
||||
|
||||
/** 探针唯一标识 */
|
||||
private String collectId;
|
||||
|
||||
/** 心跳上报时间 */
|
||||
private LocalDateTime heartbeatTime;
|
||||
|
||||
/** 探针IP */
|
||||
private String deviceIp;
|
||||
|
||||
/** 探针版本 */
|
||||
private String appVersion;
|
||||
|
||||
/** 记录创建时间 */
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
|
||||
public DeviceCollectHeartbeatHistory() {
|
||||
this.createdAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从心跳状态创建历史记录
|
||||
*/
|
||||
public static DeviceCollectHeartbeatHistory fromHeartbeat(DeviceCollectHeartbeat heartbeat) {
|
||||
DeviceCollectHeartbeatHistory history = new DeviceCollectHeartbeatHistory();
|
||||
history.setCollectId(heartbeat.getCollectId());
|
||||
history.setHeartbeatTime(heartbeat.getLastHeartbeat());
|
||||
history.setDeviceIp(heartbeat.getDeviceIp());
|
||||
history.setAppVersion(heartbeat.getAppVersion());
|
||||
history.setCreatedAt(LocalDateTime.now());
|
||||
return history;
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.common.mapper;
|
||||
|
||||
import com.common.entity.DeviceCollectHeartbeatHistory;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 探针心跳历史 Mapper 接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface DeviceCollectHeartbeatHistoryMapper {
|
||||
|
||||
/**
|
||||
* 插入心跳历史记录
|
||||
*/
|
||||
@Insert("INSERT INTO device_collect_heartbeat_history (" +
|
||||
"collect_id, heartbeat_time, device_ip, app_version, created_at " +
|
||||
") VALUES (" +
|
||||
"#{collectId}, #{heartbeatTime}, #{deviceIp}, #{appVersion}, #{createdAt} " +
|
||||
")")
|
||||
@Options(useGeneratedKeys = true, keyProperty = "id")
|
||||
int insert(DeviceCollectHeartbeatHistory history);
|
||||
|
||||
/**
|
||||
* 批量插入心跳历史记录
|
||||
*/
|
||||
@Insert("<script>" +
|
||||
"INSERT INTO device_collect_heartbeat_history " +
|
||||
"(collect_id, heartbeat_time, device_ip, app_version, created_at ) " +
|
||||
"VALUES " +
|
||||
"<foreach collection='list' item='item' separator=','>" +
|
||||
"(#{item.collectId}, #{item.heartbeatTime}, #{item.deviceIp}, #{item.appVersion}, " +
|
||||
"#{item.createdAt} )" +
|
||||
"</foreach>" +
|
||||
"</script>")
|
||||
int batchInsert(@Param("list") List<DeviceCollectHeartbeatHistory> histories);
|
||||
|
||||
/**
|
||||
* 根据探针ID查询历史记录
|
||||
*/
|
||||
@Select("SELECT * FROM device_collect_heartbeat_history " +
|
||||
"WHERE collect_id = #{collectId} ORDER BY heartbeat_time DESC LIMIT #{limit}")
|
||||
List<DeviceCollectHeartbeatHistory> selectByCollectId(@Param("collectId") String collectId,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 删除指定日期之前的记录
|
||||
*/
|
||||
@Delete("DELETE FROM device_collect_heartbeat_history WHERE created_at < #{beforeTime}")
|
||||
int deleteBeforeTime(@Param("beforeTime") LocalDateTime beforeTime);
|
||||
|
||||
/**
|
||||
* 统计指定日期之前的记录数
|
||||
*/
|
||||
@Select("SELECT COUNT(*) FROM device_collect_heartbeat_history WHERE created_at < #{beforeTime}")
|
||||
long countBeforeTime(@Param("beforeTime") LocalDateTime beforeTime);
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.common.mapper;
|
||||
|
||||
import com.common.entity.DeviceCollectHeartbeat;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 探针心跳状态 Mapper 接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface DeviceCollectHeartbeatMapper {
|
||||
|
||||
/**
|
||||
* 根据探针ID查询
|
||||
*/
|
||||
@Select("SELECT * FROM device_collect_heartbeat WHERE collect_id = #{collectId}")
|
||||
DeviceCollectHeartbeat selectByCollectId(@Param("collectId") String collectId);
|
||||
|
||||
/**
|
||||
* 查询所有探针
|
||||
*/
|
||||
@Select("SELECT * FROM device_collect_heartbeat ORDER BY update_time DESC")
|
||||
List<DeviceCollectHeartbeat> selectAll();
|
||||
|
||||
/**
|
||||
* 查询所有在线探针
|
||||
*/
|
||||
@Select("SELECT * FROM device_collect_heartbeat WHERE status = 'online' ORDER BY update_time DESC")
|
||||
List<DeviceCollectHeartbeat> selectAllOnline();
|
||||
|
||||
/**
|
||||
* 查询所有离线探针
|
||||
*/
|
||||
@Select("SELECT * FROM device_collect_heartbeat WHERE status = 'offline' ORDER BY update_time DESC")
|
||||
List<DeviceCollectHeartbeat> selectAllOffline();
|
||||
|
||||
/**
|
||||
* 插入或更新(根据collect_id)
|
||||
*/
|
||||
@Insert("INSERT INTO device_collect_heartbeat (" +
|
||||
"collect_id, collect_name, device_ip, app_version, last_heartbeat, " +
|
||||
"heartbeat_count, status, fail_count, update_time " +
|
||||
") VALUES (" +
|
||||
"#{collectId}, #{collectName}, #{deviceIp}, #{appVersion}, #{lastHeartbeat}, " +
|
||||
"#{heartbeatCount}, #{status}, #{failCount}, #{updateTime} " +
|
||||
") ON CONFLICT (collect_id) DO UPDATE SET " +
|
||||
"collect_name = EXCLUDED.collect_name, " +
|
||||
"device_ip = EXCLUDED.device_ip, " +
|
||||
"app_version = EXCLUDED.app_version, " +
|
||||
"last_heartbeat = EXCLUDED.last_heartbeat, " +
|
||||
"heartbeat_count = EXCLUDED.heartbeat_count, " +
|
||||
"status = EXCLUDED.status, " +
|
||||
"fail_count = EXCLUDED.fail_count, " +
|
||||
"update_time = EXCLUDED.update_time")
|
||||
int upsert(DeviceCollectHeartbeat heartbeat);
|
||||
|
||||
/**
|
||||
* 更新探针状态
|
||||
*/
|
||||
@Update("UPDATE device_collect_heartbeat SET " +
|
||||
"status = #{status}, fail_count = #{failCount}, update_time = #{updateTime} " +
|
||||
"WHERE collect_id = #{collectId}")
|
||||
int updateStatus(@Param("collectId") String collectId,
|
||||
@Param("status") String status,
|
||||
@Param("failCount") Integer failCount,
|
||||
@Param("updateTime") java.time.LocalDateTime updateTime);
|
||||
|
||||
/**
|
||||
* 查询超过指定时间未心跳的探针(用于检测离线)
|
||||
*/
|
||||
@Select("SELECT * FROM device_collect_heartbeat " +
|
||||
"WHERE status = 'online' AND last_heartbeat < #{thresholdTime} " +
|
||||
"ORDER BY last_heartbeat ASC")
|
||||
List<DeviceCollectHeartbeat> selectOfflineCandidates(@Param("thresholdTime") java.time.LocalDateTime thresholdTime);
|
||||
|
||||
/**
|
||||
* 删除指定日期之前的记录
|
||||
*/
|
||||
@Delete("DELETE FROM device_collect_heartbeat WHERE update_time < #{beforeTime}")
|
||||
int deleteBeforeTime(@Param("beforeTime") java.time.LocalDateTime beforeTime);
|
||||
}
|
||||
+2
-2
@@ -20,10 +20,10 @@ public class AlarmHealthCheckScheduler {
|
||||
private AlarmHealthCheckService alarmHealthCheckService;
|
||||
|
||||
/**
|
||||
* 每5分钟执行一次告警健康检查
|
||||
* 每30分钟执行一次告警健康检查
|
||||
* 巡检告警表 alarm 和告警日志表 alarm_visit
|
||||
*/
|
||||
@Scheduled(cron = "0 */5 * * * ?")
|
||||
@Scheduled(cron = "0 */30 * * * ?")
|
||||
public void scheduledHealthCheck() {
|
||||
logger.info("========== 开始执行告警健康检查 ==========");
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.common.schedule;
|
||||
|
||||
import com.common.service.ProbeHeartbeatService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 探针心跳历史清理调度器
|
||||
* 定期清理过期的探针心跳历史记录
|
||||
*/
|
||||
@Component
|
||||
public class ProbeHeartbeatHistoryCleanupScheduler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProbeHeartbeatHistoryCleanupScheduler.class);
|
||||
|
||||
@Autowired
|
||||
private ProbeHeartbeatService probeHeartbeatService;
|
||||
|
||||
/** 保留天数,默认10天 */
|
||||
@Value("${probe.heartbeat.history.keep-days:10}")
|
||||
private int keepDays;
|
||||
|
||||
/** 是否启用清理 */
|
||||
@Value("${probe.heartbeat.history.cleanup-enabled:true}")
|
||||
private boolean cleanupEnabled;
|
||||
|
||||
/**
|
||||
* 每天凌晨1点执行清理
|
||||
*/
|
||||
@Scheduled(cron = "${probe.history.cleanup.cron:0 0 1 * * ?}")
|
||||
public void cleanupHistory() {
|
||||
if (!cleanupEnabled) {
|
||||
logger.debug("心跳历史清理已禁用");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("========== 开始清理心跳历史记录 ==========");
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
long deleted = probeHeartbeatService.cleanupHistory(keepDays);
|
||||
|
||||
long elapsedTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
if (deleted > 0) {
|
||||
logger.info("心跳历史清理完成,删除 {} 条 {} 天前的记录, 耗时: {}ms",
|
||||
deleted, keepDays, elapsedTime);
|
||||
} else {
|
||||
logger.info("心跳历史清理完成,无过期记录需要清理, 耗时: {}ms", elapsedTime);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("心跳历史清理异常: {}", e.getMessage(), e);
|
||||
}
|
||||
|
||||
logger.info("========== 心跳历史清理结束 ==========");
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发清理
|
||||
* @return 删除的记录数
|
||||
*/
|
||||
public long manualCleanup() {
|
||||
logger.info("手动触发心跳历史清理");
|
||||
return probeHeartbeatService.cleanupHistory(keepDays);
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.common.schedule;
|
||||
|
||||
import com.common.entity.DeviceCollectHeartbeat;
|
||||
import com.common.service.ProbeHeartbeatService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 探针状态检查调度器
|
||||
* 定期检查探针是否离线,触发告警
|
||||
*/
|
||||
@Component
|
||||
public class ProbeStatusCheckScheduler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProbeStatusCheckScheduler.class);
|
||||
|
||||
@Autowired
|
||||
private ProbeHeartbeatService probeHeartbeatService;
|
||||
|
||||
@Value("${probe.heartbeat.enabled:true}")
|
||||
private boolean heartbeatEnabled;
|
||||
|
||||
/**
|
||||
* 检查探针状态
|
||||
* 默认每10分钟检查一次(可配置)
|
||||
*/
|
||||
@Scheduled(cron = "${probe.status.check.cron:0 */10 * * * ?}")
|
||||
public void checkProbeStatus() {
|
||||
if (!heartbeatEnabled) {
|
||||
logger.debug("探针状态检查已禁用");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("========== 开始探针状态检查 ==========");
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// 检查并标记离线探针
|
||||
List<DeviceCollectHeartbeat> newlyOffline = probeHeartbeatService.checkAndMarkOfflineProbes();
|
||||
|
||||
long elapsedTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
if (!newlyOffline.isEmpty()) {
|
||||
logger.warn("探针状态检查完成,发现 {} 个新离线探针, 离线阈值: {}分钟, 耗时: {}ms",
|
||||
newlyOffline.size(),
|
||||
probeHeartbeatService.getOfflineThresholdMinutes(),
|
||||
elapsedTime);
|
||||
|
||||
for (DeviceCollectHeartbeat probe : newlyOffline) {
|
||||
logger.warn("离线探针: collectId={}, ip={}, name={}",
|
||||
probe.getCollectId(), probe.getDeviceIp(), probe.getCollectName());
|
||||
}
|
||||
} else {
|
||||
logger.info("探针状态检查完成,所有探针在线, 耗时: {}ms", elapsedTime);
|
||||
}
|
||||
|
||||
// 输出当前探针统计
|
||||
List<DeviceCollectHeartbeat> allProbes = probeHeartbeatService.getAllProbes();
|
||||
long onlineCount = allProbes.stream().filter(p -> "online".equals(p.getStatus())).count();
|
||||
long offlineCount = allProbes.size() - onlineCount;
|
||||
|
||||
logger.info("探针统计: 总数={}, 在线={}, 离线={}",
|
||||
allProbes.size(), onlineCount, offlineCount);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("探针状态检查异常: {}", e.getMessage(), e);
|
||||
}
|
||||
|
||||
logger.info("========== 探针状态检查结束 ==========");
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发探针状态检查
|
||||
* @return 新增的离线探针数量
|
||||
*/
|
||||
public int manualCheck() {
|
||||
logger.info("手动触发探针状态检查");
|
||||
List<DeviceCollectHeartbeat> newlyOffline = probeHeartbeatService.checkAndMarkOfflineProbes();
|
||||
return newlyOffline.size();
|
||||
}
|
||||
}
|
||||
+24
@@ -272,6 +272,9 @@ public class AccessLogAlertService {
|
||||
logObject.put("_source.vlan_id", "");
|
||||
logObject.put("_type", "skyeye-file");
|
||||
|
||||
//补充syslog_normal_data.device_id 字段
|
||||
logObject.put("_source.device_id", logData.getDeviceId() != null ? logData.getDeviceId() : "");
|
||||
|
||||
requestArray.add(logObject);
|
||||
}
|
||||
|
||||
@@ -416,12 +419,33 @@ public class AccessLogAlertService {
|
||||
log.debug("算法:{},ID:{} ,AlarmNme:{} 没有返回 origin_log节点.",AlgorithmName, alarmVisit.getId(), alarmVisit.getAlarmName());
|
||||
return false;
|
||||
}
|
||||
/** 旧版有BUG
|
||||
alarmVisit.setAttackPort( new Integer[]{alarmResult.getInteger("_source.sport")} );
|
||||
alarmVisit.setVictimPort( new Integer[]{alarmResult.getInteger("_source.dport")} );
|
||||
alarmVisit.setAttackMethod(alarmResult.getString("_source.method") );
|
||||
String deviceIp= alarmResult.getString("_source.device_ip");
|
||||
//alarmVisit.setDeviceId( new Integer[]{ getDeviceID(deviceIp)} );
|
||||
alarmVisit.setHttpStatus( alarmResult.getString("_source.status"));
|
||||
**/
|
||||
|
||||
// _source.sport/dport 在 JSON 中为字符串类型,需要用 getString() 读取后 parseInt
|
||||
String sportStr = originLogObject.getString("_source.sport");
|
||||
if (sportStr != null && !sportStr.isEmpty()) {
|
||||
alarmVisit.setAttackPort(new Integer[]{Integer.parseInt(sportStr)});
|
||||
}
|
||||
String dportStr = originLogObject.getString("_source.dport");
|
||||
if (dportStr != null && !dportStr.isEmpty()) {
|
||||
alarmVisit.setVictimPort(new Integer[]{Integer.parseInt(dportStr)});
|
||||
}
|
||||
alarmVisit.setAttackMethod(originLogObject.getString("_source.method"));
|
||||
String deviceIp = originLogObject.getString("_source.device_ip");
|
||||
//alarmVisit.setDeviceId( new Integer[]{ getDeviceID(deviceIp)} );
|
||||
|
||||
//补充alarm_visist.device_id
|
||||
String deviceidStr = originLogObject.getString("_source.device_id");
|
||||
if (deviceidStr != null && !deviceidStr.isEmpty()) {
|
||||
alarmVisit.setDeviceId(new Integer[]{Integer.parseInt(deviceidStr)});
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("算法:{} 补充原始记录日志字段异常。error:{} ",AlgorithmName,e.getMessage(), e );
|
||||
|
||||
-1
@@ -119,7 +119,6 @@ public class AlarmHealthCheckService {
|
||||
String content = String.format(
|
||||
"【数据巡检告警】%n" +
|
||||
"表名: %s%n" +
|
||||
"告警时间: %s%n" +
|
||||
"告警描述: 最近%d小时内无新数据%n" +
|
||||
"建议: 请检查数据采集服务是否正常运行%n" +
|
||||
"状态: 需要人工介入检查",
|
||||
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
package com.common.service;
|
||||
|
||||
import com.common.entity.DeviceCollectHeartbeat;
|
||||
import com.common.entity.DeviceCollectHeartbeatHistory;
|
||||
import com.common.entity.WecomNotification;
|
||||
import com.common.mapper.DeviceCollectHeartbeatMapper;
|
||||
import com.common.mapper.DeviceCollectHeartbeatHistoryMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 探针心跳服务
|
||||
* 管理探针心跳状态、心跳历史、以及离线告警
|
||||
*/
|
||||
@Service
|
||||
public class ProbeHeartbeatService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProbeHeartbeatService.class);
|
||||
|
||||
@Autowired
|
||||
private DeviceCollectHeartbeatMapper heartbeatMapper;
|
||||
|
||||
@Autowired
|
||||
private DeviceCollectHeartbeatHistoryMapper historyMapper;
|
||||
|
||||
@Autowired
|
||||
private WecomNotificationService wecomNotificationService;
|
||||
|
||||
/** 离线阈值(分钟) */
|
||||
@Value("${probe.heartbeat.offline-threshold-minutes:10}")
|
||||
private int offlineThresholdMinutes;
|
||||
|
||||
/** 租户ID */
|
||||
@Value("${probe.heartbeat.tenant-id:000000}")
|
||||
private String tenantId;
|
||||
|
||||
/** 已发送离线告警的探针集合(用于告警收敛) */
|
||||
private final Map<String, Boolean> alertedProbes = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 接收探针心跳
|
||||
* @param heartbeatData 心跳数据
|
||||
* @return 探针实体
|
||||
*/
|
||||
@Transactional
|
||||
public DeviceCollectHeartbeat receiveHeartbeat(ProbeHeartbeatData heartbeatData) {
|
||||
String collectId = heartbeatData.getCollectId();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
// 查询现有探针状态
|
||||
DeviceCollectHeartbeat existing = heartbeatMapper.selectByCollectId(collectId);
|
||||
boolean wasOffline = existing != null && "offline".equals(existing.getStatus());
|
||||
|
||||
// 创建或更新探针状态
|
||||
DeviceCollectHeartbeat heartbeat = new DeviceCollectHeartbeat();
|
||||
heartbeat.setCollectId(collectId);
|
||||
heartbeat.setCollectName(heartbeatData.getCollectName());
|
||||
heartbeat.setDeviceIp(heartbeatData.getDeviceIp());
|
||||
heartbeat.setAppVersion(heartbeatData.getAppVersion());
|
||||
heartbeat.setLastHeartbeat(now);
|
||||
heartbeat.setHeartbeatCount(existing == null ? 1L : existing.getHeartbeatCount() + 1);
|
||||
heartbeat.setStatus("online");
|
||||
heartbeat.setFailCount(0);
|
||||
heartbeat.setUpdateTime(now);
|
||||
|
||||
|
||||
// 如果有ID则保留
|
||||
if (existing != null) {
|
||||
heartbeat.setId(existing.getId());
|
||||
}
|
||||
|
||||
// 插入/更新主表
|
||||
heartbeatMapper.upsert(heartbeat);
|
||||
|
||||
// 插入历史记录
|
||||
DeviceCollectHeartbeatHistory history = DeviceCollectHeartbeatHistory.fromHeartbeat(heartbeat);
|
||||
historyMapper.insert(history);
|
||||
|
||||
// 如果从离线恢复,发送恢复通知
|
||||
if (wasOffline) {
|
||||
sendRecoveryNotification(heartbeat);
|
||||
alertedProbes.remove(collectId); // 清除告警标记
|
||||
logger.info("探针 {} 已恢复在线", collectId);
|
||||
}
|
||||
|
||||
logger.debug("接收探针 {} 心跳,IP: {}, 版本: {}", collectId, heartbeat.getDeviceIp(), heartbeat.getAppVersion());
|
||||
|
||||
return heartbeat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有探针状态
|
||||
*/
|
||||
public List<DeviceCollectHeartbeat> getAllProbes() {
|
||||
return heartbeatMapper.selectAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在线探针
|
||||
*/
|
||||
public List<DeviceCollectHeartbeat> getOnlineProbes() {
|
||||
return heartbeatMapper.selectAllOnline();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取离线探针
|
||||
*/
|
||||
public List<DeviceCollectHeartbeat> getOfflineProbes() {
|
||||
return heartbeatMapper.selectAllOffline();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据探针ID获取状态
|
||||
*/
|
||||
public DeviceCollectHeartbeat getProbeById(String collectId) {
|
||||
return heartbeatMapper.selectByCollectId(collectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查探针状态并标记离线
|
||||
* @return 新增的离线探针列表
|
||||
*/
|
||||
@Transactional
|
||||
public List<DeviceCollectHeartbeat> checkAndMarkOfflineProbes() {
|
||||
LocalDateTime thresholdTime = LocalDateTime.now().minusMinutes(offlineThresholdMinutes);
|
||||
List<DeviceCollectHeartbeat> candidates = heartbeatMapper.selectOfflineCandidates(thresholdTime);
|
||||
|
||||
List<DeviceCollectHeartbeat> newlyOffline = new java.util.ArrayList<>();
|
||||
|
||||
for (DeviceCollectHeartbeat probe : candidates) {
|
||||
String collectId = probe.getCollectId();
|
||||
|
||||
// 检查是否已经发送过告警(告警收敛)
|
||||
if (alertedProbes.containsKey(collectId)) {
|
||||
// 仅更新状态,不重复告警
|
||||
heartbeatMapper.updateStatus(collectId, "offline",
|
||||
(probe.getFailCount() == null ? 0 : probe.getFailCount()) + 1, LocalDateTime.now());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 标记为离线
|
||||
heartbeatMapper.updateStatus(collectId, "offline",
|
||||
(probe.getFailCount() == null ? 0 : probe.getFailCount()) + 1, LocalDateTime.now());
|
||||
|
||||
// 发送离线告警
|
||||
sendOfflineAlert(probe);
|
||||
|
||||
// 标记已告警
|
||||
alertedProbes.put(collectId, true);
|
||||
newlyOffline.add(probe);
|
||||
|
||||
logger.warn("探针 {} 已离线,最后心跳时间: {}", collectId, probe.getLastHeartbeat());
|
||||
}
|
||||
|
||||
return newlyOffline;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送离线告警
|
||||
*/
|
||||
private void sendOfflineAlert(DeviceCollectHeartbeat probe) {
|
||||
String content = String.format(
|
||||
"【探针离线告警】%n" +
|
||||
"探针ID: %s%n" +
|
||||
"探针名称: %s%n" +
|
||||
"探针IP: %s%n" +
|
||||
"版本: %s%n" +
|
||||
"离线时间: %s%n" +
|
||||
"最后心跳: %s%n" +
|
||||
"建议: 请检查探针服务是否正常运行",
|
||||
probe.getCollectId(),
|
||||
probe.getCollectName() != null ? probe.getCollectName() : "未知",
|
||||
probe.getDeviceIp(),
|
||||
probe.getAppVersion() != null ? probe.getAppVersion() : "未知",
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
|
||||
probe.getLastHeartbeat() != null ? probe.getLastHeartbeat().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : "未知"
|
||||
);
|
||||
|
||||
try {
|
||||
WecomNotification notification = wecomNotificationService.sendAlert(
|
||||
"探针离线-" + probe.getCollectId(),
|
||||
"probe_offline",
|
||||
"4", // 紧急
|
||||
content,
|
||||
probe.getDeviceIp()
|
||||
);
|
||||
logger.info("发送探针离线告警成功, 通知ID: {}", notification.getWecomNotificationId());
|
||||
} catch (Exception e) {
|
||||
logger.error("发送探针离线告警失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送恢复通知
|
||||
*/
|
||||
private void sendRecoveryNotification(DeviceCollectHeartbeat probe) {
|
||||
String content = String.format(
|
||||
"【探针恢复通知】%n" +
|
||||
"探针ID: %s%n" +
|
||||
"探针名称: %s%n" +
|
||||
"探针IP: %s%n" +
|
||||
"恢复时间: %s%n" +
|
||||
"状态: 已恢复正常",
|
||||
probe.getCollectId(),
|
||||
probe.getCollectName() != null ? probe.getCollectName() : "未知",
|
||||
probe.getDeviceIp(),
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||
);
|
||||
|
||||
try {
|
||||
WecomNotification notification = wecomNotificationService.sendAlert(
|
||||
"探针恢复-" + probe.getCollectId(),
|
||||
"probe_recovery",
|
||||
"1", // 低
|
||||
content,
|
||||
probe.getDeviceIp()
|
||||
);
|
||||
logger.info("发送探针恢复通知成功, 通知ID: {}", notification.getWecomNotificationId());
|
||||
} catch (Exception e) {
|
||||
logger.error("发送探针恢复通知失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理历史记录
|
||||
* @param daysToKeep 保留天数
|
||||
* @return 删除的记录数
|
||||
*/
|
||||
public long cleanupHistory(int daysToKeep) {
|
||||
LocalDateTime beforeTime = LocalDateTime.now().minusDays(daysToKeep);
|
||||
long count = historyMapper.countBeforeTime(beforeTime);
|
||||
if (count > 0) {
|
||||
int deleted = historyMapper.deleteBeforeTime(beforeTime);
|
||||
logger.info("清理心跳历史记录: 删除 {} 条, 保留 {} 天前的数据", deleted, daysToKeep);
|
||||
return deleted;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定探针的告警标记(手动恢复)
|
||||
*/
|
||||
public void clearAlertFlag(String collectId) {
|
||||
alertedProbes.remove(collectId);
|
||||
logger.info("清除探针 {} 的告警标记", collectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取离线阈值配置
|
||||
*/
|
||||
public int getOfflineThresholdMinutes() {
|
||||
return offlineThresholdMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 探针心跳数据DTO
|
||||
*/
|
||||
public static class ProbeHeartbeatData {
|
||||
private String collectId;
|
||||
private String collectName;
|
||||
private String deviceIp;
|
||||
private String appVersion;
|
||||
private String loadStatus;
|
||||
|
||||
public String getCollectId() { return collectId; }
|
||||
public void setCollectId(String collectId) { this.collectId = collectId; }
|
||||
public String getCollectName() { return collectName; }
|
||||
public void setCollectName(String collectName) { this.collectName = collectName; }
|
||||
public String getDeviceIp() { return deviceIp; }
|
||||
public void setDeviceIp(String deviceIp) { this.deviceIp = deviceIp; }
|
||||
public String getAppVersion() { return appVersion; }
|
||||
public void setAppVersion(String appVersion) { this.appVersion = appVersion; }
|
||||
public String getLoadStatus() { return loadStatus; }
|
||||
public void setLoadStatus(String loadStatus) { this.loadStatus = loadStatus; }
|
||||
}
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
package com.haobang.controller;
|
||||
|
||||
import com.common.entity.DeviceCollectHeartbeat;
|
||||
import com.common.service.ProbeHeartbeatService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 探针心跳接收接口
|
||||
* 提供给探针端(syslog-serve)调用
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/interlocking/probe")
|
||||
public class ProbeHeartbeatController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProbeHeartbeatController.class);
|
||||
|
||||
@Autowired
|
||||
private ProbeHeartbeatService probeHeartbeatService;
|
||||
|
||||
@Value("${interlocking.api-key:}")
|
||||
private String expectedApiKey;
|
||||
|
||||
/**
|
||||
* 接收探针心跳
|
||||
* POST /interlocking/probe/heartbeat
|
||||
*
|
||||
* Headers: X-API-KEY: {api-key}
|
||||
* Body: {
|
||||
* "collectId": "probe-001",
|
||||
* "collectName": "测试探针",
|
||||
* "deviceIp": "192.168.1.100",
|
||||
* "appVersion": "1.0.0",
|
||||
* "loadStatus": "{}"
|
||||
* }
|
||||
*/
|
||||
@PostMapping("/heartbeat")
|
||||
public ResponseEntity<Map<String, Object>> receiveHeartbeat(
|
||||
@RequestHeader(value = "X-API-KEY", required = false) String apiKey,
|
||||
@RequestBody ProbeHeartbeatService.ProbeHeartbeatData heartbeatData) {
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
// 验证API Key
|
||||
if (expectedApiKey != null && !expectedApiKey.isEmpty()
|
||||
&& !expectedApiKey.equals(apiKey)) {
|
||||
result.put("code", 401);
|
||||
result.put("message", "API Key验证失败");
|
||||
logger.warn("探针心跳请求API Key验证失败");
|
||||
return ResponseEntity.status(401).body(result);
|
||||
}
|
||||
|
||||
// 验证必填字段
|
||||
if (heartbeatData.getCollectId() == null || heartbeatData.getCollectId().isEmpty()) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "collectId不能为空");
|
||||
return ResponseEntity.badRequest().body(result);
|
||||
}
|
||||
|
||||
try {
|
||||
DeviceCollectHeartbeat heartbeat = probeHeartbeatService.receiveHeartbeat(heartbeatData);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("collectId", heartbeat.getCollectId());
|
||||
data.put("status", heartbeat.getStatus());
|
||||
data.put("lastHeartbeat", heartbeat.getLastHeartbeat().toString());
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", data);
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("处理探针心跳异常: {}", e.getMessage(), e);
|
||||
result.put("code", 500);
|
||||
result.put("message", "处理心跳失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有探针状态
|
||||
* GET /interlocking/probe/list
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public ResponseEntity<Map<String, Object>> getAllProbes(
|
||||
@RequestHeader(value = "X-API-KEY", required = false) String apiKey) {
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (expectedApiKey != null && !expectedApiKey.isEmpty()
|
||||
&& !expectedApiKey.equals(apiKey)) {
|
||||
result.put("code", 401);
|
||||
result.put("message", "API Key验证失败");
|
||||
return ResponseEntity.status(401).body(result);
|
||||
}
|
||||
|
||||
try {
|
||||
List<DeviceCollectHeartbeat> probes = probeHeartbeatService.getAllProbes();
|
||||
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", probes);
|
||||
result.put("total", probes.size());
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取探针列表异常: {}", e.getMessage(), e);
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取探针列表失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在线探针列表
|
||||
* GET /interlocking/probe/online
|
||||
*/
|
||||
@GetMapping("/online")
|
||||
public ResponseEntity<Map<String, Object>> getOnlineProbes(
|
||||
@RequestHeader(value = "X-API-KEY", required = false) String apiKey) {
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (expectedApiKey != null && !expectedApiKey.isEmpty()
|
||||
&& !expectedApiKey.equals(apiKey)) {
|
||||
result.put("code", 401);
|
||||
result.put("message", "API Key验证失败");
|
||||
return ResponseEntity.status(401).body(result);
|
||||
}
|
||||
|
||||
try {
|
||||
List<DeviceCollectHeartbeat> probes = probeHeartbeatService.getOnlineProbes();
|
||||
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", probes);
|
||||
result.put("total", probes.size());
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取在线探针列表异常: {}", e.getMessage(), e);
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取在线探针列表失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取离线探针列表
|
||||
* GET /interlocking/probe/offline
|
||||
*/
|
||||
@GetMapping("/offline")
|
||||
public ResponseEntity<Map<String, Object>> getOfflineProbes(
|
||||
@RequestHeader(value = "X-API-KEY", required = false) String apiKey) {
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (expectedApiKey != null && !expectedApiKey.isEmpty()
|
||||
&& !expectedApiKey.equals(apiKey)) {
|
||||
result.put("code", 401);
|
||||
result.put("message", "API Key验证失败");
|
||||
return ResponseEntity.status(401).body(result);
|
||||
}
|
||||
|
||||
try {
|
||||
List<DeviceCollectHeartbeat> probes = probeHeartbeatService.getOfflineProbes();
|
||||
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", probes);
|
||||
result.put("total", probes.size());
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取离线探针列表异常: {}", e.getMessage(), e);
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取离线探针列表失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个探针状态
|
||||
* GET /interlocking/probe/{collectId}
|
||||
*/
|
||||
@GetMapping("/{collectId}")
|
||||
public ResponseEntity<Map<String, Object>> getProbe(
|
||||
@RequestHeader(value = "X-API-KEY", required = false) String apiKey,
|
||||
@PathVariable String collectId) {
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (expectedApiKey != null && !expectedApiKey.isEmpty()
|
||||
&& !expectedApiKey.equals(apiKey)) {
|
||||
result.put("code", 401);
|
||||
result.put("message", "API Key验证失败");
|
||||
return ResponseEntity.status(401).body(result);
|
||||
}
|
||||
|
||||
try {
|
||||
DeviceCollectHeartbeat probe = probeHeartbeatService.getProbeById(collectId);
|
||||
|
||||
if (probe == null) {
|
||||
result.put("code", 404);
|
||||
result.put("message", "探针不存在");
|
||||
return ResponseEntity.status(404).body(result);
|
||||
}
|
||||
|
||||
result.put("code", 200);
|
||||
result.put("message", "success");
|
||||
result.put("data", probe);
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取探针状态异常: {}", e.getMessage(), e);
|
||||
result.put("code", 500);
|
||||
result.put("message", "获取探针状态失败: " + e.getMessage());
|
||||
return ResponseEntity.status(500).body(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 健康检查
|
||||
* GET /interlocking/probe/health
|
||||
*/
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<Map<String, Object>> health() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 200);
|
||||
result.put("message", "OK");
|
||||
result.put("service", "probe-heartbeat-api");
|
||||
result.put("timestamp", java.time.LocalDateTime.now().toString());
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,7 @@ public class InfluxDBClient implements AutoCloseable {
|
||||
public void writePoint(Point point) {
|
||||
try {
|
||||
writeApi.writePoint(point);
|
||||
// 优雅关闭 WriteApi,确保数据发送完成
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to write point to InfluxDB: {}", e.getMessage());
|
||||
throw e;
|
||||
|
||||
@@ -156,7 +156,7 @@ analysis.realtime.check-interval-seconds: 10
|
||||
# API-KEY认证(32位,建议使用随机生成的密钥)
|
||||
interlocking.api-key=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
# API接口基础URL(供syslog-serve调用)
|
||||
interlocking.api.base-url=http://localhost:8089/xdrservice/interlocking
|
||||
interlocking.api.base-url=http://192.168.222.131:8089/xdrservice/interlocking
|
||||
|
||||
# ============================================
|
||||
# 告警健康检查配置
|
||||
@@ -166,4 +166,23 @@ alarm.health-check.alarm-hours=2
|
||||
# 告警日志表无数据阈值(小时)
|
||||
alarm.health-check.alarm-visit-hours=4
|
||||
# 是否启用定时巡检
|
||||
alarm.health-check.enabled=true
|
||||
alarm.health-check.enabled=true
|
||||
|
||||
|
||||
# ============================================
|
||||
# 探针心跳检测配置
|
||||
# ============================================
|
||||
# 是否启用心跳检测
|
||||
probe.heartbeat.enabled=true
|
||||
# 探针离线阈值(分钟),超过此时间未收到心跳则判定为离线
|
||||
probe.heartbeat.offline-threshold-minutes=10
|
||||
# 状态检查Cron表达式(默认每10分钟)
|
||||
probe.status.check.cron=0 */10 * * * ?
|
||||
# 探针租户ID
|
||||
probe.heartbeat.tenant-id=000000
|
||||
# 心跳历史保留天数
|
||||
probe.heartbeat.history.keep-days=10
|
||||
# 是否启用历史清理
|
||||
probe.heartbeat.history.cleanup-enabled=true
|
||||
# 历史清理Cron表达式(默认每天凌晨1点)
|
||||
probe.history.cleanup.cron=0 0 1 * * ?
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
#Server Configuration
|
||||
server.port=8089
|
||||
server.servlet.context-path=/xdrservice
|
||||
#server.address=0.0.0.0
|
||||
server.tomcat.uri-encoding=UTF-8
|
||||
server.error.include-message=always
|
||||
server.error.include-binding-errors=always
|
||||
|
||||
#run.environment: dev|test|pro
|
||||
server.run.environment=pro
|
||||
|
||||
|
||||
# Syslog Server Configuration
|
||||
syslog.tcp.port=514
|
||||
syslog.udp.port=514
|
||||
syslog.max.frame.length=65536
|
||||
syslog.buffer.size=1000
|
||||
syslog.sm4.generateKey=f79548ab6fa8a304fc0115e17230358a
|
||||
|
||||
# InfluxDB 2.7 Configuration
|
||||
influxdb.url=http://10.150 81.211:8087
|
||||
influxdb.token=LFjXZyRxTf1V84oN-wwjhSjS4qIK-ZMoHzQJB67ir3qHNSBVJbMcTkPuNmM0cNxvzFEDWLYNzrz1VJKMitY5hw==
|
||||
influxdb.org=influxdb
|
||||
influxdb.bucket=yelangbucket
|
||||
influxdb.batch.size=1000
|
||||
influxdb.flush.interval=1000
|
||||
influxdb.retry.attempts=3
|
||||
influxdb.retry.delay=1000
|
||||
# InfluxDB 2.7 连接超时配置
|
||||
influxdb.connection.timeout=30s
|
||||
influxdb.connection.read-timeout=30s
|
||||
influxdb.connection.write-timeout=60s
|
||||
# Application Configuration
|
||||
app.worker.threads=8
|
||||
app.max.queue.size=10000
|
||||
app.metrics.enabled=true
|
||||
|
||||
|
||||
#database Configuration
|
||||
spring.datasource.url=jdbc:postgresql://10.150 81.209:5432/ecosys
|
||||
spring.datasource.username=postgres
|
||||
spring.datasource.password=caZ2TcmXNSW8L2Ap
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
|
||||
# mybatis Configuration
|
||||
mybatis.mapper-locations=classpath:mapper/*.xml
|
||||
mybatis.type-aliases-package=com.common.entity
|
||||
#mybatis handler 类
|
||||
mybatis.configuration.default-statement-timeout=30
|
||||
mybatis.configuration.default-fetch-size=1000
|
||||
mybatis.configuration.map-underscore-to-camel-case=true
|
||||
mybatis.type-handlers-package=com.Modules.etl.handler
|
||||
mybatis-plus.configuration.map-underscore-to-camel-case=true
|
||||
mybatis-plus.type-handlers-package=com.Modules.etl.handler
|
||||
|
||||
# kafka Configuration
|
||||
spring.kafka.consumer.bootstrap-servers=10.150 81.211:9092
|
||||
spring.kafka.consumer.group-id=agent-syslog-group
|
||||
spring.kafka.consumer.auto-offset-reset=latest
|
||||
spring.kafka.consumer.enable-auto-commit=false
|
||||
spring.kafka.consumer.auto-commit-interval=1000
|
||||
spring.kafka.consumer.topic=agent-syslog-topic
|
||||
|
||||
|
||||
spring.kafka.consumer.max-poll-records=1000
|
||||
spring.kafka.consumer.properties.max.poll.interval.ms=300000
|
||||
spring.kafka.consumer.properties.session.timeout.ms=45000
|
||||
|
||||
spring.kafka.consumer.fetch-min-size= 1048576
|
||||
spring.kafka.listener.ack-mode= manual
|
||||
spring.kafka.listener.concurrency= 2
|
||||
spring.kafka.listener.type=batch
|
||||
|
||||
|
||||
# 定时任务配置
|
||||
spring.task.scheduling.pool.size=10
|
||||
|
||||
# 日志配置
|
||||
logging.level.com.common.schedule=INFO
|
||||
logging.level.com.common.service=INFO
|
||||
|
||||
# 分区表检查配置
|
||||
partition.check.tomorrow.enabled=true
|
||||
partition.check.future.days=7
|
||||
partition.auto.create=true
|
||||
|
||||
|
||||
# 生产环境缓存配置
|
||||
spring.redis.host=192.168.4.26
|
||||
spring.redis.port=6379
|
||||
# 密码(如果没有设置密码,可以省略)
|
||||
spring.redis.password=123456
|
||||
spring.redis.database=0
|
||||
spring.redis.timeout=5000
|
||||
#spring.redis.password=${REDIS_PASSWORD:default_prod_password}
|
||||
|
||||
spring.redis.lettuce.pool.max-active=20
|
||||
spring.redis.lettuce.pool.max-wait=5000
|
||||
spring.redis.lettuce.pool.max-idle=10
|
||||
spring.redis.lettuce.pool.min-idle=5
|
||||
|
||||
# 生产环境缓存时间较长
|
||||
spring.cache.redis.time-to-live=3600000
|
||||
|
||||
# 应用处理器配置
|
||||
app.processor.thread-pool.core-pool-size=10
|
||||
app.processor.thread-pool.max-pool-size=20
|
||||
app.processor.thread-pool.queue-capacity=2000
|
||||
app.processor.thread-pool.keep-alive-seconds=60
|
||||
app.processor.batch-size=100
|
||||
app.processor.process-timeout-ms=30000
|
||||
|
||||
|
||||
# 配置 Elasticsearch
|
||||
# Elasticsearch连接地址
|
||||
spring.elasticsearch.uris=http://192.168.1.174:9200
|
||||
# 配置 Elasticsearch 用户名
|
||||
spring.elasticsearch.username=CONTAINER_NAME
|
||||
# 配置 Elasticsearch 密码
|
||||
spring.elasticsearch.password=t2NZCiajmdazxBrF
|
||||
# 连接超时时间
|
||||
spring.elasticsearch.connection-timeout=10s
|
||||
# Socket 超时时间
|
||||
spring.elasticsearch.socket-timeout=30s
|
||||
|
||||
|
||||
# ETL配置
|
||||
etl.batch.page-size=1000
|
||||
etl.batch.insert-batch-size=500
|
||||
etl.schedule.cron=0 0 2 * * ?
|
||||
|
||||
|
||||
# ============================================
|
||||
# HikariCP Connection Pool Configuration
|
||||
# ============================================
|
||||
spring.datasource.hikari.maximum-pool-size=50
|
||||
spring.datasource.hikari.minimum-idle=5
|
||||
spring.datasource.hikari.connection-timeout=30000
|
||||
spring.datasource.hikari.idle-timeout=600000
|
||||
spring.datasource.hikari.max-lifetime=900000
|
||||
spring.datasource.hikari.connection-test-query=SELECT 1
|
||||
spring.datasource.hikari.validation-timeout=5000
|
||||
spring.datasource.hikari.leak-detection-threshold=30000
|
||||
spring.datasource.hikari.pool-name=HikariPool-SyslogConsumer
|
||||
spring.datasource.hikari.auto-commit=false
|
||||
spring.datasource.hikari.schema=public
|
||||
|
||||
|
||||
# 关联分析规则配置
|
||||
analysis.realtime.enabled= true
|
||||
# 检查间隔(秒) - 默认10秒
|
||||
analysis.realtime.check-interval-seconds: 10
|
||||
|
||||
# ============================================
|
||||
# 探针联动API配置
|
||||
# ============================================
|
||||
# API-KEY认证(32位,建议使用随机生成的密钥)
|
||||
interlocking.api-key=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
# API接口基础URL(供syslog-serve调用)
|
||||
interlocking.api.base-url=http://10.150 81.210:8089/xdrservice/interlocking
|
||||
|
||||
# ============================================
|
||||
# 告警健康检查配置
|
||||
# ============================================
|
||||
# 告警表无数据阈值(小时)
|
||||
alarm.health-check.alarm-hours=2
|
||||
# 告警日志表无数据阈值(小时)
|
||||
alarm.health-check.alarm-visit-hours=4
|
||||
# 是否启用定时巡检
|
||||
alarm.health-check.enabled=true
|
||||
|
||||
# ============================================
|
||||
# 探针心跳检测配置
|
||||
# ============================================
|
||||
# 是否启用心跳检测
|
||||
probe.heartbeat.enabled=true
|
||||
# 探针离线阈值(分钟),超过此时间未收到心跳则判定为离线
|
||||
probe.heartbeat.offline-threshold-minutes=10
|
||||
# 状态检查Cron表达式(默认每10分钟)
|
||||
probe.status.check.cron=0 */10 * * * ?
|
||||
# 探针租户ID
|
||||
probe.heartbeat.tenant-id=000000
|
||||
# 心跳历史保留天数
|
||||
probe.heartbeat.history.keep-days=10
|
||||
# 是否启用历史清理
|
||||
probe.heartbeat.history.cleanup-enabled=true
|
||||
# 历史清理Cron表达式(默认每天凌晨1点)
|
||||
probe.history.cleanup.cron=0 0 1 * * ?
|
||||
+20
-2
@@ -157,7 +157,7 @@ analysis.realtime.check-interval-seconds: 10
|
||||
# API-KEY认证(32位,建议使用随机生成的密钥)
|
||||
interlocking.api-key=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
# API接口基础URL(供syslog-serve调用)
|
||||
interlocking.api.base-url=http://localhost:8089/xdrservice/interlocking
|
||||
interlocking.api.base-url=http://192.168.4.26:8089/xdrservice/interlocking
|
||||
|
||||
# ============================================
|
||||
# 告警健康检查配置
|
||||
@@ -167,4 +167,22 @@ alarm.health-check.alarm-hours=2
|
||||
# 告警日志表无数据阈值(小时)
|
||||
alarm.health-check.alarm-visit-hours=4
|
||||
# 是否启用定时巡检
|
||||
alarm.health-check.enabled=true
|
||||
alarm.health-check.enabled=true
|
||||
|
||||
# ============================================
|
||||
# 探针心跳检测配置
|
||||
# ============================================
|
||||
# 是否启用心跳检测
|
||||
probe.heartbeat.enabled=true
|
||||
# 探针离线阈值(分钟),超过此时间未收到心跳则判定为离线
|
||||
probe.heartbeat.offline-threshold-minutes=10
|
||||
# 状态检查Cron表达式(默认每10分钟)
|
||||
probe.status.check.cron=0 */10 * * * ?
|
||||
# 探针租户ID
|
||||
probe.heartbeat.tenant-id=000000
|
||||
# 心跳历史保留天数
|
||||
probe.heartbeat.history.keep-days=10
|
||||
# 是否启用历史清理
|
||||
probe.heartbeat.history.cleanup-enabled=true
|
||||
# 历史清理Cron表达式(默认每天凌晨1点)
|
||||
probe.history.cleanup.cron=0 0 1 * * ?
|
||||
@@ -157,7 +157,7 @@ analysis.realtime.check-interval-seconds: 10
|
||||
# API-KEY认证(32位,建议使用随机生成的密钥)
|
||||
interlocking.api-key=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
||||
# API接口基础URL(供syslog-serve调用)
|
||||
interlocking.api.base-url=http://localhost:8089/xdrservice/interlocking
|
||||
interlocking.api.base-url=http://192.168.4.26:8089/xdrservice/interlocking
|
||||
|
||||
# ============================================
|
||||
# 告警健康检查配置
|
||||
@@ -167,4 +167,22 @@ alarm.health-check.alarm-hours=2
|
||||
# 告警日志表无数据阈值(小时)
|
||||
alarm.health-check.alarm-visit-hours=4
|
||||
# 是否启用定时巡检
|
||||
alarm.health-check.enabled=true
|
||||
alarm.health-check.enabled=true
|
||||
|
||||
# ============================================
|
||||
# 探针心跳检测配置
|
||||
# ============================================
|
||||
# 是否启用心跳检测
|
||||
probe.heartbeat.enabled=true
|
||||
# 探针离线阈值(分钟),超过此时间未收到心跳则判定为离线
|
||||
probe.heartbeat.offline-threshold-minutes=10
|
||||
# 状态检查Cron表达式(默认每10分钟)
|
||||
probe.status.check.cron=0 */10 * * * ?
|
||||
# 探针租户ID
|
||||
probe.heartbeat.tenant-id=000000
|
||||
# 心跳历史保留天数
|
||||
probe.heartbeat.history.keep-days=10
|
||||
# 是否启用历史清理
|
||||
probe.heartbeat.history.cleanup-enabled=true
|
||||
# 历史清理Cron表达式(默认每天凌晨1点)
|
||||
probe.history.cleanup.cron=0 0 1 * * ?
|
||||
Reference in New Issue
Block a user