如何不刷新网页即可实时展示更新后日志文件的最后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>
运行步骤
- 执行命令:
python server.py --host 127.0.0.1 --port 8765 - 执行命令:
python -m http.server - 在浏览器中打开地址:
http://localhost:8000/demo.html
内容的提问来源于stack exchange,提问作者Glen Veigas
相关产品推荐
相关产品推荐

