使用py 和flask 实现的服务器系统目录浏览,日志文件实时显示到网页的功能

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

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

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

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

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

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

实现代码

main.py

*- 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('\n', '<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('\n', '<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="width: 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>

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flask是一个基于Python的轻量级Web框架,可以用来快速搭建Web应用。要实现一个文件管理系统,我们可以使用Flask来处理文件的上传、下载和管理。 首先,我们需要创建一个Flask应用,并配置相应的路由和视图函数。在路由函数中,我们可以定义不同的URL来实现文件上传和下载功能。 对于文件上传功能,我们可以使用Flask提供的`request`对象来获取上传的文件,并保存在服务器上的指定目录中。例如,可以使用`request.files.get('file')`来获取上传的文件,并使用文件对象的`save()`方法将文件保存在目标目录中。 对于文件下载功能,我们可以使用Flask提供的`send_from_directory`方法来发送指定文件到客户端。我们可以使用`send_from_directory(directory, filename)`来指定文件所在的目录和文件名。 除了上传和下载功能文件管理系统还需要实现文件的查看、删除和重命名等功能。在视图函数中,我们可以通过操作文件系统的API来实现这些功能。例如,可以使用`os.listdir(directory)`获取指定目录下的所有文件,然后在网页显示出来。 另外,我们还可以使用数据库来存储文件的相关信息,如文件名、上传时间和文件的URL等。Flask提供了与多种数据库的集成,如SQLite、MySQL和PostgreSQL等,可以根据需要选择合适的数据库。 总之,使用Flask实现文件管理系统需要定义相应的路由和视图函数,处理文件上传、下载和管理的功能。在视图函数中,可以使用Flask提供的API来实现文件操作,并可选择使用数据库来存储文件的相关信息。这样就可以实现一个简单的文件管理系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值