在日常工作中,我们以往登录到服务器部署安装环境时,所操作的命令都是实时打印过程信息或者查看应用日志实时输出日志的时候我们也可以用tailf命令实时显示,

但是当我们把这些工作web平台化之后,怎么使用实时查看日志呢,我使用过以下两种方法实现:

1. 前端网页使用ajax定时向服务器请求获取日志信息返回。是不是有点low,但功能还是实现了。

2. 前端网页使用websocket建立连接,实时从服务器接收日志。

目前使用第二种方法通过使用flask来实现。

以下简单演示实现过程,从服务器中实时显示日志,可根据实际情况进行修改。

配图,代码参考往下内容

1.测试环境python3 使用pip安装以下库

flask==1.1.2

gevent==20.9.0

gevent-websocket==0.10.1

2.服务端代码

import os
import time
import logging
from gevent import monkey

monkey.patch_all()
from gevent.pywsgi import wsgiserver
from geventwebsocket.handler import websockethandler
from geventwebsocket.exceptions import websocketerror
from flask import flask, request, render_template
from multiprocessing import cpu_count, process

app = flask(__name__)

def tailf(filename, websocket):
    """打开文件并把读取内容发给websocket"""
    with open(filename) as f:
        # 输出已经存在的文件内容
        websocket.send(''.join(f.readlines()))
        # 移动到了文件eof处
        f.seek(0, 2)
        while true:
            line = f.readline()
            if line:
                websocket.send(line)
            else:
                time.sleep(1)


@app.route('/tailf/')
def tailf_log():
    websocket = request.environ['wsgi.websocket']
    # 演示功能这里写死,实际使用可自定义
    filename = '/data/ops/20201117/test.log'
    if os.path.exists(filename):
        try:
            tailf(filename, websocket)
        except websocketerror as e:
            logging.info('error {} websocket closed!'.format(e))
            websocket.close()
        return 'ok'
    else:
        websocket.send('<h3>查看的文件不存在!</h3>')


@app.route('/')
def index():
    return render_template('index.html')


# 日志配置
logging.basicconfig(
    filename='logs.log',
    format='%(asctime)s %(levelname)s: %(message)s',
    level='info')
# 实例化 这里包括监听端口
ws_server = wsgiserver(
    ('0.0.0.0', 5000),
    app,
    log=logging,
    handler_class=websockethandler,
)
ws_server.start()


def serve_forever():
    try:
        ws_server.start_accepting()
        ws_server._stop_event.wait()
    except keyboardinterrupt:
        ws_server.stop()


if __name__ == "__main__":
    # 用multiprocessing配合gevent来启动多进程
    for i in range(cpu_count()):
        p = process(target=serve_forever)
        p.start()

3.前端代码(需要引入jquery.min.js

<!doctype html>
<html lang="en">
<head>
    <title>实时日志查看</title>
    <!-- jquery 3 -->
    <script src="{{ url_for('static', filename='jquery/dist/jquery.min.js') }}"></script>
</head>
<body>
<div class="container">
    <div id="log_id" style="height: 95vh; overflow-y: scroll;padding: 10px;">
        <pre></pre>
    </div>
</div>
<script>
    var ws_scheme = window.location.protocol === "https:" ? "wss" : "ws";
    var socket = new websocket(ws_scheme + '://' + "192.168.209.222:5000/tailf/");
    var log_id = $("#log_id");
    var log_pre_id = $("#log_id pre");

    socket.onopen = function () {
        socket.onmessage = function (msg) {
            log_pre_id.append(msg.data);
            // 滚动条滚动到最低部
            log_id.scrolltop(log_pre_id.height() - log_id.height());
        };
    };
    socket.onerror = function () {
        log_pre_id.innerhtml = '<h3>连接websocket失败!</h3>';
    };

    window.onbeforeunload = function (event) {
        console.log("关闭websocket连接!");
        socket.close();
    }
</script>
</body>
</html>

4.运行代码进行测试

在服务器上模拟定时输出信息到日志文件

for i in $(seq 1 1000);do echo -e “$i —————-” >> /data/ops/20201117/test.log;sleep 1;done

在浏览器打开网页实时查看

ps: 我比较好奇在头条发这一类文章有没有流量的,毕竟在这里的大部分以手机端娱乐为主