linux查看实时日志命令 查看日志的三种命令分享

前言最近在做一个小工具 , 有个需求是在Web端能实时查看日志文件 , 也就是相当于在终端执行tail -f命令 , 对此没有找到好的解决方式 , 一开始想得直接通过FileInputStream来读取 , 因为他也能直接跳过n个字节来读取 , 就像下面这样 。
public static void main(String[] args) throws Exception {File file = new File("/home/1.txt");FileInputStream fin = new FileInputStream(file);int ch;fin.skip(10);while ((ch = fin.read()) != -1){System.out.print((char) ch);}}如果不跳过的话 , 那么每次读取全部内容并展示显然不现实 , 我们要做的是像tail一样 , 每次从后n行开始读取 , 并且会持续输出最新的行 。
还有一个问题就是对文件的变化要能感知到 , 所以最后选择直接调用tail命令 , 并且通过WebSocket输出到网页上 。
tail用法在java中调用tail命令后 , 拿到它的输入流并且包装成BufferedReader , 如果通过readLine()读取不到数据 , 那么他会一直阻塞 , 并不会返回null , 这也就代表日志文件中暂时还没有新数据写入 , 一旦readLine()方法返回 , 那么就代表有新数据到达了 。另外一个问题就是如何终止 , 我们不可能让他一直读取 , 要在一个合适的时间终止 , 答案就是在WebSocket断开连接时 , 并且Process类提供了destroy()方法用来终止这个进程 , 相当于按下了Ctrl+C
public static void main(String[] args) throws Exception {Process exec = Runtime.getRuntime().exec(new String[]{"bash", "-c", "tail -F /home/HouXinLin/test.txt"});InputStream inputStream = exec.getInputStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));for (;;){System.out.println(bufferedReader.readLine()+"r");} }实现过程在Spring Boot中加入WebSocket功能有很多方式 , 目前感觉普遍的文章都是介绍以ServerEndpointExporter、@OnOpen、 @OnClose、@OnMessage这种方式来实现的 , 这种方式需要声明一个Bean , 也就是ServerEndpointExporter , 但是我记得如果要打包成war放入Tomcat中运行时 , 还需要把这个Bean取消掉 , 否则还会报错 , 非常的麻烦 , 当然也有办法解决 。
还有其他集成的办法 , 比如实现WebSocketConfigurer或者
WebSocketMessageBrokerConfigurer接口 , 而我目前采用的是实现WebSocketMessageBrokerConfigurer接口 , 并且前端还需要两个库 , SockJS和Stomp(更具选择 , 也可以不使用) 。
SockJS提供类似于WebSocket的对象 , 还有一套跨浏览器的API , 可以在浏览器和Web服务器之间创建了低延迟 , 全双工 , 跨域的通信通道 , 如果浏览器不支持 WebSocket , 它还可以模拟对WebSocket的支持 。
Stomp即Simple Text Orientated Messaging Protocol , 简单(流)文本定向消息协议 , 它提供了一个可互操作的连接格式 , 允许STOMP客户端与任意STOMP消息代理(Broker)进行交互 。
首先看一下连接处理层的逻辑 , 其中一部分非必要的代码就不展示了 。
@Configuration@EnableWebSocketMessageBrokerpublic class WebSocketConfig implements WebSocketMessageBrokerConfigurer {private static final Logger log = LoggerFactory.getLogger(WebSocketConfig.class.getName());@AutowiredSimpMessagingTemplate mSimpMessagingTemplate;@AutowiredWebSocketManager mWebSocketManager;@AutowiredTailLog mTailLog;@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {registry.enableSimpleBroker("/topic/path");}@Overridepublic void configureWebSocketTransport(WebSocketTransportRegistration registration) {registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {@Overridepublic WebSocketHandler decorate(WebSocketHandler webSocketHandler) {return new WebSocketHandlerDecorator(webSocketHandler) {@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {log.info("日志监控WebSocket连接,sessionId={}", session.getId());mWebSocketManager.add(session);super.afterConnectionEstablished(session);}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {mWebSocketManager.remove(session.getId());super.afterConnectionClosed(session, closeStatus);}};}});}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/socket-log").addInterceptors(new HttpHandshakeInterceptor()).setHandshakeHandler(new DefaultHandshakeHandler() {@Overrideprotected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {return new StompPrincipal(UUID.randomUUID().toString());}}).withSockJS();}@EventListenerpublic void handlerSessionCloseEvent(SessionDisconnectEvent sessionDisconnectEvent) {StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionDisconnectEvent.getMessage());mTailLog.stopMonitor(headerAccessor.getSessionId());}/*** 路径订阅** @param sessionSubscribeEvent*/@EventListenerpublic void handlerSessionSubscribeEvent(SessionSubscribeEvent sessionSubscribeEvent) {StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionSubscribeEvent.getMessage());if (mTailLog.isArriveMaxLog()) {mWebSocketManager.sendMessage(headerAccessor.getSessionId(), "监控数量已经达到限制 , 无法查看"");log.info("日志监控WebSocket连接已经到达最大数量 , 将断开sessionId={}", headerAccessor.getSessionId());mWebSocketManager.close(headerAccessor.getSessionId());return;}String destination = headerAccessor.getDestination();String userId = headerAccessor.getUser().getName();if (destination.startsWith("/user/topic/path")) {String path = destination.substring("/user/topic/path".length());File file = new File(StringUtils.urlDecoder(path));if (!file.exists()) {mWebSocketManager.sendMessage(headerAccessor.getSessionId(), "what are you 弄啥嘞 , 文件找不到啊");mWebSocketManager.close(headerAccessor.getSessionId());return;}TailLogListenerImpl tailLogListener = new TailLogListenerImpl(mSimpMessagingTemplate, userId);mTailLog.addMonitor(new LogMonitorObject(file.getName(), file.getParent(),tailLogListener, "" + headerAccessor.getSessionId(), userId));}}}