java 日志监听程序,动态监听log文件递增的内容

业务场景: 新上线一个线上运行版本,测试运行一段时间验证是否可用。测试运行版本要保证与之前服务的数据一致,故做了个日志转发,把发送到现运行版本的请求全部转发给测试版本一份。程序完全基于jvm自有jar包实现,单java文件就可执行,轻量如果想要做其他的日志处理,比如保存mysql,日志备份等,只需要实现LogProcessing接口即可,方便可扩展。

 

我这里是直接获取日志之后做了个转发。单个转发速度太慢,做了个多线程版本的转发。

 

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;


/**
 * 日志监听类,可以做请求转发,日志入库,日志备份等
 * 未依赖任何第三方jar包,基于jvm就可直接执行
 * 执行步骤:
 *        javac RequestListen.java
 *        nohup java -cp . RequestListen info.log http://127.0.0.1:8080/ 0 >> listen.log 2>&1 &
 * @author ZhangShaobo
 * @date 2019/7/16 17:07
 * @param
 * @return
*/
public class RequestListen {

    // 指定上次文件读取位置
    private long lastTimeFileSize = 0;

    public void realtimesShowLog(File logFile, LogProcessing logProcessing) throws FileNotFoundException {
        final RandomAccessFile randomAccessFile = new RandomAccessFile(logFile,"r");

        new Thread(() -> {
            for(;;){
                try {
                    randomAccessFile.seek(lastTimeFileSize);
                    String tmp = "";
                    while( (tmp = randomAccessFile.readLine())!= null) {
                        String line = new String(tmp.getBytes("ISO8859-1"));
                        logProcessing.process(line);
                    }
                    lastTimeFileSize = randomAccessFile.length();
                    System.out.println("当前执行位置:"+ lastTimeFileSize);
                    Thread.sleep(10000);
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }).start();

    }

    /**
     * 主函数
     * @param args 0:监听的文件地址。1: 转发的请求地址。 2.读取的文件位置
     */
    public static void main(String[] args) {
        RequestListen listen = new RequestListen();
        if (args.length < 3) {
            System.err.println("param can't be null ! args[0]: listen file path, args[1] request url, args[2] lastTimeFileSize!");
            return ;
        }
        File file = new File(args[0]);
        String urlstr = args[1];
        listen.lastTimeFileSize = Long.parseLong(args[2]);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(100, 200, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy());

        try {
            listen.realtimesShowLog(file, new LogProcessingForward(urlstr, threadPoolExecutor));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 日志程序处理接口
 */
interface LogProcessing {
    void process(String line);
}

/**
 * 日志处理转发实现类
 */
class LogProcessingForward implements LogProcessing {

    private String urlstr;

    private ThreadPoolExecutor threadPoolExecutor;

    public LogProcessingForward(String urlstr, ThreadPoolExecutor threadPoolExecutor) {
        this.urlstr = urlstr;
        this.threadPoolExecutor = threadPoolExecutor;
    }

    @Override
    public void process(String line) {
        threadPoolExecutor.submit(new ForwardHandle(line, urlstr));
    }
}

/**
 * 日志转发线程
 */
class ForwardHandle implements Runnable {

    private String line;

    private String urlstr;

    public ForwardHandle(String line, String urlstr) {
        this.line = line;
        this.urlstr = urlstr;
    }


    @Override
    public void run() {
        if (!line.startsWith("20") || line.length() < 19) {
            return ;
        }
        String dateStr = line.substring(0, 19);
        String[] split1 = line.split(" - ");
        String[] split = null;
        if (line.contains("request:")) {
            split = split1[split1.length-1].split("request\\:");
        } else if (line.contains("request :")) {
            split = split1[split1.length-1].split("request \\:");
        }
        if (split == null || split.length < 2) {
            return ;
        }
        String key = split[0].trim();
//        if (!key.equals("details") && !key.equals("syncDetails") && !key.equals("rollback")) {
//            return ;
//        }
        String jsonObject = split[1].trim();
        HttpURLConnection con = null;
        OutputStream os = null;
        String concat = urlstr.concat(key);
        System.out.println(dateStr + ", request url: "+concat +", param: "+ jsonObject);
        try {
            URL url = new URL(concat);
            con = (HttpURLConnection) url.openConnection();
            //设置请求类型
            con.setRequestMethod("POST");

            if (key.equals("rollback")) {
                //设置请求需要返回的数据类型和字符集类型
                con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=GBK");
                jsonObject = "_id=" + jsonObject;
            } else {
                //设置请求需要返回的数据类型和字符集类型
                con.setRequestProperty("Content-Type", "application/json;charset=GBK");
            }

            //允许写出
            con.setDoOutput(true);
            //允许读入
            con.setDoInput(true);
            //不使用缓存
            con.setUseCaches(false);
            //获得输出流,并将其封装为字符流
            PrintWriter out = new PrintWriter(con.getOutputStream());
            //按字节的方式打印输出字符,并写入数组的某一部分
            out.print(jsonObject);
            //刷新输出流的缓冲
            out.flush();
            //得到响应码
            con.getResponseCode();


        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (con != null) {
                con.disconnect();
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }
        }
    }
}



 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java可以使用inotify-tools库来监听Linux服务器上的文件变化。 inotify-tools是一个用于Linux的C库,允许程序监视文件系统事件,例如文件或目录的创建,删除,修改等。Java可以使用JNA库来调用inotify-tools的API。 下面是一个使用inotify-tools和JNA库的Java程序,用于监听远程Linux服务器上的文件变化: ```java import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Pointer; public class FileMonitor { public interface INotify extends Library { INotify INSTANCE = (INotify) Native.loadLibrary("c", INotify.class); int inotify_init(); int inotify_add_watch(int fd, String pathname, int mask); int inotify_rm_watch(int fd, int wd); int read(int fd, Pointer buf, int size); } public static void main(String[] args) throws Exception { int fd = INotify.INSTANCE.inotify_init(); String pathname = "/path/to/file"; int wd = INotify.INSTANCE.inotify_add_watch(fd, pathname, 0x00000100); byte[] buf = new byte[4096]; Pointer pointer = new Pointer(buf); while (true) { int bytesRead = INotify.INSTANCE.read(fd, pointer, buf.length); for (int i = 0; i < bytesRead; ) { int wd2 = pointer.getInt(i); i += 4; int mask = pointer.getInt(i); i += 4; int cookie = pointer.getInt(i); i += 4; int nameLen = pointer.getByte(i); i += 1; byte[] nameBytes = new byte[nameLen]; pointer.read(i, nameBytes, 0, nameBytes.length); String name = new String(nameBytes); i += nameLen; System.out.println("wd=" + wd2 + " mask=" + mask + " cookie=" + cookie + " name=" + name); } } } } ``` 这个程序使用了JNA库,它提供了对inotify-tools库的封装和调用。程序连接到远程主机,并使用inotify_add_watch函数监视指定文件的变化。在文件发生更改时,程序将打印出相应的事件信息。在使用前,需要将JNA库添加到项目依赖
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值