django自动化运维平台-web页面实时显示tomcat启动日志,给予tornado和redis

先来发大概的技术实现,参考好多博客,地址忘记了 后面看到再加

用脚本将要查看的日志文件读取出来,使用redis的发布订阅模式将内容发布到redis的指定频道

写一个websocket服务端监听一个端口,等待长连接接入

       在websocket里面 使用redis的发布订阅模式订阅指定频道,如果有用户访问进来就把订阅内容推送出去

在html建立与websocket的长连接,显示websocket返回的内容

 

读取日志文件脚本:

# coding:utf8
import paramiko
import select
import redis
import sys

#此方法是进行实时返回,例如tail -f这样的命令,本次监控就用的是此方法。
def send_content_redis(ip, port, user, pwd, subscribe, logfile):
    redis_config = {
        "host": "xx.xx.xx.xx",
        "port": 6379
    }
    redis_pool = redis.ConnectionPool(**redis_config)
    r = redis.Redis(connection_pool=redis_pool)
    r.pubsub_channels(subscribe)

    # 进行连接
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(ip, port, username=user, password=pwd, timeout=4)
    # 开启channel 管道
    transport = client.get_transport()
    channel = transport.open_session()
    channel.get_pty()
    tail = 'tail -f %s' %logfile
    #将命令传入管道中
    channel.exec_command(tail)
    while True:
        #判断退出的准备状态
        if channel.exit_status_ready():
            break
        try:
            # 通过socket进行读取日志,个人理解,linux相当于客户端,我本地相当于服务端请求获取数据(此处若有理解错误,望请指出。。谢谢)
            rl, wl, el = select.select([channel], [], [])
            if len(rl) > 0:
                recv = channel.recv(10240)
                # 此处将获取的数据解码成gbk的存入本地日志
                print(recv.decode('utf-8', 'ignore'))
                r.publish(subscribe, recv.decode('utf-8', 'ignore'))
        # 键盘终端异常
        except KeyboardInterrupt:
            channel.send("x03")  # 发送 ctrl+c
            channel.close()
    client.close()

def main():
    send_content_redis(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6])
  


if __name__ == '__main__':
    main()

websocket 服务端代码

# coding:utf8
import os
import sys
import tornado.websocket
import tornado.web
import tornado.ioloop
from tornado import gen
from tornado.escape import to_unicode
import redis
import subprocess


class SubWebSocket(tornado.websocket.WebSocketHandler):
    """
    此handler处理远程日志查看
    """
    # 允许跨域请求 
    def check_origin(self, origin):
        return True

    def open(self, *args, **kwargs):
        print("opened")
        self.ip = self.get_argument('ip', '')
        self.redis_ip = self.get_argument('redis_ip', '')
        self.redis_port = self.get_argument('redis_port', '')
        self.pubscribe = self.get_argument('pubscribe', '')
        self.user = self.get_argument('user', '')
        self.password = self.get_argument('password', '')
        self.port = self.get_argument('port', '')
        self.logfile = self.get_argument('logfile', '')
        self.sub = subprocess.Popen('python 1.py %s %s %s %s %s %s' %(self.ip, self.port, self.user, self.password, self.pubscribe, self.logfile ), shell=True)

    @gen.coroutine
    def on_message(self, message):
        r = redis.StrictRedis(host=self.redis_ip)
        # 订阅频道,服务器和日志路径确定一个频道
        channel = r.pubsub()
        channel.subscribe(self.pubscribe)
        try:
            while True:
                data = channel.get_message()
                if not data:
                    # 如果读取不到消息,间隔一定时间,避免无谓的CPU消耗
                    yield gen.sleep(0.05)
                    continue
                if data["type"] == "message":
                    line = data["data"]
                    self.write_message(line)
        except tornado.websocket.WebSocketClosedError:
            self.close()

    def on_close(self):
        print("closed")
        self.sub.kill()



class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r'/', MainHandler),  # 提供浏览页面,页面中的JS与服务器建立连接
            (r'/log', SubWebSocket),  # 处理远程日志实时查看,稍微复杂
        ]
        settings = {
            "debug": True,
            "template_path": os.path.join(os.path.dirname(__file__), "templates"),
            "static_path": os.path.join(os.path.dirname(__file__), "static"),
        }
        super(Application, self).__init__(handlers, **settings)


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("index.html")

def main():
    app = Application()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()


if __name__ == '__main__':
    main()
                                              

html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript">
      window.onload = function(){
            if("WebSocket" in window){
              console.log('浏览器支持websocket!');var ws = new WebSocket("ws://xx.xx.xx.xx:8888/log?ip={{ip}}&" +
                  "redis_ip={{redis_ip}}&redis_port={{redis_port}}&pubscribe={{pubscribe}}&" +
                  "user={{user}}&password={{password}}&port={{port}}&logfile={{logfile}}");
              var div = document.getElementById('content');
              ws.onopen = function () {
                  ws.send('websocket 链接建立第一次发送数据!');
                  console.log('第一次发送数据结束!');
              };
              ws.onmessage = function (evt) {
                  console.log("开始接收数据!");
                  var received_msg = evt.data;
                  div.innerText = div.innerText  + received_msg;
                  content_end.scrollIntoView();

              };
            }else{
                console.log("你的浏览器不支持websocket")
            }

        }
    </script>
</head>
<body>
      <div id="sse">
         <h3>服务启动日志{{salt_key_id}}</h3>
      </div>
      <div id="content">

      </div>
      <div id="content_end" style="height:100px; overflow:hidden">


     </div>
</body>
</html>

遇到的问题:

开始使用的一个单独的index.html调试的代码没问题,放到项目中出现了不能跨域请求的问题 ,然后我就把跨域请求关掉了,不检查是否跨域

原文地址:https://www.cnblogs.com/xianyin/p/9299698.html