Use py and flask to browse the server system directory, and log files can be displayed on the web page in real time

I hope to see the log in color, and I hope to see it from the browser instead of connecting to the machine.

Browse the folders of the system, scan + the hierarchical name of the system folder as url routing, you can deeply see the folders at any level on the machine, and realize the browsing and downloading of the system folders.

If you click on the folder to enter the subdirectory.

If you click on the file, try to read the file in text format, and display it to the browser log console with real-time updates and add color. The main purpose is to ensure that the push logs are not missed and the push logs are not repeated, and the seek and tell of the python operation file are used.

Browse the page for system directories and download files

View the page for real-time log updates, providing a pause function and an automatic pull-down function. The logs are colored according to the level, which makes it easier to see which ones are serious and which ones are debug.

Implement the code.

# -*- 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('read error')
            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('read error')
            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>View %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>
    
    <button onclick="toggle_scroll()"> Auto scroll browser scroll bar </button>
     &nbsp;
    <div style="display: inline" id="auto_scroll_stat">ON</div>
    <button id= "runButton" style="margin-left:300px" onclick="startOrStop()"> Running </button>
    <button id= "runButton" style="margin-left:300px" > <a href="/%s/d" download="%s">Download %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("Running");
            iid = setInterval(get_log,%s);
            status = 1;
        }

    function stopRun(){
        $("#runButton").text("stopped");
        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': 'root directory'})
                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 ($) {
            //plugin
            $.extend($, {
                //Namespaces
                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]; //store the information of each row in the table in the newly created array
                        }

                        if (tbody. sortCol == Idx) {
                            trValue.reverse(); //If the column has already been sorted, it will be reversed directly
                        } else {
                            //trValue.sort(compareTrs(Idx)); //sort
                            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(); //Create a new code fragment to save the sorted results
                        for (var i = 0; i < trValue. length; i ++ ) {
                            fragment.appendChild(trValue[i]);
                        }

                        tbody.appendChild(fragment); //Replace the sorted result with the previous value
                        tbody.sortCol = Idx;
                    }
                }
            });
        })(jQuery);
    </script>
{<!-- -->% endblock %}

{<!-- -->% block content %}
      
    <div class="container" style="width: 80%">
        <span class="label label-default">Frequent Folder</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">
            File browsing for {<!-- --># <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;'s file browse
            </caption>
            <thead>
            <tr>
                <th onclick="$.sortTable.sort('table1',0)">
                    <button>Name</button>
                </th>
                <th onclick="$.sortTable.sort('table1',1)">
                    <button>Last modified time</button>
                </th>
                <th onclick="$.sortTable.sort('table1',2)">
                    <button>File Size</button>
                </th>
                <th>Download file</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) }}>Download{< !-- -->{ 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>View {<!-- -->{ 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>

<button onclick="toggle_scroll()"> Automatically scroll the browser scroll bar</button>
 &nbsp;
<div style="display: inline" id="auto_scroll_stat">ON</div>
<button id="runButton" style="margin-left:300px" onclick="startOrStop()"> Running</button>
<button style="margin-left:300px"><a href="{<!-- -->{ url_for('download_file',fullname=fullname) }}" download={<! -- -->{ fullname| file_filter(2) }}>Download{<!-- -->{ 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("Running");
        iid = setInterval(get_log, {<!-- -->{ config.REFRESH_MSEC }});
        runStatus = 1;
    }

    function stopRun() {
        $("#runButton").text("Paused");
        clearInterval(iid);
        runStatus = 0;
    }

    function startOrStop() {
        if (runStatus === 1) {
            stopRun();
        } else {
            startRun();
        }
    }
</script>


</body>
</html>