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

浏览系统的文件夹,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('\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>

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

  1. SNF开发平台WinForm之十三-单独从服务器上获取PDF文件进行显示-SNF快速开发平台3.3-Spring.Net.Framework

    1运行效果: 2开发实现: 如果需要单独显示PDF文件时用下面代码去实现,指定url地址. 地址: . 获取附件管理的实体对象: List<KeyValuePair<string, obj ...

  2. python实现websocket服务器,可以在web实时显示远程服务器日志

    一.开始的话 使用python简单的实现websocket服务器,可以在浏览器上实时显示远程服务器的日志信息. 之前做了一个web版的发布系统,但没实现在线看日志,每次发布版本后,都需要登录到服务器上 ...

  3. lnmp vps服务器删除mysql日志文件三种方法

    我在上一篇文章介绍了著名的LNMP主机一键安装工具,对比了军哥lnmp和AMH主机的差别,由于AMH拥有用户后台界面,易于新手操作,值得推荐. 但是,上周末我网站宕机,收到DNSPOD发来了宕机提醒, ...

  4. python2.7实现websocket服务器,可以在web实时显示远程服务器日志

    一.开始的话 使用python实现websocket服务器,可以在浏览器上实时显示远程服务器的日志. 之前写了一个发布系统,每次发布版本后,为了了解发布情况(进度.是否有错误)都会登录到服务器上查看日 ...

  5. windows服务器自动删除日志文件

    https://blog.csdn.net/u010050174/article/details/72510367 步骤: 1.新建 一个bat脚本 2.添加到window执行计划中,进行每日执行. ...

  6. 将线上服务器生成的日志信息实时导入kafka,采用agent和collector分层传输,app的数据通过thrift传给agent,agent通过avro sink将数据发给collector,collector将数据汇集后,发送给kafka

    记flume部署过程中遇到的问题以及解决方法(持续更新) - CSDN博客 https://blog.csdn.net/lijinqi1987/article/details/77449889 现将调 ...

  7. python websocket网页实时显示远程服务器日志信息

    功能:用websocket技术,在运维工具的浏览器上实时显示远程服务器上的日志信息 一般我们在运维工具部署环境的时候,需要实时展现部署过程中的信息,或者在浏览器中实时显示程序日志给开发人员看.你还在用 ...

  8. django搭建一个小型的服务器运维网站-查看服务器中的日志与前端的datatable的利用

    目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...

  9. 【实操日记】使用 PyQt5 设计下载远程服务器日志文件程序

    最近通过 PyQt5 设计了一个下载服务器指定日期日志文件的程序,里面有些有意思的技术点,现在做一些分享. PyQt5 是一套 Python 绑定 Digia Qt5 应用的框架,是最强大的 GUI ...

随机推荐

  1. sublime 快捷键,左菜单乱码

    sublime 快捷键安装 packagecontrol https://packagecontrol.io/installation#st3 import urllib.request,os,has ...

  2. JSON JsonArray和JsonObject学习资料

    资料地址: http://www.json.org/json-zh.html

  3. Integer 与 int 中的 ==

    public class IntegerTest { public static void main(String args[]){ /** * int == 比较大小 */ int p1 = 100 ...

  4. Render树、RenderObject与RenderLayer

    Chapter: 呈现树的构建 1. 呈现树与CSS盒子模型千丝万缕的关系 2. 呈现树与DOM树的关系 3. 浏览器构建呈现树的流程 4. Firefox的规则树和样式上下文树 5. 规则树是如何解 ...

  5. Android OTA在线升级一(架构分析)【转】

    本文转载自:http://blog.csdn.net/yanleizhouqing/article/details/50234213 1.前言 OTA(Over-the-Air Technology) ...

  6. Linux Glibc库严重安全漏洞修复方案通知(腾讯开发者社区)

    如何查看当前glibc的版本号? rpm -aq | grep glibc 尊敬的用户:       您好!2015年1月28日, 腾讯云安全情报监测到LinuxGlibc库存在一处严重安全漏洞,可以 ...

  7. C# 中获取CPU序列号/网卡mac地址

    1.cpu序列号2.mac序列号3.硬盘id在给软件加序列号时这三个应该是最有用的,可以实现序列号和机器绑定,对保护软件很有好处.哈哈.   using System; using System.Ma ...

  8. Windows下控制Nginx的状态

    Windows下Nginx的启动.停止等命令 在Windows下使用Nginx,我们需要掌握一些基本的操作命令,比如:启动.停止Nginx服务,重新载入Nginx等,下面我就进行一些简单的介绍.1.启 ...

  9. linux lvm

    一.linux的lv(logical volume) lv各层次示例图如下: 核心思想:最底层的pv就是一个一个的磁盘,在保证总体容量的情况下,可以移除部分磁盘,在pv上面设置一个vg,相当于vg把所 ...

  10. snowflake(canvas)

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" charset=&q ...