1. 程式人生 > >[原創] python monitor log end content send to html use websocket

[原創] python monitor log end content send to html use websocket

Use Python monitor log file end content, like tail -f, and send to html use websocket.

server.py
# server.py
import tornado.web
import tornado.httpserver
import tornado.options
from tornado.options import define
from tornado.options import options

from .log_handler import LogHandler, LogScoketHandler


define("port"
, default=8182, help="Run server on a specific port", type=int) define("host", default='0.0.0.0', help="Bind host name or ip", type=str) define("log_dir", default='logs', help="logs dirname", type=str) class Server(): def __init__(self, settings, *args, **kwargs): self.settings = settings self.handlers = [ (r'/static/(.*)'
, tornado.web.StaticFileHandler, {'path': settings.get("static_path")}), (r"/log\.html$", LogHandler), (r"/log/?$", LogSocketHandler) ] def start(self): tornado.options.parse_command_line() app = tornado.web.Application(self, self.handlers, **self.settings) http_server = tornado.httpserver.HTTPServer(app, xheaders=True
) http_server.listen(options.port, address=options.host) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": Server({"static_path": "static"}).start()
log_handler.py
# log_handler.py
import os, sys, time

from tornado.web import RequestHandler
from tornado.websocket import WebSocketHandler
from tornado.websocket import WebSocketClosedError
from tornado.ioloop import IOLoop
from tornado.options import options


class LogHandler(RequestHandler):
    def get(self):
        job_name = self.get_argument("name")
        date = self.get_argument("date")
        self.render("log.html", name=job_name, date=date)

class LogSocketHandler(WebSocketHandler):
    def __init__(self, *args, **kwargs):
        super(LogSocketHandler, self).__init__(*args, **kwargs)
        self._fp = None
        self._filename = None
        self._st_ino = None

    def on_message(self, message):
        """
        action:open:{job_name}:{job_date}
        action:close
        """
        _tmp_list = message.split(":")
        action, func, args = _tmp_list[0],_tmp_list[1],_tmp_list[2:]
        if action != "action":
            self.write_message("not start with action, close.")
            self.close()
        if not hasattr(self, "do_" + func):
            self.close()
        try:
            getattr(self, "do_" + func)(*args)
        except Exception, e:
            traceback.print_exc()
            self.write_message(str(e))
            self.do_close()

    def do_open(self, job_name ="crawler", date="today", *args):
        # logs/crawler-wechat_2018-07-13.log
        path = os.path.join(options.log_dir, "%s_%s.log" % (job_name, date))
        if not os.path.isfile(path):
            self.write_message("log file not found. file: %s" % path)
            return
        self._filename = path
        self.read_file()

    def do_close(self, *args):
        self.on_close()

    def on_close(self):
        try:
            self.close()
            self._fp.close()
        except:
            pass

    def read_file(self):
        if self._fp is None or self._fp.closed:
            self._fp = open(self._filename)
            # self._fp = file(path, encoding="utf-8")
            self._st_ino = os.fstat(self._fp.fileno()).st_ino
        if not self._fp:
            return False
        while True:
            if self._fp.closed:
                break
            line = self._fp.readline()
            if line == "":
                break
            try:
                self.write_message(line)
            except WebSocketClosedError:
                self.on_close()
        if os.stat(self._filename).st_ino != self._st_ino:
            seek = self._fp.tell()
            new = open(self._filename)
            self._fp.close()
            self._fp = new
            self._fp.seek(seek)
            self._st_ino = os.fstat(self._fp.fileno()).st_ino
        IOLoop.instance().add_timeout(time.time() + 0.5, self.read_file)
static/log.html
# log.html
<html>
<head>
    <meta charset="UTF-8">
    <title>Log History {{ name }}</title>
    <style>
    pre {
        /*white-space: pre-wrap;*/
        white-space: -moz-pre-wrap;
        white-space: -pre-wrap;
        white-space: -o-pre-wrap;
        word-wrap: break-word;
        margin: unset;
    }
    </style>
    <script type="text/javascript" src="/static/module/jquery-2.1.1.min.js"></script>
</head>

<body>
    <h5><span>Log File Name: {{ name }}_{{ date }} </span></h5>
    <code id="logs"> </code>
    <script>
    function scrollEnd() {
        $(document).scrollTop($(document).height() - $(window).height());
    }
    var ws = new WebSocket("ws://localhost:8182/log");
    ws.onopen = function() {
        ws.send("action:open:{{ name }}:{{ date }}");
    };
    ws.onmessage = function(msg) {
        $("#logs").append("<pre>" + msg.data + "</pre>");
        scrollEnd();
    };
    </script>
</body>

</html>
view files
# file list
- server.py
- log_handler.py
- static/log.html
- static/module/jquery-2.1.1.min.js
- logs/crawler-wechat_2018-07-13.log
view on browser
reference: