You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不刷新网页即可实时展示更新后日志文件的最后n行内容

基于Python的tail -f日志实时查看工具问题说明

我开发了一款模拟UNIX系统中tail -f命令的Python应用,用于展示日志文件的最后10条日志,现有代码可检测日志文件变更,通过websocket向客户端推送更新,实现网页无刷新展示。

当前运行逻辑

  • 首次启动服务端和客户端时,网页会正常展示日志文件的最后10行内容
  • 向日志文件新增内容时,新内容会追加展示在原有内容后,若新增n行则会在初始10行基础上额外展示这n行内容

预期与实际效果对比

为更清晰说明想要的最终效果,假设需要展示日志文件的最后5行:
现有日志文件内容如下:

1
2
3
4
5
6
7

运行服务端和客户端后,网页当前展示内容如下(即日志的最后5行):

3
4
5
6
7

当向日志文件新增一条内容8时,期望的最终输出如下:

4
5
6
7
8

该效果需要在不刷新页面的前提下实现,但目前实际输出为:

3
4
5
6
7
8

现有代码

server.py

import time
import os.path
import asyncio
import logging
from collections import deque

import websockets
from ansi2html import Ansi2HTMLConverter

NUM_LINES = 10
HEARTBEAT_INTERVAL = 15

conv = Ansi2HTMLConverter(inline=True)

async def view_log(websocket, path):
    try:
        file_path='log.log'
        tail=True

        i=0
        with open(file_path) as f:
            content = ''.join(deque(f, NUM_LINES))
            content = conv.convert(content, full=False)
            await websocket.send(content)

            if tail:
                last_heartbeat = time.time()
                while True:
                    content = f.read()
                    if content:
                        i+=1
                        content = conv.convert(content, full=False)
                        await websocket.send(content)
                    else:
                        await asyncio.sleep(1)

                    # heartbeat
                    #print(last_heartbeat)
                    if time.time() - last_heartbeat > HEARTBEAT_INTERVAL:
                        try:
                            await websocket.send('ping')
                            pong = await asyncio.wait_for(websocket.recv(), 5)
                            if pong != 'pong':
                                raise Exception()
                        except Exception:
                            raise Exception('Ping error')
                        else:
                            last_heartbeat = time.time()

            else:
                await websocket.close()

    except ValueError as e:
        try:
            await websocket.send(e)
            await websocket.close()
        except Exception:
            pass

        log_close(websocket, path, e)

    except Exception as e:
        log_close(websocket, path, e)

    else:
        log_close(websocket, path)


def log_close(websocket, path, exception=None):
    message = 'Closed, remote={}, path={}'.format(websocket.remote_address, path)
    if exception is not None:
        message += ', exception={}'.format(exception)
    logging.info(message)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--host', default='127.0.0.1')
    parser.add_argument('--port', type=int, default=8765)
    args = parser.parse_args()

    start_server = websockets.serve(view_log, args.host, args.port)
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()


if __name__ == '__main__':
    main()

demo.html

<html>
  <head>
    <title>Logviewer Demo</title>
  </head>
  <body>
    <pre id="logs"></pre>
    <script>
      let ws = new WebSocket('ws://localhost:8765')
      ws.onmessage = (event) => {
        if (event.data === 'ping') {
          ws.send('pong')
          return
        }
        document.getElementById('logs').innerHTML += event.data
      }
    </script>
  </body>
</html>

运行步骤

  1. 执行命令:python server.py --host 127.0.0.1 --port 8765
  2. 执行命令:python -m http.server
  3. 在浏览器中打开地址:http://localhost:8000/demo.html

内容的提问来源于stack exchange,提问作者Glen Veigas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 09:15:04