大致思路:
1.利用tornado提供的websocket功能与浏览器建立长连接,读取实时日志并输出到浏览器
2.写一个实时读取日志的脚本,利用saltstack远程执行,并把实时日志发往redis中。
3.tornado读取redis中的信息,发往浏览器。
此过程用到了redis的发布和订阅功能。
先看一下tornado中是如何处理的:
import os
import sys
import tornado.websocket
import tornado.web
import tornado.ioloop
import redis
import salt.client
from tornado import gen
from tornado.escape import to_unicode
from logs.utility import get_last_lines
from logs import settings
class SubWebSocket(tornado.websocket.WebSocketHandler):
"""
此handler处理远程日志查看
"""
def open(self, *args, **kwargs):
print("opened")
@gen.coroutine
def on_message(self, message):
# 主机名,要查看的日志路径,运行脚本的命令这些信息从浏览器传过来
hostname, log_path, cmd = message.split("||")
local = salt.client.LocalClient()
r = redis.StrictRedis(host=settings.REDIS_HOST, port=settings.REDIS_PORT,
password=settings.REDIS_PASSWD, db=5)
# 订阅频道,服务器和日志路径确定一个频道
key = settings.LOG_KEY.format(server=hostname.strip(), log_path=log_path.strip())
channel = r.pubsub()
channel.subscribe(key)
# 异步方式执行命令,远程运行脚本
local.cmd_async(hostname, "cmd.run", [cmd])
try:
while True:
data = channel.get_message()
if not data:
# 如果读取不到消息,间隔一定时间,避免无谓的CPU消耗
yield gen.sleep(0.05)
continue
if data["type"] == "message":
line = format_line(data["data"])
self.write_message(line)
except tornado.websocket.WebSocketClosedError:
self.close()
def on_close(self):
global FLAG
FLAG = False
print("closed")
def format_line(line):
line = to_unicode(line)
if "INFO" in line:
color = "#46A3FF"
elif "WARN" in line:
color = "#FFFF37"
elif "ERROR" in line:
color = "red"
elif "CRITICAL" in line:
color = "red"
else:
color = "#FFFFFF"
return "<span style='color:{}'>{}</span>".format(color, line)
class EchoWebSocket(tornado.websocket.WebSocketHandler):
def open(self):
print("WebSocket opened")
@gen.coroutine
def on_message(self, message):
log = message
print "log file: ", log
try:
with open(log, 'r') as f:
for line in get_last_lines