日志实时监控+上传

摘要:日志实时监控得意+上传

关键字:common-io/monitor包,生产消费模式,非阻塞队列,钩子

看点:

1.如何监听文件改变

common-io提供minitor工具,可以监控文件的改变

File directory = new File(logPath);
long interval = TimeUnit.SECONDS.toMillis(3);
FileFilter fileFilter = FileFilterUtils.or(FileFilterUtils.nameFileFilter("async_task.log"),
        FileFilterUtils.nameFileFilter("error.log"),
        FileFilterUtils.nameFileFilter("moviebar_local.log"),
        FileFilterUtils.nameFileFilter("push-message.log"));
FileAlterationObserver observer = new FileAlterationObserver(directory, fileFilter);
FileIncreListener listener = new FileIncreListener();
observer.addListener(listener);
initReadMark(directory.listFiles(fileFilter), listener);
FileAlterationMonitor monitor = new FileAlterationMonitor(interval,observer);
monitor.start();

2.文件改变后做什么

文件改变后应该获取最新的改变内容,所以需要记录上次读完后的内容偏移量offset

public void onFileChange(File file) {
    InputStream inputStream = null;
    ByteArrayOutputStream outputStream = null;
    try {
        String filepath = file.getPath();
        Long readOffset = readMark.get(filepath);
        if (readOffset == null) {
            readMark.put(filepath, file.length());
        } else {
            long fileLength = file.length();
            //兼容文件内容减少的情况
            if(readOffset > fileLength) {
                readOffset = fileLength;
                return;
            }
            long readLength = fileLength - readOffset;
            inputStream = new FileInputStream(file);
            outputStream = new ByteArrayOutputStream();
            IOUtils.copyLarge(inputStream, outputStream, readOffset, readLength);
            readMark.put(filepath, file.length());

            byte[] increByte = outputStream.toByteArray();
            if(increByte.length >= 1024 * 1024 * 1){
                return;
            }
            String increCon = new String(increByte);
            Map<String, String> params = new HashMap<>();
            LocalBar bar = ((BarCache)ApplicationContextUtil.getBean("barCache")).get();
            if(bar != null){
                params.put("barId", String.valueOf(bar.getId()));
                params.put("barName", bar.getName());
            }
            params.put("filename", file.getName());
            params.put("increCon", increCon);
            LogUpdProcessor.offer(params);
        }
    }catch (Exception e) {
        ;
    }finally {
        IOUtils.closeQuietly(outputStream);
        IOUtils.closeQuietly(inputStream);
    }

3.监听改变与处理日志的解耦

监听到日志马上就处理最新的内容吗?如果处理工作阻塞了怎么办?使用队列解耦!采用生产者、消费者模式!!!

public class LogUpdProcessor implements Runnable {

    private static ConcurrentLinkedQueue<Map> logMessageQueue = new ConcurrentLinkedQueue<Map>();
    @Resource
    private Environment env;

    public static boolean offer(Map map) {
        if(logMessageQueue.size() >= 1000){
            logMessageQueue.poll();
        }
        if(!Constants.UOLOAD_LOG_SWITCH){
            return false;
        }
        return logMessageQueue.offer(map);
    }

    public static Map poll() {
        return logMessageQueue.poll();
    }

    public static int queueSize(){
        return logMessageQueue.size();
    }

    @Override
    public void run() {
        while(true) {
            try{
                if(!Constants.UOLOAD_LOG_SWITCH) {
                    Thread.sleep(2000);
                    continue;
                }
                Map params = logMessageQueue.poll();
                if(params == null){
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        ;
                    }
                }else{
                    SecurityClientUtils.getInstance().exePostFormMethod(env.getProperty("url_cloud_service") + "/api/log/instantCollect", params);
                }
            }catch (Exception e){
                ;
            }
        }
    }

}

4.监控程序对监控目标保持静默

这个监控过程需要对监控对象的日志保持静默,不产生任何输出,否则就会造成递归死循环的场景:日志改变-监控捕获-处理-产生日志-日志改变,所以任何log,catch都不输出


5.对offset的维护(初始化,新建,增加,减少)

当程序启动时,offset初始为null,要二次更新时才能获取更新内容,存在消息丢失的情况!

故而当初始化时,offset置为file.length(),日志创建时同理

当日志减少时,offset小于length,会有读异常,兼容下


6.上传的开关与上传大小控制

上传增加开关,可控制

上传size做下限制,不能无限量上传  


7.jvm退出前清扫队列(钩子)

为了保证消息不丢失,在jvm退出前clean日志队列

Runtime.getRuntime().addShutdownHook(cleanLogThread);

8.云端简述

服务器端,同样可以采取生产者、消费者模式,消息到达时入队列,有其他线程完成日志后续处理工作

可提高服务器端吞吐能力

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值