Web 实现日志文件实时监听
在 Linux 中,若想要查看日志文件的实时输出内容,会使用 tailf 命令。现在想要在 Web 项目中实现这个功能。

思路

第一个想法,是 java 接收 tail 命令返回,然后通过 websocket 推送给前端。也搜到了有人利用此方法实现了。

但是个人觉得日志数据量较大,此方法效率偏低。巧的是,Apache Commons 包里已经帮忙实现了这个方法。

要注意的是,2.4 之前不支持中文。Commons 包较为常见,一开始我没有考虑版本,拿着 2.4 的包用,结果乱码,且没有相关参数指定编码,一度打算舍弃它。

实现

Apache Commons 包中的 Tailer 类实现了这个,一旦了解了这个类,实现起来就简单了。直接贴代码了。

websocket 入口

import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.File;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * websocket
 */
@ServerEndpoint("/websocket/log/{sid}")
@Component
public class WebSocketServerLog {
    private static Logger LOG = LoggerFactory.getLogger(WebSocketServerLog.class);

    private static AtomicInteger onlineCount = new AtomicInteger(0);

    private Tailer tailer;

    //接收sid
    private String sid="";

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        addOnlineCount();
        this.sid = sid;

        //tail listen
        TailerListener listener = new MyTailerListener(session);
        tailer = Tailer.create(new File("C:\\Users\\lenovo\\Desktop\\" + sid), listener, 1000, true);

        LOG.info("sid " + sid + " on open and online count " + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        subOnlineCount();
        tailer.stop();
        LOG.info("sid " + sid + " on close and online count " + getOnlineCount());
    }

    @OnError
    public void onError(Throwable error) {
        LOG.error("sid {} error: {}", sid, error.getMessage());
    }

    public static int getOnlineCount() {
        return onlineCount.get();
    }

    public static void addOnlineCount() {
        onlineCount.incrementAndGet();
    }

    public static synchronized void subOnlineCount() {
        onlineCount.decrementAndGet();
    }
}

继承 Tailer

import org.apache.commons.io.input.TailerListenerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.Session;
import java.io.IOException;

/**
 * 继承 TailerListenerAdapter
 */
public class MyTailerListener extends TailerListenerAdapter {

    private static Logger LOG = LoggerFactory.getLogger(MyTailerListener.class);

    private Session session;

    public MyTailerListener(Session session) {
        this.session = session;
    }

    @Override
    public void handle(String line) {
        try {
            LOG.info(line);
            if (session.isOpen()){
                session.getBasicRemote().sendText(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

参考

Java WebSocket + tail命令实现Web实时日志|叉叉哥的BLOG


Last modified on 2021-06-09