V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
yongzhong
V2EX  ›  Python

django channel 如何实时 tail 某个文件

  •  
  •   yongzhong · 2018-09-19 17:23:53 +08:00 · 2245 次点击
    这是一个创建于 2282 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我写了一个 consumer 在前端的 websocket 请求过来后就开始对某个日志实时输出

    class LogConsumer(WebsocketConsumer):
    
        def disconnect(self, close_code):
            print('关闭')
            if getattr(self, 'f', None):
                self.f.terminate()
    
        def receive(self, text_data):
            print(text_data)
            log_file = 'xxxxx.log'
    
            if not os.path.exists(log_file):
                self.send(json.dumps({
                    'key': 0,
                    'data': '日志不存在'
                }))
                return
            self.f = subprocess.Popen(
                'tail -f -n 40 {}'.format(log_file),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                shell=True,
            )
            p = select.poll()
            p.register(self.f.stdout)
            line_number = 1
            while True:
                if p.poll(1):
                    msg = self.f.stdout.readline().decode("utf-8")
                    if not msg:
                        raise Exception
                    for m in str(msg).splitlines():
                        self.send(json.dumps({'key': line_number,
                                                'data': m + '\n'
                                                }))
                        line_number += 1
    

    这样有一个问题就是会导致这个 consumer 处于 blocking 状态,导致 disconnect 无法被触发,进而无法释放进程

    有什么好的解决办法吗?

    第 1 条附言  ·  2019-02-14 15:25:25 +08:00

    没用到channel

    class LogConsumer(WebsocketConsumer):
        def __init__(self, *args, **kwargs):
            super(LogConsumer, self).__init__(*args, **kwargs)
            self.processes = []
            self.threads = []
    
        def disconnect(self, close_code):
            for p in self.processes:
                p.terminate()
    
            for th in self.threads:
                th.join()
    
        def receive(self, text_data):
            log_file = 'some_path'
    
            if not os.path.exists(log_file):
                self.send(json.dumps({
                    'key': 0,
                    'data': '日志不存在'
                }))
                return
            popen = subprocess.Popen(
                'tail -f -n 40 {}'.format(log_file),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                shell=True,
            )
            self.processes.append(popen)
    
            def output_log():
                line_number = 1
                while True:
                    msg = popen.stdout.readline().decode("utf-8")
                    if not msg:
                        continue
                    for m in str(msg).splitlines():
                        self.send(json.dumps({'key': line_number,
                                            'data': m + '\n'
                                            }))
                        line_number += 1
    
            tail_thread = threading.Thread(name='log_tail', target=output_log)
            tail_thread.start()
    
            self.threads.append(tail_thread)
    
    5 条回复    2020-01-07 18:27:20 +08:00
    phithon
        1
    phithon  
       2018-09-19 21:35:37 +08:00
    两个线程或进程,一个 websocket,一个 subprocess。中间用 channels layer 连接。
    zengcul
        2
    zengcul  
       2019-01-22 21:14:18 +08:00
    同遇到这个问题 请问楼主如何解决
    zengcul
        3
    zengcul  
       2019-02-14 14:19:17 +08:00
    @zengcul 想了了个歪招,后端不能使用 while True 一直占用进程,前端 ws 握手连接成功后,使用定时器向后端 send message,后端每收到一次 message 去 stdout.readline 下
    yongzhong
        4
    yongzhong  
    OP
       2019-02-14 15:25:51 +08:00
    @zengcul #3 我用了个比较丑陋的方法,见 append,没用到 channel
    37Y37
        5
    37Y37  
       2020-01-07 18:27:20 +08:00
    可以看看这个,正好实现了一样的功能
    https://ops-coffee.cn/s/r5SpyTjRl0jJeAuYE4Q_-Q
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1147 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:18 · PVG 02:18 · LAX 10:18 · JFK 13:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.