调试agent本地存储流量功能

This commit is contained in:
gaoyutao
2026-01-21 18:12:35 +08:00
parent 3820d11353
commit 421b7f1073
5 changed files with 215 additions and 25 deletions
@@ -75,6 +75,8 @@ public enum MsgEnum {
iops结果上报("IOPS_RESULT"),
tcpdump结果上报("TCPDUMP_RESULT"),
多网IP探测上报("NETWORK_DETECT");
private String value;
@@ -105,8 +105,8 @@ public class AppInitializer implements CommandLineRunner {
AssertLog.info("启动frpc状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 300000);
dynamicTaskService.scheduleTask("upFrpcMsg", businessTasks::upFrpcMsgTask, 15000, 300000);
long milliFive = AgentUtil.millisecondsToNext5Minute();
AssertLog.info("启动本地存储流量信息上报定时任务 - 延迟: {}ms, 间隔: {}ms", milliFive, 960000);
dynamicTaskService.scheduleTask("upTempTraffic", businessTasks::upTempTraffic, milliFive, 960000);
AssertLog.info("启动本地存储流量信息上报定时任务 - 延迟: {}ms, 间隔: {}ms", milliFive, 7200000);
dynamicTaskService.scheduleTask("upTempTraffic", businessTasks::upTempTraffic, milliFive, 7200000);
AssertLog.info("检测PppoE配置");
agentService.handleRebootRecovery();
}else{
@@ -876,8 +876,8 @@ public class BusinessTasks {
AssertLog.info("启动frpc状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 300000);
dynamicTaskService.scheduleTask("upFrpcMsg", businessTasks::upFrpcMsgTask, 15000, 300000);
long milliFive = AgentUtil.millisecondsToNext5Minute();
AssertLog.info("启动本地存储流量信息上报定时任务 - 延迟: {}ms, 间隔: {}ms", milliFive, 960000);
dynamicTaskService.scheduleTask("upTempTraffic", businessTasks::upTempTraffic, milliFive, 960000);
AssertLog.info("启动本地存储流量信息上报定时任务 - 延迟: {}ms, 间隔: {}ms", milliFive, 7200000);
dynamicTaskService.scheduleTask("upTempTraffic", businessTasks::upTempTraffic, milliFive, 7200000);
AssertLog.info("检测PppoE配置");
agentService.handleRebootRecovery();
}else{
@@ -1,5 +1,8 @@
package com.tongran.agent.client.scheduler.task;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.tongran.agent.client.core.config.ApplicationProperties;
import com.tongran.agent.client.core.config.GlobalConfig;
@@ -11,15 +14,18 @@ import com.tongran.agent.client.service.AgentService;
import com.tongran.agent.client.utils.AgentDataUtil;
import com.tongran.agent.client.utils.AgentUtil;
import com.tongran.agent.client.utils.AssertLog;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -40,6 +46,20 @@ public class SpecificTimeTaskService {
this.sessionManager = SessionManager.getInstance();
}
public boolean createTcpdumpSpecificTimeTask(SpecificTimeRequest request){
String taskId = request.getTaskId();
Runnable task = createTcpdumpTaskRunnable(request);
try {
if (request.getTime() != null) {
taskConfig.addDailyTimeTask(taskId, task, request.getTime());
} else {
throw new IllegalArgumentException("必须指定一种时间方式");
}
return true;
} catch (Exception e) {
throw new RuntimeException("创建任务失败: " + e.getMessage(), e);
}
}
/**
* 创建指定时间任务
*/
@@ -67,13 +87,148 @@ public class SpecificTimeTaskService {
}
}
private Runnable createTcpdumpTaskRunnable(SpecificTimeRequest request) {
return () -> {
System.out.println("执行定时任务: " + request.getTaskName());
System.out.println("执行时间: " + LocalDateTime.now());
System.out.println("-----------------------------------");
// 具体的业务逻辑
executeTcpdump(request);
};
}
private void executeTcpdump(SpecificTimeRequest request) {
try {
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
String pcapFileName = timestamp + ".pcap";
// 第一步:执行tcpdump命令捕获数据
ProcessBuilder captureBuilder = new ProcessBuilder();
captureBuilder.command("timeout", "10", "tcpdump", "-i", "eth0", "-nn", "-n", "-w", pcapFileName);
Process captureProcess = captureBuilder.start();
int captureExitCode = captureProcess.waitFor();
if (captureExitCode != 0) {
AssertLog.error("Tcpdump capture failed with exit code: {}", captureExitCode);
return;
}
// 等待文件写入完成
Thread.sleep(1000);
// 第二步:分析pcap文件并统计目标IP
ProcessBuilder analyzeBuilder = new ProcessBuilder();
analyzeBuilder.command("bash", "-c",
"tcpdump -r " + pcapFileName + " -nn | awk '/IP/{split($5,a,\".\"); print a[1]\".\"a[2]\".\"a[3]\".\"a[4]}' | sort | uniq -c | sort -rn");
Process analyzeProcess = analyzeBuilder.start();
// 读取分析结果
BufferedReader reader = new BufferedReader(new InputStreamReader(analyzeProcess.getInputStream()));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line).append("\n");
}
int analyzeExitCode = analyzeProcess.waitFor();
if (analyzeExitCode == 0) {
AssertLog.info("Tcpdump analysis completed successfully for task: {}", request.getTaskId());
AssertLog.info("IP statistics:\n{}", result.toString());
// 解析并保存结果
saveTcpdumpResult(request, pcapFileName, result.toString());
} else {
AssertLog.error("Tcpdump analysis failed with exit code: {}", analyzeExitCode);
}
} catch (IOException | InterruptedException e) {
AssertLog.error("Error executing tcpdump task: {}", request.getTaskId(), e);
Thread.currentThread().interrupt();
}
}
private void saveTcpdumpResult(SpecificTimeRequest request, String fileName, String statistics) {
try {
// 解析统计结果
List<IpCount> ipCountList = parseTcpdumpOutput(statistics);
AssertLog.info("Saving tcpdump result - Task: {}, File: {}, Total unique IPs: {}",
request.getTaskId(), fileName, ipCountList.size());
String data = "";
if(CollectionUtil.isNotEmpty(ipCountList)){
data = JSONArray.toJSONString(ipCountList);
}
Message message = Message.builder().clientId(request.getClientId()).dataType(MsgEnum.tcpdump结果上报.getValue()).data(data).build();
if (Objects.nonNull(sessionManager.getSessionById(request.getClientId()))) {
sessionManager.writeAndFlush(sessionManager.getSessionById(request.getClientId()).getChannel(), message);
AssertLog.info("发送tcpdump包={}", JSON.toJSONString(message));
}
} catch (Exception e) {
AssertLog.error("Failed to parse tcpdump result for task: {}", request.getTaskId(), e);
}
}
/**
* 解析tcpdump输出为IP统计列表
*/
private List<IpCount> parseTcpdumpOutput(String output) {
List<IpCount> ipCountList = new ArrayList<>();
if (output == null || output.trim().isEmpty()) {
return ipCountList;
}
String[] lines = output.split("\n");
for (String line : lines) {
line = line.trim();
// 跳过空行和标题行
if (line.isEmpty() || line.contains("reading from file") || line.contains("link-type")) {
continue;
}
// 解析格式: " 455 172.16.15.52"
String[] parts = line.trim().split("\\s+", 2); // 按空格分割,最多分成2部分
if (parts.length >= 2) {
try {
int count = Integer.parseInt(parts[0].trim());
String ip = parts[1].trim();
ipCountList.add(new IpCount(ip, count));
} catch (NumberFormatException e) {
AssertLog.warn("Failed to parse count from line: {}", line);
}
}
}
return ipCountList;
}
/**
* IP统计实体类
*/
@Data
@AllArgsConstructor
public static class IpCount {
private String ip;
private int count;
}
private Runnable createTaskRunnable(SpecificTimeRequest request) {
return () -> {
System.out.println("执行定时任务: " + request.getTaskName());
System.out.println("任务数据: " + request.getTaskData());
System.out.println("执行时间: " + LocalDateTime.now());
System.out.println("-----------------------------------");
// 具体的业务逻辑
executeBusinessLogic(request);
};
@@ -153,4 +308,16 @@ public class SpecificTimeTaskService {
System.err.println("任务执行异常: " + e.getMessage());
}
}
public void cancleTcpdumpSpecificTimeTask() {
// 获取所有任务ID
Set<String> taskIds = taskConfig.getTaskMap().keySet();
// 遍历并关闭所有以"tcpdump"开头的任务
for (String taskId : taskIds) {
if (taskId.startsWith("tcpdump")) {
taskConfig.removeTask(taskId);
}
}
}
}
@@ -322,8 +322,8 @@ public class AgentServiceImpl implements AgentService {
AssertLog.info("启动frpc状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 300000);
dynamicTaskService.scheduleTask("upFrpcMsg", businessTasks::upFrpcMsgTask, 15000, 300000);
long milliFive = AgentUtil.millisecondsToNext5Minute();
AssertLog.info("启动本地存储流量信息上报定时任务 - 延迟: {}ms, 间隔: {}ms", milliFive, 960000);
dynamicTaskService.scheduleTask("upTempTraffic", businessTasks::upTempTraffic, milliFive, 960000);
AssertLog.info("启动本地存储流量信息上报定时任务 - 延迟: {}ms, 间隔: {}ms", milliFive, 7200000);
dynamicTaskService.scheduleTask("upTempTraffic", businessTasks::upTempTraffic, milliFive, 7200000);
AssertLog.info("检测PppoE配置");
handleRebootRecovery();
}
@@ -920,21 +920,42 @@ public class AgentServiceImpl implements AgentService {
}
if(jsonObject.containsKey("trafficUsedTimestamp")){
String trafficUsedTimestamp = jsonObject.getString("trafficUsedTimestamp");
// if (trafficUsedTimestamp != null) {
// String[] fileNames = trafficUsedTimestamp.split(",");
//
// // 删除对应文件
// for (String fileName : fileNames) {
// if (StringUtils.isNotBlank(fileName)) {
// fileName = fileName+"conf";
// String filePath = properties.getTempTrafficPath() + fileName.trim();
// AssertLog.info("已处理文件:{}", fileName);
// deleteTrafficFile(filePath);
// }
// }
// }
if (trafficUsedTimestamp != null) {
String[] fileNames = trafficUsedTimestamp.split(",");
// 删除对应文件
for (String fileName : fileNames) {
if (StringUtils.isNotBlank(fileName)) {
fileName = fileName+"conf";
String filePath = properties.getTempTrafficPath() + fileName.trim();
AssertLog.info("已处理文件:{}", fileName);
deleteTrafficFile(filePath);
}
}
}
}
if(jsonObject.containsKey("tcpdumpTimes")){
String tcpdumpTimes = jsonObject.getString("tcpdumpTimes");
handleTcpdump(tcpdumpTimes);
}
}
private void handleTcpdump(String tcpdumpTimes) {
taskService.cancleTcpdumpSpecificTimeTask();
if(!"".equals(tcpdumpTimes)){
String[] tcpdumpTimeArr = tcpdumpTimes.split(",");
for (String tcpdumpTime : tcpdumpTimeArr) {
SpecificTimeRequest request = SpecificTimeRequest.builder()
.taskId("tcpdump"+tcpdumpTime)
.taskName("tcpdump"+tcpdumpTime)
.time(tcpdumpTime)
.clientId(GlobalConfig.CLIENT_ID)
.build();
taskService.createTcpdumpSpecificTimeTask(request);
}
}
}
private void deleteTrafficFile(String filePath) {
try {
File file = new File(filePath);
@@ -2314,8 +2335,8 @@ public class AgentServiceImpl implements AgentService {
// 配置参数
int batchSize = 10; // 每批10个文件
long intraBatchInterval = 5000; // 批次内文件间隔5s
long interBatchInterval = 1000; // 批次间间隔10
long intraBatchInterval = 1000; // 批次内文件间隔5s
long interBatchInterval = 1000; // 批次间间隔1秒
int totalProcessed = 0;
int totalFiles = fileList.size();