zoukankan      html  css  js  c++  java
  • 使用py 和flask 实现的服务器系统目录浏览,日志文件实时显示到网页的功能

    看日志希望带有彩色,希望从浏览器上看到,不用连到机器上看。

     浏览系统的文件夹,scan + 系统文件夹的层级名字当做url路由,可以深层次看到机器上任何层级的文件夹,实现系统文件夹浏览下载。

    如果是点击文件夹进入子目录。

    如果是点击文件,尝试以文本格式读取文件,并以实时更新的方式显示到浏览器日志控制台并加彩。 主要是要做到不遗漏推送日志和不重复推送日志,采用的是python 操作文件的seek和tell。

    浏览系统目录和下载文件的页面

     

    查看实时日志更新的页面,提供了暂停功能和自动下拉功能。把日志根据级别加了彩色,更容易观察哪些是严重的,哪些是debug的。

     

    实现代码。

    # -*- coding: utf-8 -*-
    # @Author  : ydf
    # @Time    : 2019/6/14 17:33
    import os
    from pathlib import Path
    from flask import Flask, send_from_directory, url_for, jsonify, request, render_template, current_app, abort, g, send_file
    from flask_httpauth import HTTPBasicAuth
    from flask_bootstrap import Bootstrap
    from app.utils_ydf import LogManager, nb_print, time_util
    
    print(str((Path(__file__).parent / Path('ydf_dir')).absolute()))
    app = Flask(__name__, template_folder=str((Path(__file__).parent / Path('ydf_dir')).absolute()))
    app.config['JSON_AS_ASCII'] = False
    app.config['REFRESH_MSEC'] = 1000
    auth = HTTPBasicAuth()
    LogManager(app.logger.name).get_logger_and_add_handlers()
    bootstrap = Bootstrap(app)
    
    
    @app.route('/favicon.ico')
    def favicon():
        print(Path(__file__).parent / Path('ydf_dir/').absolute())
        return send_from_directory(str(Path(__file__).parent / Path('ydf_dir/').absolute()),
                                   'log_favicon.ico', mimetype='image/vnd.microsoft.icon')
    
    
    @app.route("/ajax0/<path:fullname>/")
    def info0(fullname):
        fullname = f'/{fullname}'
        position = int(request.args.get('position'))
        current_app.logger.debug(position)
        # if os.path.isfile(full_name):
        #     fo = open(full_name,encoding='utf8')
        #     content  = fo.read()
        #     return content
        # else :
        #     return "There is no log file"
    
        with open(fullname, 'rb') as f:
            try:
                if position == 0:
                    f.seek(-50000, 2)
                else:
                    f.seek(position, 0)
            except Exception:
                current_app.logger.exception('读取错误')
                f.seek(0, 0)
            content_text = f.read().decode()
            # nb_print([content_text])
            content_text = content_text.replace('
    ', '<br>')
            # nb_print(content_text)
            position_new = f.tell()
            current_app.logger.debug(position_new)
            # nb_print(len(content_text))
    
            return jsonify(content_text=content_text, position=position_new)
    
    
    @app.route("/ajax/<path:fullname>/")
    def info(fullname):
        fullname = f'/{fullname}'
        position = int(request.args.get('position'))
        current_app.logger.debug(position)
        # if os.path.isfile(full_name):
        #     fo = open(full_name,encoding='utf8')
        #     content  = fo.read()
        #     return content
        # else :
        #     return "There is no log file"
    
        with open(fullname, 'rb') as f:
            try:
                if position == 0:
                    f.seek(-50000, 2)
                else:
                    f.seek(position, 0)
            except Exception:
                current_app.logger.exception('读取错误')
                f.seek(0, 0)
            lines = f.readlines()
            content_text = ''
            for line in lines:
                line = line.strip().decode()
                if '- DEBUG -' in line:
                    color = '#00FF00'
                elif '- INFO -' in line:
                    color = '#00FFFF'
                elif '- WARNING -' in line:
                    color = 'yellow'
                elif '- ERROR -' in line:
                    color = '#FF00FF'
                elif '- CRITICAL -' in line:
                    color = '#FF0033'
                else:
                    color = ''
                content_text += f'<p style="color:{color}"> {line} </p>'
    
            # content_text = f.read().decode()
            # # nb_print([content_text])
            # content_text = content_text.replace('
    ', '<br>')
            # # nb_print(content_text)
            position_new = f.tell()
            current_app.logger.debug(position_new)
            # nb_print(content_text)
    
            return jsonify(content_text=content_text, position=position_new)
    
    
    @app.route("/view/<path:fullname>")
    def view(fullname):
        view_html = '''
        <html>
        <head>
        <title>查看 %s </title>
        <script type="text/javascript" src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js">
        </script>
        </head>
        <body>
        <div id="result"></div>
        <hr>
        <button onclick="toggle_scroll()"> 自动滚动浏览器滚动条 </button>
        &nbsp;
        <div style="display: inline" id="auto_scroll_stat">ON</div>
        <button id= "runButton"  style="margin-left:300px" onclick="startOrStop()"> 运行中 </button>
        <button id= "runButton"  style="margin-left:300px" > <a href="/%s/d" download="%s">下载 %s</a></button>
        </body>
        <script>
        var autoscroll = "ON";
        toggle_scroll = function(){
            if(autoscroll == "ON") autoscroll = "OFF";
            else autoscroll = "ON";
        }
        var position = 0;
        function downloadFile(){
    
        }
        get_log = function(){
         $.ajax({url: "/%s/a", data: {"position":position} ,success: function(result){
            console.debug(4444);
            var resultObj = result;
            console.debug(6666);
            //var html = document.getElementById("div_id").innerHTML;
            var html = $("#result").html();
            var  htmlShort = html.substr(-40000);
            console.debug(htmlShort);
            document.getElementById("result").innerHTML = htmlShort || "";
            console.debug($("#result").html());
            $("#result").append( resultObj.content_text);
            console.debug(resultObj.position);
            position = resultObj.position;
            if(autoscroll == "ON")
                window.scrollTo(0,document.body.scrollHeight);
            $("#auto_scroll_stat").text(autoscroll);
         }});
        }
        iid = setInterval(get_log,%s);
        status = 1;
        function startRun(){
                $("#runButton").text("运行中");
                iid = setInterval(get_log,%s);
                status = 1;
            }
    
        function stopRun(){
            $("#runButton").text("停止了");
            clearInterval(iid);
            status = 0;
        }
        function startOrStop(){
            if(status == 1){
                stopRun();}
            else
                {startRun();}
        }
        </script>
        </html>
        '''
        # return view_html % (logfilename,logfilename,logfilename,logfilename,logfilename, REFRESH_MSEC, REFRESH_MSEC)
        return render_template('/log_view_html.html', fullname=fullname)
    
    
    @app.route('/download/<path:fullname>', )
    def download_file(fullname):
        current_app.logger.debug(fullname)
        return send_file(f'/{fullname}')
        # return send_from_directory(f'/{logs_dir}',
        #                            filename, as_attachment=True, )
    
    
    @app.route('/scan/', )
    @app.route('/scan/<path:logs_dir>', )
    def index(logs_dir=''):
        current_app.logger.debug(logs_dir)
        file_ele_list = list()
        dir_ele_list = list()
        for f in (Path('/') / Path(logs_dir)).iterdir():
            fullname = str(f).replace('\', '/')
            if f.is_file():
                # current_app.logger.debug(str(f).replace('\', '/')[1:])
                # current_app.logger.debug((logs_dir, str(f).replace('\','/')[1:]))
                current_app.logger.debug(str(f))
                current_app.logger.debug(url_for('download_file', fullname=fullname[0:]))
                # current_app.logger.debug(url_for('download_file', logs_dir='', filename='windows_to_linux_syn_config.json'))
                file_ele_list.append({'is_dir': 0, 'filesize': os.path.getsize(f) / 1000000,
                                      'last_modify_time': time_util.DatetimeConverter(os.stat(str(fullname)).st_mtime).datetime_str,
                                      'url': url_for('view', fullname=fullname[1:]), 'download_url': url_for('download_file', fullname=fullname[1:]), 'fullname': fullname})
            if f.is_dir():
                fullname = str(f).replace('\', '/')
                dir_ele_list.append({'is_dir': 1, 'filesize': 0,
                                     'last_modify_time': time_util.DatetimeConverter(os.stat(str(f)).st_mtime).datetime_str, 'url': url_for('index', logs_dir=fullname[1:]), 'download_url': url_for('index', logs_dir=fullname[1:]), 'fullname': fullname})
    
        return render_template('dir_view.html', ele_list=dir_ele_list + file_ele_list, logs_dir=logs_dir)
    
    
    @app.template_filter()
    def file_filter(filefullname, file_name_part):
        if file_name_part == 1:
            return str(Path(filefullname).parent)
        if file_name_part == 2:
            return str(Path(filefullname).name)
    
    
    @app.context_processor
    def dir_processor():
        def format_logs_dir_to_multi(logs_dir):
            parent_dir_list = list()
            pa = Path(f'/{logs_dir}')
            while True:
                nb_print(pa.as_posix())
                parent_dir_list.append({'url': url_for('index', logs_dir=pa.as_posix()[1:]), 'dir_name': pa.name[:]})
                pa = pa.parent
                if pa == Path('/'):
                    parent_dir_list.append({'url': url_for('index', logs_dir=''), 'dir_name': '根目录'})
                    break
            nb_print(parent_dir_list)
            return parent_dir_list
    
        return dict(format_logs_dir_to_multi=format_logs_dir_to_multi)
    
    
    @auth.verify_password
    def verify_password(username, password):
        if username == 'user' and password == 'mtfy123':
            return True
        return False
    
    
    @app.before_request
    @auth.login_required
    def before_request():
        pass
    
    
    if __name__ == "__main__":
        # main()
        print(app.url_map)
    
        app.run(host="0.0.0.0", port=8888, threaded=True, )
        

    dir_view.html

    {% extends 'bootstrap/base.html' %}
    ​
    {% block title %} {{ logs_dir }} {% endblock %}
    {% block scripts %}
        {{ super() }}
        <script>
            (function ($) {
                //插件
                $.extend($, {
                    //命名空间
                    sortTable: {
                        sort: function (tableId, Idx) {
                            var table = document.getElementById(tableId);
                            var tbody = table.tBodies[0];
                            var tr = tbody.rows;
    
                            var trValue = new Array();
                            for (var i = 0; i < tr.length; i++) {
                                trValue[i] = tr[i];  //将表格中各行的信息存储在新建的数组中
                            }
    
                            if (tbody.sortCol == Idx) {
                                trValue.reverse(); //如果该列已经进行排序过了,则直接对其反序排列
                            } else {
                                //trValue.sort(compareTrs(Idx));  //进行排序
                                trValue.sort(function (tr1, tr2) {
                                    var value1 = tr1.cells[Idx].innerHTML;
                                    var value2 = tr2.cells[Idx].innerHTML;
                                    return value1.localeCompare(value2);
                                });
                            }
    
                            var fragment = document.createDocumentFragment();  //新建一个代码片段,用于保存排序后的结果
                            for (var i = 0; i < trValue.length; i++) {
                                fragment.appendChild(trValue[i]);
                            }
    
                            tbody.appendChild(fragment); //将排序的结果替换掉之前的值
                            tbody.sortCol = Idx;
                        }
                    }
                });
            })(jQuery);
        </script>
    {% endblock %}
    
    {% block content %}
          
        <div class="container" style=" 80%">
            <span class="label label-default">常用文件夹</span>
            <a class="label label-primary" href="{{url_for('index',logs_dir='pythonlogs/')}}" target="_blank">pythonlogs/</a>
            <a class="label label-primary" href="{{url_for('index',logs_dir='data/supervisorout')}}" target="_blank">data/supervisorout/</a>
            <table class="table" id="table1">
                {#  <caption> / {{ logs_dir }} 的文件浏览</caption> #}
                <caption>  {% for dir_item in format_logs_dir_to_multi(logs_dir)|reverse %}
                    /<a href="{{ dir_item.url }}" >  {{ dir_item.dir_name }}</a>
                {% endfor %}
                    &nbsp;的文件浏览
                </caption>
                <thead>
                <tr>
                    <th onclick="$.sortTable.sort('table1',0)">
                        <button>名称</button>
                    </th>
                    <th onclick="$.sortTable.sort('table1',1)">
                        <button>最后修改时间</button>
                    </th>
                    <th onclick="$.sortTable.sort('table1',2)">
                        <button>文件大小</button>
                    </th>
                    <th>下载文件</th>
                </tr>
                </thead>
                <tbody>
                {% for ele in ele_list %}
                    {% if ele.is_dir %}
                        <tr class="warning">
                            {% else %}
                        <tr class="success">
                    {% endif %}
    
                <td><a href="{{ ele.url }}" >{{ ele.fullname | file_filter(2) }}</a></td>
                <td>{{ ele.last_modify_time }}</td>
                <td>{{ ele.filesize }} M</td>
                <td><a href="{{ ele.download_url }}" download={{ ele.fullname | file_filter(2) }}>下载 {{ ele.fullname | file_filter(2) }}</a></td>
                </tr>
                {% endfor %}
    
                </tbody>
            </table>
    
    
        </div>
    {% endblock %}

    log_view.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>查看 {{ fullname|  file_filter(2) }} </title>
        <script type="text/javascript" src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js">
        </script>
    </head>
    <style>
        .page {
            background-color: #000000;
            color: #FFFFFF;
        }
    </style>
    <body class="page">
    
    <div id="result"></div>
    <hr>
    <button onclick="toggle_scroll()"> 自动滚动浏览器滚动条</button>
    &nbsp;
    <div style="display: inline" id="auto_scroll_stat">ON</div>
    <button id="runButton" style="margin-left:300px" onclick="startOrStop()"> 运行中</button>
    <button style="margin-left:300px"><a href="{{ url_for('download_file',fullname=fullname) }}" download={{ fullname|  file_filter(2) }}>下载 {{ fullname|  file_filter(2) }} </a></button>
    <script>
        var autoscroll = "ON";
        toggle_scroll = function () {
            if (autoscroll === "ON") autoscroll = "OFF";
            else autoscroll = "ON";
        };
        var position = 0;
    
        get_log = function () {
            $.ajax({
                url: "{{  url_for('info',fullname=fullname) }}", data: {"position": position}, success: function (result) {
                    console.debug(4444);
                    var resultObj = result;
                    console.debug(6666);
                    //var html = document.getElementById("div_id").innerHTML;
                    var resultEle = $("#result");
                    var html = resultEle.html();
                    var htmlShort = html.substr(-50000);
                    console.debug(htmlShort);
                    document.getElementById("result").innerHTML = htmlShort;
                    console.debug(resultEle.html());
                    resultEle.append(resultObj.content_text);
                    console.debug(resultObj.position);
                    position = resultObj.position;
                    if (autoscroll === "ON") {
                        window.scrollTo(0, document.body.scrollHeight);
                    }
                    $("#auto_scroll_stat").text(autoscroll);
                }
            });
        };
        iid = setInterval(get_log, {{ config.REFRESH_MSEC }});
        runStatus = 1;
    
        function startRun() {
            $("#runButton").text("运行中");
            iid = setInterval(get_log, {{ config.REFRESH_MSEC }});
            runStatus = 1;
        }
    
        function stopRun() {
            $("#runButton").text("暂停了");
            clearInterval(iid);
            runStatus = 0;
        }
    
        function startOrStop() {
            if (runStatus === 1) {
                stopRun();
            } else {
                startRun();
            }
        }
    </script>
    
    
    </body>
    </html>
  • 相关阅读:
    Erlang顺序型编程
    [转]理解gen_server behaviour
    [转]Parsing Text and Binary Files With Erlang
    [转]Running Hadoop On Ubuntu Linux (SingleNode Cluster)
    [转]erlang 监督树
    [转]Erlang之IO编程
    [转]分段表
    [转]如何“打败”CAP定理
    [转]A Millionuser Comet Application with Mochiweb
    [转]消息队列软件大比拼
  • 原文地址:https://www.cnblogs.com/ydf0509/p/11032904.html
Copyright © 2011-2022 走看看