目录
- 项目介绍和源码;
- 拿来即用的bootstrap模板;
- 服务器SSH服务配置与python中paramiko的使用;
- 用户登陆与session;
- 最简单的实践之修改服务器时间;
- 查看和修改服务器配置与数据库的路由;
- 基于websocket的实时日志实现;
- 查看服务器中的日志与前端的datatable的利用;
- 重启服务器进程。
前言
除了能够支持实时的日志之外,小项目还需要增加一个回看日志的页面,页面的效果如图1所示。这个页面的作用是按用户的需求(日志的日期、日志内容的时间、日志的内容)筛选出需要的日志并且展示到这个datatable的动态表格中,它的实现原理很简单,但是具有一定的局限性。但是可以满足一些本身不多的日志的查看,如错误日志、测试日志、服务器日志这些。
功能内容
显示页面
页面由一个Datatable和自己写的一些input组件组成,其html脚本如下。
{% extends "./base.html" %}
{% block othercss %}
<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet" />
{% endblock %}
{% block title %}{{ title }}{% endblock %}
{% block log %}{{ title }}{% endblock %}
{% block username %}{{ username }}{% endblock %}
{% block mainbody %}
<section class="wrapper site-min-height">
<h3><i class="fa fa-angle-right"></i> 查找日志 <i class="fa fa-desktop"></i></h3>
<div class="row mt">
<div class="form-panel">
<div class="col-lg-12 row mt">
<div class="col-sm-6">
<h4 class="mb" style="float:left;dispaly:block;">查找日志</h4>
</div>
<div class="col-sm-5 search">
<input type="text" class="form-control" id='contentkey' placeholder='关键内容或日志名(可填)'>
<input type="text" class="form-control" id="date">
<div class="row">
<div class="col-sm-8">
<input type="text" class="form-control" id="time" placeholder='选择时间段(必填)'>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-theme02" id='searchlog' style="float:right;">查找日志</button>
</div>
</div>
</div>
</div>
<div>
<div class="progress progress-striped active" style="display:none" id="loading">
<div class="progress-bar" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
</div>
<table id="logtable" class="table-striped dataTable table-advance table-hover" style="word-break:break-all;">
<thead>
<tr>
<th style="width:25%;">日志时间</th>
<th style="width:15%;">名字</th>
<th>日志内容</th>
</tr>
</thead>
<tbody id="log">
</tbody>
</table>
</div>
</div>
</div>
</section>
{% endblock %}
控制这个html界面的javascript代码如下,代码中laydate
组件的作用是针对图2中的蓝框中的时间选择器,它的引用在文章最简单的实践之修改服务器时间中提到过,具体的使用方法可以移步文章layDate 日期与时间组件, $('#logtable').DataTable({...})
用来初始化一个定制的动态响应表格,后文中会具体说说它的使用。当用户填好内容之后点击查找日志按钮,会执行$("#searchlog").click(function(){...})
函数,它会依次判断日期、时间段是否已经填写,由于筛选日志时候用的是时间段,所以还会判断一下首尾时间是否相等。
{% block scripts %}
<script>
// 获取当前的日期,在用户选择日期的时候input栏默认显示为当前日期
var formatDate = function (date) {
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? '0' + m : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
return y + '-' + m + '-' + d;
};
$(document).ready(function (){
$('#logtable').DataTable({
"scrollCollapse": true,
'columnDefs':[{
'targets' : [0,1,2], //除时间列以外都不排序
'orderable' : false
}],
"order": [[0 , "asc" ]],
"oLanguage": {
"sZeroRecords": "无结果!",
"sSearch": "日志过滤:",
},
});
laydate.render({
theme: 'molv',
elem: '#date',
// input栏默认当前日期
value: formatDate(new Date())
});
// 时间范围
laydate.render({
theme: 'molv',
elem: '#time',
type: 'time',
format: 'H点',
range: true
});
});
$("#searchlog").click(function(){
keycontent = $("#contentkey").val();
date = $("#date").val();
if(date == ''){
swal('', '请选择日期!', 'error')
return ;
}
time = $("#time").val();
if(time == ''){
swal('', '请填写时间段!', 'error')
return ;
}
// 判定首尾时间是否相等,由于是取时间段,首尾时间相等时是不允许的
_time = time.split("-");
begin_time = _time[0].replace(/\s/ig,'');
end_time = _time[1].replace(/\s/ig,'');
if(begin_time == end_time){
swal('', '首位时间相等,请重新输入!', 'error')
return ;
}
var table = $('#logtable').DataTable().clear().draw();
table.clear().draw();
$.ajax({
url:"searchlog",
type:'POST',
data:{'keycontent':keycontent, 'date':date, 'time':time},
success: function(arg){
ret = eval(arg);
logs = ret.logs;
for(j = 0,len = logs.length; j < len; j++) {
logtime = logs[j][0];
logname = logs[j][1];
logcontent = logs[j][2];
table.row.add([logtime,logname,logcontent]).draw(true);
}
}
});
});
</script>
<script src="/templates/servermaterial/assets/laydate/laydate.js"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
{% endblock %}
添加server/urls.py中的url函数url(r'^searchlog', views.searchlog)
。
在server/views.py中添加页面渲染函数log和由url请求过来的searchlog功能函数:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib.auth import logout
from django.shortcuts import render_to_response
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
import json
import time
'''以下这些函数是渲染前端模板的函数'''
# 服务器的名字
htmltitle = '服务器工具'
# 页面渲染函数
@login_required(login_url='/loginpage')
def log(request):
username = request.session.get('username')
pagedict = {'title': htmltitle, 'username': username}
return render_to_response("servermaterial/log.html", pagedict)
# 查找日志
def searchlog(request):
ret = {'status': False, 'logs': ''}
if request.method == 'POST':
from WebTool.functions import get_filter_log
# 关键内容
keycontent = request.POST.get('keycontent')
# 日志日期
logdate = request.POST.get('date')
# 日志筛选的时间段
logtime = request.POST.get('time')
filter_list = [keycontent, logdate, logtime]
logs = get_filter_log(filter_list)
ret['status'] = True
ret['logs'] = logs
return JsonResponse(ret)
searchlog
中的get_filter_log
函数是根据服务器中日志的形式单独定制的,所以在前面的文章中没有写过它的实现,下面的服务器中的日志内容中会实现一个get_filter_log
函数。
服务器中的日志内容
- 服务器中日志格式
如图3,服务器中的日志名字规律用log-(日期)的格式存放着,每个txt日志的文档内容都形如图4所示,日志中会记录条目生成的时间,名字和内容。
- paramiko实现get_filter_log函数
根据日志的名字规律和格式可以单独写一个paramiko函数如下,写好的函数放在Webtool/Webtool中的functions文件中。用到了一些简单的Linux命令行。
'find /home/logs -name *' + filter_date + '*.txt'
用来在日志文件夹下查找给定日期的日志文件。
| xargs cat
将查找到的结果执行cat。
grep -E \'' + filter_time + '\' | grep -i ' + filter_content
用来在cat的结果中查找符合时间段和内容的结果。
可以看出这里,查找日志的方式是使用cat
一步到位的,所以对于日志内容很大的情况,需要很长一段时间,特别是还要传递到前端的datatable中显示。
# 获得服务器的日志
def get_filter_log(filter_list):
ssh = login_server_by_pwd()
# 筛选日志的时期
filter_date = filter_list[1].replace('-', '')
_filter_date = filter_list[1]
# 筛选日志的时间
filter_content = filter_list[0]
# 筛选日志的时间范围
time_range = filter_list[2]
beg_time, end_time = re.findall("\d+", time_range)
beg_time = int(beg_time)
end_time = int(end_time)
if beg_time > end_time:
beg_time, end_time = end_time, beg_time
# 根据首尾时间生成每个单独时间用于日志帅选
time_list = ["%02d" % num for num in range(beg_time, end_time)]
filter_time = ''
# 可被Linux执行的命令行
for _time in time_list:
filter_time += (_filter_date + ' ' + _time + ':|')
filter_time = filter_time[:-1]
# 检查是否存在该天的日志
stdin, stdout, stderr = ssh.exec_command('find /home/logs -name *' + filter_date + '*.txt')
istxt = bool(len(stdout.read()))
# 如果存在改天的日志
if istxt:
# 如果有需要进一步筛选内容
if filter_content:
filter_command = 'find /home/logs -name "*' \
+ filter_date + '*.txt" | xargs cat | grep -E \'' \
+ filter_time + '\' | grep -i ' + filter_content
else:
filter_command = 'find /home/logs -name "*' \
+ filter_date + '*.txt" | xargs cat | grep -E \'' + filter_time + '\''
print filter_command
stdin, stdout, stderr = ssh.exec_command(filter_command)
raw_log = stdout.read()
log = re.findall("\[(.*?)\]\[(.*?)\],({.*})", raw_log)
return log
Datatable的使用
关于Datatable的使用可以参考的文章很多,这里只是说下这个页面中dataatable的使用。它的javascript函数很简单,如下:
$('#logtable').DataTable({
"scrollCollapse": true,
'columnDefs':[{
'targets' : [1,2], // 除时间列以外都不排序,0列为时间,1列为名字,2列为内容
'orderable' : false
}],
"order": [[0 , "asc" ]], // 时间列默认按升序排列
"oLanguage": {
"sZeroRecords": "无结果!", // 表格没有内容的时候显示无结果!,如图5红色框
"sSearch": "日志过滤:", // 搜索栏的提示,如图5蓝色框
},
});
下面的javascript代码通过ajax请求到后台之后,将后台传递上来的日志结果一个个增加到表格中,table.row.add([logtime,logname,logcontent]).draw(true)
这个函数用来向datatable中增加数据。
$.ajax({
url:"searchlog",
type:'POST',
data:{'keycontent':keycontent, 'date':date, 'time':time},
success: function(arg){
ret = eval(arg);
logs = ret.logs;
for(j = 0,len = logs.length; j < len; j++) {
logtime = logs[j][0];
logname = logs[j][1];
logcontent = logs[j][2];
table.row.add([logtime,logname,logcontent]).draw(true);
}
}
});
结语
这里说了下怎么实现查看服务器已经存在的日志,但是这个方法本身是存在缺陷的,它只适用于比较小的日志文件的显示,大文件需要很长一段时间。