diff --git a/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java b/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java index ffd4ac2..b5ac2d6 100644 --- a/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java +++ b/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java @@ -143,7 +143,7 @@ public class GlobalConfig { * 告警 */ public static boolean IS_ALARM = false; - public static long ALARM_INTERVAL = 120; + public static long ALARM_INTERVAL = 60; public static List ALARM_LIST; //告警设置信息 /** * 告警监控 @@ -163,4 +163,9 @@ public class GlobalConfig { */ public static List NET_LIST; + /** + * 脚本文件下载标识 + */ + public static LinkedHashMap DOWN_FILES = new LinkedHashMap<>(); + } diff --git a/src/main/java/com/tongran/agent/client/core/eo/ScriptPolicyEO.java b/src/main/java/com/tongran/agent/client/core/eo/ScriptPolicyEO.java index 8222969..e75da24 100644 --- a/src/main/java/com/tongran/agent/client/core/eo/ScriptPolicyEO.java +++ b/src/main/java/com/tongran/agent/client/core/eo/ScriptPolicyEO.java @@ -6,7 +6,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; -import java.time.LocalDateTime; import java.util.List; @Data @@ -17,6 +16,7 @@ public class ScriptPolicyEO implements Serializable { private static final long serialVersionUID = -1267013167162440612L; + private String policyName; /** * 文件 */ @@ -32,7 +32,7 @@ public class ScriptPolicyEO implements Serializable { private int method; //执行方式为1、定时执行时必传-指定时间 - private LocalDateTime policyTime; + private long policyTime; @Data diff --git a/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java b/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java index 1b13b4c..06cb767 100644 --- a/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java +++ b/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java @@ -11,7 +11,6 @@ import com.tongran.agent.client.core.eo.AlarmEO; import com.tongran.agent.client.core.eo.ScriptPolicyEO; import com.tongran.agent.client.netty.annotation.AgentDispatcher; import com.tongran.agent.client.netty.basics.AgentHandler; -import com.tongran.agent.client.netty.model.Message; import com.tongran.agent.client.netty.model.UpMsgResponse; import com.tongran.agent.client.scheduler.service.AdvancedAsyncDownloader; import com.tongran.agent.client.scheduler.service.AppInitializer; @@ -22,6 +21,7 @@ import com.tongran.agent.client.scheduler.task.SpecificTimeTaskService; 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 org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -203,8 +203,11 @@ public class AgentEndpoint { JSONObject jsonObject = JSONObject.parseObject(data); if(jsonObject.containsKey("alarms")){ String alarms = jsonObject.getString("alarms"); + AssertLog.info("告警设置,alarms={}", alarms); GlobalConfig.ALARM_LIST = JSON.parseObject(alarms, new TypeReference>() {}); + AssertLog.info("告警设置,监控项={}", JSON.toJSONString(GlobalConfig.ALARM_LIST)); if(CollectionUtil.isNotEmpty(GlobalConfig.ALARM_LIST)){ + AssertLog.info("告警设置,is_alarm={}", AgentDataUtil.hasAnyActiveAlarm(GlobalConfig.ALARM_LIST)); GlobalConfig.IS_ALARM = AgentDataUtil.hasAnyActiveAlarm(GlobalConfig.ALARM_LIST); } } @@ -225,12 +228,36 @@ public class AgentEndpoint { public class ScriptPolicyHandler implements AgentHandler { @Override public UpMsgResponse upHandle(String data, String clientId) { - ScriptPolicyEO policy = JSON.parseObject(data, ScriptPolicyEO.class); + JSONObject jsonObject = JSONObject.parseObject(data); + ScriptPolicyEO policy = ScriptPolicyEO.builder().build(); + if(jsonObject.containsKey("policyName")) { + policy.setPolicyName(jsonObject.getString("policyName")); + } + if(jsonObject.containsKey("files")) { + String files = jsonObject.getString("files"); + List fileList = JSON.parseObject(files, new TypeReference>() {}); + policy.setFiles(fileList); + } + if(jsonObject.containsKey("filePath")) { + policy.setFilePath(jsonObject.getString("filePath")); + } + if(jsonObject.containsKey("commands")) { + String commands = jsonObject.getString("commands"); + List commandList = JSON.parseObject(commands, new TypeReference>() {}); + policy.setCommands(commandList); + } + if(jsonObject.containsKey("method")) { + policy.setMethod(jsonObject.getInteger("method")); + } + if(jsonObject.containsKey("policyTime")) { + policy.setPolicyTime(jsonObject.getLong("policyTime")); + } boolean isFalse = false; if(StringUtils.isNotBlank(policy.getFilePath())){ if(AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(policy.getFilePath())){ if(CollectionUtil.isNotEmpty(policy.getFiles())){ isFalse = true; + GlobalConfig.DOWN_FILES.put(policy.getPolicyName(), policy.getFiles().size()); for (ScriptPolicyEO.ScriptFile f : policy.getFiles()) { String finalSaveDir = policy.getFilePath(); //文件类型:0、平台文件地址;1、外网HTTP(S) @@ -244,100 +271,75 @@ public class AgentEndpoint { AgentUtil.base64ToFile(f.getFileData(), filePath); System.out.println("文件保存成功: " + filePath); isFalse = true; + try { + AgentDataUtil.chmod(filePath,"+x"); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } } catch (IOException e) { isFalse = false; System.err.println("文件保存失败: " + e.getMessage()); } }else{ - Java8FileDownloader.DownloadResult result = Java8FileDownloader.downloadFile(f.getFileUrl(), finalSaveDir, f.getFileName()); - // 验证下载是否完成 - if (result.isSuccess()) { - boolean isComplete = Java8FileDownloader.verifyFileCompletion( - result.getFilePath(), result.getExpectedSize()); - if(isComplete){ - isFalse = true; - System.out.println("下载完成: " + finalSaveDir+"/"+f.getFileName()); - }else{ - isFalse = false; - System.err.println("下载失败"); + AdvancedAsyncDownloader.downloadWithProgress(f.getFileUrl(), finalSaveDir, f.getFileName(), progress -> { + System.out.printf("下载进度: %.1f%%\n", progress); + }).thenAccept(filePath -> { + System.out.println("下载完成: " + filePath); + try { + AgentDataUtil.chmod(finalSaveDir+"/"+f.getFileName(),"775"); + int count = GlobalConfig.DOWN_FILES.get(policy.getPolicyName()); + if(count > 1){ + GlobalConfig.DOWN_FILES.put(policy.getPolicyName(), count--); + }else{ + //所有文件下载完成,执行脚本命令 + agentService.command(policy, clientId); + } + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); } - } + }).exceptionally(ex -> { + System.err.println("下载错误: " + ex.getMessage()); + return null; + }); +// Java8FileDownloader.DownloadResult result = Java8FileDownloader.downloadFile(f.getFileUrl(), finalSaveDir, f.getFileName()); +// // 验证下载是否完成 +// if (result.isSuccess()) { +// boolean isComplete = Java8FileDownloader.verifyFileCompletion( +// result.getFilePath(), result.getExpectedSize()); +// if(isComplete){ +// isFalse = true; +// System.out.println("下载完成: " + finalSaveDir+"/"+f.getFileName()); +// try { +// AgentDataUtil.chmod(finalSaveDir+"/"+f.getFileName(),"775"); +// } catch (IOException e) { +// e.printStackTrace(); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// }else{ +// isFalse = false; +// System.err.println("下载失败"); +// } +// } } } } } } - //判断文件是否保存成功 - if(isFalse){ - if(CollectionUtil.isNotEmpty(policy.getCommands())){ - //执行方式:0、立即执行;1、定时执行; - if(policy.getMethod() == 1){ - SpecificTimeRequest request = SpecificTimeRequest.builder() - .taskId("") - .taskName("") - .taskData(policy.getCommands()) - .specificDateTime(policy.getPolicyTime()) - .clientId(clientId) - .build(); - try { - taskService.createSpecificTimeTask(request); - JSONObject json = new JSONObject(); - json.put("resCode",1); - json.put("resMsg", "执行脚本策略定时任务保存成功"); - Message message = Message.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).data(json.toString()).build(); - return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).content(json.toString()).build(); - } catch (Exception e) { - JSONObject json = new JSONObject(); - json.put("resCode",0); - json.put("resMsg", "执行脚本策略定时任务保存失败"); - Message message = Message.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).data(json.toString()).build(); - return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).content(json.toString()).build(); - } - }else{ - List> list = new ArrayList<>(); - for (String command : policy.getCommands()) { - Map map = new HashMap<>(); - List cmd = Arrays.asList(command.split("\\s+")); - CompletableFuture future = - AsyncCommandExecutor.executeCommandAsync( - cmd, - 60, TimeUnit.SECONDS); - future.thenAccept(result -> { - if (result.isSuccess()) { - System.out.println("脚本执行成功"); - System.out.println("[成功resOut] " + result.getOutput()); - map.put("command",command); - map.put("resOut",result.getOutput()); - } else { - System.out.println("脚本执行失败"); - System.out.println("[失败resOut] " + result.getOutput()); - map.put("command",command); - map.put("resOut",result.getOutput()); - } - }).exceptionally(ex -> { - System.err.println("执行失败: " + ex.getMessage()); - map.put("command",command); - map.put("resOut","Policy execute filed"); - return null; - }); - list.add(map); - } - if(CollectionUtil.isNotEmpty(list)){ - JSONObject json = new JSONObject(); - json.put("resCode",1); - json.put("resMsg", ""); - json.put("result", AgentUtil.toJsonString(list)); - return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).content(json.toString()).build(); - } - } - } + //判断是否需要保存文件 + if(!isFalse){ + agentService.command(policy, clientId); + return null; }else{ JSONObject json = new JSONObject(); - json.put("resCode",0); - json.put("resMsg", "A执行脚本策略文件保存失败"); + json.put("resCode",1); + json.put("resMsg", "A执行脚本策略文件保存中"); return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).content(json.toString()).build(); } - return null; } } @@ -440,4 +442,7 @@ public class AgentEndpoint { } + + + } \ No newline at end of file diff --git a/src/main/java/com/tongran/agent/client/netty/handler/AgentDecoderHandler.java b/src/main/java/com/tongran/agent/client/netty/handler/AgentDecoderHandler.java index e001d42..a35a443 100644 --- a/src/main/java/com/tongran/agent/client/netty/handler/AgentDecoderHandler.java +++ b/src/main/java/com/tongran/agent/client/netty/handler/AgentDecoderHandler.java @@ -109,9 +109,10 @@ public class AgentDecoderHandler extends ChannelInboundHandlerAdapter { JSONObject jsonObject = JSONObject.parseObject(message); String clientId = jsonObject.getString("clientId"); String dataType = jsonObject.getString("dataType"); + String data = jsonObject.getString("data"); AgentHandler msgHandler = agentDispatcherManager.getHandler(dataType + "&" + AgentDispatcher.VersionEnum.V1.value); if (ObjectUtil.isNotEmpty(msgHandler)) { - UpMsgResponse response = msgHandler.upHandle(message, clientId ); + UpMsgResponse response = msgHandler.upHandle(data, clientId ); AssertLog.info("<<[up-after-handle]:clientId:{},type={},[handle-content]={}", response.getClientId(), dataType, message); if(Objects.nonNull(response)){ Message agentMessage = Message.builder().build(); diff --git a/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java b/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java index a9e0445..359fb5f 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java +++ b/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java @@ -313,6 +313,7 @@ public class BusinessTasks { if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { String data = ""; List list = alarmService.alarmMonitor(timestamp); + AssertLog.info("告警监控定时任务执行={}", JSON.toJSONString(list)); if(CollectionUtil.isNotEmpty(list)){ data = JSONArray.toJSONString(list); } diff --git a/src/main/java/com/tongran/agent/client/service/AgentService.java b/src/main/java/com/tongran/agent/client/service/AgentService.java index 48617d7..097a36b 100644 --- a/src/main/java/com/tongran/agent/client/service/AgentService.java +++ b/src/main/java/com/tongran/agent/client/service/AgentService.java @@ -1,5 +1,7 @@ package com.tongran.agent.client.service; +import com.tongran.agent.client.core.eo.ScriptPolicyEO; + public interface AgentService { void cancelCollect(); @@ -12,4 +14,6 @@ public interface AgentService { void switchCollectStop(); void alarmMonitor(); + + void command(ScriptPolicyEO policy, String clientId); } diff --git a/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java b/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java index feb789f..de0fd9c 100644 --- a/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java +++ b/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java @@ -1,40 +1,58 @@ package com.tongran.agent.client.service.impl; +import cn.hutool.core.collection.CollectionUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.TypeReference; import com.tongran.agent.client.core.config.GlobalConfig; +import com.tongran.agent.client.core.enums.MsgEnum; import com.tongran.agent.client.core.eo.CollectEO; +import com.tongran.agent.client.core.eo.ScriptPolicyEO; +import com.tongran.agent.client.core.session.SessionManager; +import com.tongran.agent.client.netty.model.Message; +import com.tongran.agent.client.scheduler.service.AsyncCommandExecutor; import com.tongran.agent.client.scheduler.service.BusinessTasks; import com.tongran.agent.client.scheduler.service.DynamicTaskService; +import com.tongran.agent.client.scheduler.task.SpecificTimeRequest; +import com.tongran.agent.client.scheduler.task.SpecificTimeTaskService; import com.tongran.agent.client.service.AgentService; import com.tongran.agent.client.utils.AgentUtil; +import com.tongran.agent.client.utils.AssertLog; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import java.util.List; +import javax.annotation.Resource; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; @Service public class AgentServiceImpl implements AgentService { + protected final SessionManager sessionManager; private final DynamicTaskService dynamicTaskService; private final BusinessTasks businessTasks; + @Resource + private SpecificTimeTaskService taskService; + // 在注入点使用@Lazy @Autowired public AgentServiceImpl(DynamicTaskService dynamicTaskService, @Lazy BusinessTasks businessTasks) { this.dynamicTaskService = dynamicTaskService; this.businessTasks = businessTasks; + this.sessionManager = SessionManager.getInstance(); } @Override public void cancelCollect() { systemCollectStop(); switchCollectStop(); + dynamicTaskService.cancelTask("alarmTask"); dynamicTaskService.cancelTask("heartbeat"); } @@ -642,15 +660,115 @@ public class AgentServiceImpl implements AgentService { public void alarmMonitor() { if(GlobalConfig.IS_ALARM){ //开启告警监控 + AssertLog.info("开启告警监控,监控项={}", JSON.toJSONString(GlobalConfig.ALARM_LIST)); long milli = AgentUtil.getMillisToNextMinute() + 60000; dynamicTaskService.scheduleTask("alarmTask", businessTasks::alarmTask, milli, GlobalConfig.ALARM_INTERVAL*1000L); }else{ //关闭告警监控 + AssertLog.info("关闭告警监控"); dynamicTaskService.cancelTask("alarmTask"); } } + @Override + public void command(ScriptPolicyEO policy, String clientId) { + long timestamp = System.currentTimeMillis(); + timestamp = Math.round(timestamp / 1000.0); + if(CollectionUtil.isNotEmpty(policy.getCommands())){ + //执行方式:0、立即执行;1、定时执行; + if(policy.getMethod() == 1){ + SpecificTimeRequest request = SpecificTimeRequest.builder() + .taskId("") + .taskName("") + .taskData(policy.getCommands()) + .specificDateTime(AgentUtil.toLocalDateTime(policy.getPolicyTime(),true)) + .clientId(clientId) + .build(); + try { + taskService.createSpecificTimeTask(request); + JSONObject json = new JSONObject(); + json.put("resCode",1); + json.put("resMsg", "执行脚本策略定时任务保存成功"); + json.put("timestamp",timestamp); + // 判定客户端与服务端是否连接 + if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { + Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.执行脚本策略应答.getValue()) + .data(json.toString()).build(); + sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); + AssertLog.info("发送执行脚本策略应答={}",JSON.toJSONString(message)); + } + } catch (Exception e) { + JSONObject json = new JSONObject(); + json.put("resCode",0); + json.put("resMsg", "执行脚本策略定时任务保存失败"); + json.put("timestamp",timestamp); + // 判定客户端与服务端是否连接 + if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { + Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.执行脚本策略应答.getValue()) + .data(json.toString()).build(); + sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); + AssertLog.info("发送执行脚本策略应答={}",JSON.toJSONString(message)); + } + } + }else{ + for (String command : policy.getCommands()) { + List cmd = Arrays.asList(command.split("\\s+")); + CompletableFuture future = + AsyncCommandExecutor.executeCommandAsync( + cmd, + 60, TimeUnit.SECONDS); + future.thenAccept(result -> { + if (result.isSuccess()) { + System.out.println("脚本执行成功"); + System.out.println("[成功resOut] " + result.getOutput()); + } else { + System.out.println("脚本执行失败"); + System.out.println("[失败resOut] " + result.getOutput()); + } + JSONObject rse = new JSONObject(); + rse.put("command",command); + rse.put("resOut", result.getOutput()); + long timestamps = System.currentTimeMillis(); + timestamps = Math.round(timestamps / 1000.0); + JSONObject json = new JSONObject(); + json.put("resCode",1); + json.put("resMsg", ""); + json.put("timestamp",timestamps); + json.put("result", rse.toString()); + // 判定客户端与服务端是否连接 + if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { + Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.执行脚本策略应答.getValue()) + .data(json.toString()).build(); + sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); + AssertLog.info("发送执行脚本策略应答={}",JSON.toJSONString(message)); + } + }).exceptionally(ex -> { + System.err.println("执行失败: " + ex.getMessage()); + JSONObject rse = new JSONObject(); + rse.put("command",command); + rse.put("resOut", "脚本执行失败"); + long timestamps = System.currentTimeMillis(); + timestamps = Math.round(timestamps / 1000.0); + JSONObject json = new JSONObject(); + json.put("resCode",1); + json.put("resMsg", ""); + json.put("timestamp",timestamps); + json.put("result", rse.toString()); + // 判定客户端与服务端是否连接 + if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { + Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.执行脚本策略应答.getValue()) + .data(json.toString()).build(); + sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); + AssertLog.info("发送执行脚本策略应答={}",JSON.toJSONString(message)); + } + return null; + }); + } + } + } + } + } diff --git a/src/main/java/com/tongran/agent/client/service/impl/AlarmServiceImpl.java b/src/main/java/com/tongran/agent/client/service/impl/AlarmServiceImpl.java index 2eb65b2..af310b8 100644 --- a/src/main/java/com/tongran/agent/client/service/impl/AlarmServiceImpl.java +++ b/src/main/java/com/tongran/agent/client/service/impl/AlarmServiceImpl.java @@ -13,6 +13,7 @@ import com.tongran.agent.client.core.eo.NativeNetworkInterfaceEO; import com.tongran.agent.client.core.vo.AlarmVO; import com.tongran.agent.client.service.AlarmService; import com.tongran.agent.client.utils.AgentDataUtil; +import com.tongran.agent.client.utils.AssertLog; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import oshi.SystemInfo; @@ -41,6 +42,7 @@ import java.util.stream.Collectors; public class AlarmServiceImpl implements AlarmService { @Override public List alarmMonitor(long timestamp) { + AssertLog.info("告警监控定时任务执行alarmMonitor()"); List alarmVOList = new ArrayList<>(); List list = GlobalConfig.ALARM_LIST.stream().filter(a -> a.isCollect() == true).collect(Collectors.toList()); if(CollectionUtil.isNotEmpty(list)){ diff --git a/src/main/java/com/tongran/agent/client/utils/AgentDataUtil.java b/src/main/java/com/tongran/agent/client/utils/AgentDataUtil.java index d0be75d..92a34b5 100644 --- a/src/main/java/com/tongran/agent/client/utils/AgentDataUtil.java +++ b/src/main/java/com/tongran/agent/client/utils/AgentDataUtil.java @@ -31,4 +31,25 @@ public class AgentDataUtil { return alarmEOList.stream() .anyMatch(AlarmEO::isCollect); } + + public static void chmod(String filePath, String mode) throws IOException, InterruptedException { + ProcessBuilder processBuilder = new ProcessBuilder("chmod", mode, filePath); + processBuilder.redirectErrorStream(true); + + Process process = processBuilder.start(); + int exitCode = process.waitFor(); + + if (exitCode != 0) { + throw new IOException("chmod命令执行失败,退出码: " + exitCode); + } + } + + public static void main(String[] args) { + try { + chmod("/opt/app/init.sh", "755"); // 或者 "+x" + System.out.println("权限设置成功!"); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/com/tongran/agent/client/utils/AgentUtil.java b/src/main/java/com/tongran/agent/client/utils/AgentUtil.java index a80283f..2590539 100644 --- a/src/main/java/com/tongran/agent/client/utils/AgentUtil.java +++ b/src/main/java/com/tongran/agent/client/utils/AgentUtil.java @@ -217,4 +217,12 @@ public class AgentUtil { return timestamp; } + public static LocalDateTime toLocalDateTime(long timestamp, boolean isSeconds) { + java.time.Instant instant = isSeconds ? + java.time.Instant.ofEpochSecond(timestamp) : + java.time.Instant.ofEpochMilli(timestamp); + + return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + } + }