zoukankan      html  css  js  c++  java
  • 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调试的代码没问题,放到项目中出现了不能跨域请求的问题 ,然后我就把跨域请求关掉了,不检查是否跨域

  • 相关阅读:
    springboot(10)logback日志配置
    springboot(9)springboot整合redis
    springboot(8)springboot整合mybatis
    springboot(7)springboot整合freemarker和thymeleaf
    springboot(6)过滤器 监听器 拦截器
    springboot(5)单元测试及MockMVC类的使用及自定义异常处理
    springboot(4)springboot热部署插件及idea热部署及配置文件注解注入
    springboot(3)使用MultipartFile上传数据文件及项目打成jar包
    springboot(2)内置序列化框架为Jackson及springboot文件目录结构
    git rebase
  • 原文地址:https://www.cnblogs.com/xianyin/p/9299698.html
Copyright © 2011-2022 走看看