| New file | 
|  |  |  | 
|---|
|  |  |  | package com.dy.rtuMw.resource.rtuLog; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import java.io.BufferedWriter; | 
|---|
|  |  |  | import java.io.File; | 
|---|
|  |  |  | import java.io.FileInputStream; | 
|---|
|  |  |  | import java.io.FileOutputStream; | 
|---|
|  |  |  | import java.io.IOException; | 
|---|
|  |  |  | import java.io.OutputStreamWriter; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import com.dy.rtuMw.resource.ResourceUnit; | 
|---|
|  |  |  | import org.apache.logging.log4j.LogManager; | 
|---|
|  |  |  | import org.apache.logging.log4j.Logger; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import com.dy.common.util.DateTime; | 
|---|
|  |  |  | import com.dy.common.queue.Queue; | 
|---|
|  |  |  | import com.dy.common.threadPool.ThreadPool; | 
|---|
|  |  |  | import com.dy.common.threadPool.TreadPoolFactory; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public class RtuLogManager { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static final Logger log = LogManager.getLogger(RtuLogManager.class) ; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static final RtuLogManager instance = new RtuLogManager() ; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static final Queue logQueue = new Queue("rtuLogQueue") ; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static final Integer maxNodeAddWorkThread = 500 ;//缓存达到这个数量,将增加线程 | 
|---|
|  |  |  | private static final Integer maxWorkThread = 5 ;//最大工作线程数 | 
|---|
|  |  |  | private static final Object maxWorkThreadSynObj = new Object() ;//最大工作线程数 | 
|---|
|  |  |  | private static int workThread = 0 ;//工作线程数 | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private RtuLogManager(){ | 
|---|
|  |  |  | } | 
|---|
|  |  |  | @SuppressWarnings("unused") | 
|---|
|  |  |  | public static RtuLogManager getInstance(){ | 
|---|
|  |  |  | return instance ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 设置队列限制 | 
|---|
|  |  |  | * @param warnSize 队列节点数量 报警值 | 
|---|
|  |  |  | * @param maxSize 队列节点数量 最大值 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @SuppressWarnings("unused") | 
|---|
|  |  |  | public void setQueueLimit(int warnSize, int maxSize){ | 
|---|
|  |  |  | logQueue.setLimit(warnSize, maxSize); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 加入Rtu日志数据 | 
|---|
|  |  |  | * 在单线程中执行 | 
|---|
|  |  |  | * @param logNodeObj 日志队列节点对象 | 
|---|
|  |  |  | * @throws Exception 异常 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public void pushRtuLog(RtuLogNode logNodeObj) throws Exception{ | 
|---|
|  |  |  | logQueue.pushTail(logNodeObj); | 
|---|
|  |  |  | //在单线程中执行 | 
|---|
|  |  |  | if(workThread <= 0){ | 
|---|
|  |  |  | startWorkThread() ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 启动工作线程工作 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | private void startWorkThread(){ | 
|---|
|  |  |  | workThread ++  ; | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | TreadPoolFactory.getThreadPoolShort().putJob(new ThreadPool.Job() { | 
|---|
|  |  |  | public void execute() { | 
|---|
|  |  |  | while(logQueue.size() > 0){ | 
|---|
|  |  |  | RtuLogNode node ; | 
|---|
|  |  |  | if(workThread > 1){ | 
|---|
|  |  |  | synchronized(logQueue){ | 
|---|
|  |  |  | node = (RtuLogNode)logQueue.pop() ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | node = (RtuLogNode)logQueue.pop() ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if(node != null){ | 
|---|
|  |  |  | //日志文件存储 | 
|---|
|  |  |  | log(node.rtuAddr, node.content) ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if(RtuLogManager.logQueue.size() > maxNodeAddWorkThread){ | 
|---|
|  |  |  | if(workThread < maxWorkThread){ | 
|---|
|  |  |  | synchronized(maxWorkThreadSynObj){ | 
|---|
|  |  |  | if(workThread < maxWorkThread){ | 
|---|
|  |  |  | startWorkThread() ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | workThread --  ; | 
|---|
|  |  |  | if(workThread < 0){ | 
|---|
|  |  |  | workThread = 0 ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /* | 
|---|
|  |  |  | * 强制停止execute方法中执行的死循环工作 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Override | 
|---|
|  |  |  | public void destroy() { | 
|---|
|  |  |  | //再将启动,防止无线程处理了 | 
|---|
|  |  |  | startWorkThread() ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * execute方法中调用此方法判断是否结束死循环工作 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Override | 
|---|
|  |  |  | public boolean isDestroy() { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }) ; | 
|---|
|  |  |  | }catch(Exception e){ | 
|---|
|  |  |  | log.error(e); | 
|---|
|  |  |  | workThread -- ; | 
|---|
|  |  |  | if(workThread < 0){ | 
|---|
|  |  |  | workThread = 0 ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 记录Rtu日志 | 
|---|
|  |  |  | * @param rtuAddr 控制器地址 | 
|---|
|  |  |  | * @param content 日志内容 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | private void log(String rtuAddr , String content){ | 
|---|
|  |  |  | Object[] res = getFileForWrite(ResourceUnit.confVo.rtuLogDir , rtuAddr.trim()) ; | 
|---|
|  |  |  | if(res[0] != null){ | 
|---|
|  |  |  | writeLog((File)res[0] , DateTime.yyyy_MM_dd_HH_mm_ss() + "  " + content) ; | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | log.error("不能得到地址为:" + rtuAddr + "的Rtu日志文件!(信息编码" + res[1] + ")") ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 得到日志文件 | 
|---|
|  |  |  | * @param path 文件路径 | 
|---|
|  |  |  | * @param rtuAddr 控制器地址 | 
|---|
|  |  |  | * @return 日志文件 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | private Object[] getFileForWrite(String path , String rtuAddr) { | 
|---|
|  |  |  | File dir = new File(path) ; | 
|---|
|  |  |  | if(!dir.exists()){ | 
|---|
|  |  |  | if(!dir.mkdirs()){ | 
|---|
|  |  |  | return new Object[]{null, 1} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | File f = new File(path + rtuAddr + ".log"); | 
|---|
|  |  |  | FileInputStream in = null; | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (f.exists()) { | 
|---|
|  |  |  | in = new FileInputStream(f); | 
|---|
|  |  |  | if(in.available() >= ResourceUnit.confVo.rtuLogFileMaxSize){ | 
|---|
|  |  |  | in.close() ;//必须加上此语句 | 
|---|
|  |  |  | File oldestLog = new File(path + rtuAddr + ".log." + (ResourceUnit.confVo.rtuLogFileMaxCount - 1)) ; | 
|---|
|  |  |  | if(oldestLog.exists()){ | 
|---|
|  |  |  | if(!oldestLog.delete()){ | 
|---|
|  |  |  | return new Object[]{null, 2} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | for(int i = (ResourceUnit.confVo.rtuLogFileMaxCount - 2) ; i > 0  ; i--){ | 
|---|
|  |  |  | File oldLog = new File(path + rtuAddr + ".log." + i) ; | 
|---|
|  |  |  | if(oldLog.exists()){ | 
|---|
|  |  |  | if(!oldLog.renameTo(new File(path + rtuAddr + ".log." + (i + 1)))){ | 
|---|
|  |  |  | return new Object[]{null, 3} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if(!oldLog.delete()){ | 
|---|
|  |  |  | //2025-06-28 对于水肥机FBox上报数据比较频繁,实测老文件常有删除不了的情况发生, | 
|---|
|  |  |  | //一次删除不了,下次再可删除,所以下面return去除 | 
|---|
|  |  |  | //return new Object[]{null, 4} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if(!f.renameTo(new File(path + rtuAddr + ".log." + 1))){ | 
|---|
|  |  |  | return new Object[]{null, 5} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | //2024-10-11 上面rename了,应该不用delete了 | 
|---|
|  |  |  | //if(!f.delete()){ | 
|---|
|  |  |  | //   return new Object[]{null, 6} ; | 
|---|
|  |  |  | //} | 
|---|
|  |  |  |  | 
|---|
|  |  |  | f = new File(path + rtuAddr + ".log"); | 
|---|
|  |  |  | if(!f.exists()){ | 
|---|
|  |  |  | if(f.createNewFile()){ | 
|---|
|  |  |  | return new Object[]{f, 7} ; | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | return new Object[]{null, 8} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | return new Object[]{f, 9} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | if(f.createNewFile()){ | 
|---|
|  |  |  | return new Object[]{f, 10} ; | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | return new Object[]{null, 11} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | log.error("得到Rtu(" + rtuAddr + ")日志文件时出错" , e) ; | 
|---|
|  |  |  | }finally{ | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (in != null) { | 
|---|
|  |  |  | in.close(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } catch (IOException e) { | 
|---|
|  |  |  | log.error("关闭Rtu日志文件(" + f.getName() + ")读入流时出错" , e) ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return new Object[]{null, 12} ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 向文件中写入日志 | 
|---|
|  |  |  | * @param f 文件 | 
|---|
|  |  |  | * @param conent 日志内容 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | private void writeLog(File f, String conent) { | 
|---|
|  |  |  | if (f.exists()) { | 
|---|
|  |  |  | BufferedWriter out = null; | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, true))); // 参数为true,表示追加内容 | 
|---|
|  |  |  | out.write(conent + "\n"); | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | log.error("写入Rtu日志文件(" + f.getName() + ")时出错" , e) ; | 
|---|
|  |  |  | } finally { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (out != null) { | 
|---|
|  |  |  | out.close(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } catch (IOException e) { | 
|---|
|  |  |  | log.error("关闭Rtu日志文件(" + f.getName() + ")写出流时出错" , e) ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|