import tornado from tornado.web import Application from tornado.web import RequestHandler from tornado.websocket import WebSocketHandler import os import json template = '''<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>Document</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script type="text/javascript" charset="utf-8"> $(function() { if (typeof String.prototype.startsWith != 'function') { String.prototype.startsWith = function (prefix){ return this.slice(0, prefix.length) === prefix; }; } var output = $("#stdout-output").html(); function addToOutput(msg) { /* output = $("#output").html() + '<br/>' + msg;*/ if (msg.startsWith('stderr:')) { if (!$('a[href="#stderr"]').hasClass("alarm-report") && $('ul[role="tablist"] li.active a').attr('href') != '#stderr') { $('a[href="#stderr"]').addClass("alarm-report") } output = $("#stderr-output").html() + msg.replace(/^stderr:/,''); $("#stderr-output").html(output); $('#stderr-output').scrollTop($('#stderr-output')[0].scrollHeight); }else { if (!$('a[href="#stdout"]').hasClass("alarm-report") && $('ul[role="tablist"] li.active a').attr('href') != '#stdout') { $('a[href="#stdout"]').addClass("alarm-report") } output = $("#stdout-output").html() + msg.replace(/^stdout:/,''); $("#stdout-output").html(output); $('#stdout-output').scrollTop($('#stdout-output')[0].scrollHeight); } } $('a#clear').click(function() { var active_tab = $('ul[role="tablist"] li.active a').attr('href'); $(active_tab + '-output').html(''); }) $('a#load').click(function() { var active_tab = $('ul[role="tablist"] li.active a').attr('href'); ws.send(JSON.stringify({room:'load',msg:active_tab.replace(/^#/,'')})); }) $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { if ($(e.target).hasClass("alarm-report")) { $(e.target).removeClass("alarm-report") } }) if ("MozWebSocket" in window) { WebSocket = MozWebSocket; } if (WebSocket) { var ws = new WebSocket("ws://%s/show"); ws.onopen = function() {}; ws.onmessage = function (evt) { addToOutput(evt.data); }; ws.onclose = function() {}; } else { alert("WebSocket not supported"); } }) </script> <style type="text/css"> .input-group { margin-bottom: 5px; } .input-group-addon { background-color:#337ab7; color:#fff; border-color:#337ab7; } li[aria-selected="true"] { display:none; } li[role="presentation"] a{ border-bottom-left-radius:0; border-bottom-right-radius:0; } .well { color:#eee; border-top:0; border-top-left-radius:0; border-top-right-radius:0; } #stdout-output,#stderr-output { background-color:#333; height:600px; overflow-y:auto; padding:10px; } .alarm-report { border:2px solid #333; border-bottom:none; animation: flash 1s linear infinite; } @keyframes flash{ from { border-color: #333; } to { border-color: red; } } </style> </head> <body> <div class="row"> <div class="col-md-offset-2 col-md-8"> <!-- Nav tabs --> <ul class="nav nav-pills nav-justified" role="tablist"> <li role="presentation" class="active"> <a href="#stdout" aria-controls="stdout" role="tab" data-toggle="tab">标准输出</a> </li> <li role="presentation"> <a href="#stderr" aria-controls="stderr" role="tab" data-toggle="tab">错误输出</a> </li> <li role="presentation"> <a href="javascript:void(0);" id="load">载入历史</a> </li> <li role="presentation"> <a href="javascript:void(0);" id="clear">清空</a> </li> </ul> <!-- Tab panes --> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="stdout"> <pre contentEditable="false" class="well" id="stdout-output"></pre> </div> <div role="tabpanel" class="tab-pane" id="stderr"> <pre contentEditable="false" class="well" id="stderr-output"></pre> </div> </div> </div> </div> </body> </html> ''' def create_app(): handlers = [(r"/", AnsibleHandler), (r'/show', CommandHandler)] app = Application( handlers=handlers, debug=True, cookie_secret='asdadasdadasdasdasda') return app class cd(object): def __init__(self, newPath): self.newPath = os.path.expanduser(newPath) def __enter__(self): self.savedPath = os.getcwd() os.chdir(self.newPath) def __exit__(self, etype, value, traceback): os.chdir(self.savedPath) class AnsibleHandler(RequestHandler): def get(self): self.write(template % (self.request.host)) class CommandHandler(WebSocketHandler): def open(self): print("WebSocket opened") LISTENERS.append(self) def on_message(self, message): message = json.loads(message) # self.write_message(u"You said: " + message['msg']) if message['room'] == 'load': out_file = STDOUT_FILENAME if message[ 'msg'] == 'stdout' else STDERR_FILENAME if os.path.getsize(out_file) > 10240000: self.write_message('file is too large!') else: with open(out_file, 'r') as f: f.seek(0, os.SEEK_END) fsize = f.tell() f.seek(max(fsize - 1024, 0), 0) for line in f.readlines()[-800:]: self.write_message('{}:{}'.format(message['msg'], line)) def on_close(self): print("WebSocket closed") try: LISTENERS.remove(self) except: pass def tail_file(): where = stdout_file.tell() line = stdout_file.readline() if not line: stdout_file.seek(where) else: for element in LISTENERS: element.write_message('stdout:{}'.format(line)) where = stderr_file.tell() line = stderr_file.readline() if not line: stderr_file.seek(where) else: for element in LISTENERS: element.write_message('stderr:{}'.format(line)) if __name__ == '__main__': STDOUT_FILENAME = 'logs/tail.log' STDERR_FILENAME = 'logs/tail_err.log' STDOUT_FILENAME = os.path.abspath(STDOUT_FILENAME) STDERR_FILENAME = os.path.abspath(STDERR_FILENAME) LISTENERS = [] stdout_file = open(STDOUT_FILENAME) stderr_file = open(STDERR_FILENAME) stdout_file.seek(os.path.getsize(STDOUT_FILENAME)) stderr_file.seek(os.path.getsize(STDERR_FILENAME)) app = create_app() http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8000, '0.0.0.0') tailed_callback = tornado.ioloop.PeriodicCallback(tail_file, 5) tailed_callback.start() io_loop = tornado.ioloop.IOLoop.instance() try: io_loop.start() except SystemExit as KeyboardInterrupt: io_loop.stop() stdout_file.close() stderr_file.close()
NO CONTENTS