python模块,邮件推送交换机error级别以上log,django前端展示

个人博客地址

http://www.darkghost.life

前情概要

  原syslog服务器只收集不推送日志,可以实时展示,服务器在海外内网,办公网做的有分流,到日志服务器的流量送到香港,其余流量国内,疫情期间在家办公,每次连接需要拨海外l2tp,挂着梯子访问国内时延较大影响办公,所以日志服务器基本一天登录一次,然后就错过了重要的error信息-_-!,所以在家的几天做了两个方案,1是上篇博客中的数通技术,2就是做一个功能邮箱推送error级别以上的日志

功能

  django前端用以日志的展示和搜索,后端用于日志采集与邮件推送

目录结构

-swlog

---swlog

------  setting.py

------  url.py

---log

------  models.py

------  views.py

------  limit.py

---sock

------  bin.py

------  formstr.py

------  sendmail.py

------  sql.py

---templates

------  log.html

------  login.html

 

urls

 1 from django.contrib import admin
 2 from django.urls import path
 3 from log import views
 4 import threading
 5 from log.sock.bin import logserver
 6 urlpatterns = [
 7     path('admin/', admin.site.urls),
 8     path('login.html/', views.login),
 9     path('log.html/', views.log),
10 ]
11 t1 = threading.Thread(target=logserver)
12 t1.start()
urls.py

后端分页

 1 class limit:
 2     def limit(self,res,obj):
 3         limit = int(res.GET.get('limit',1))
 4         pagelimit = int(res.GET.get('pagelimit',50))
 5         startlimit = (limit-1)*pagelimit
 6         endlimit = limit*pagelimit
 7         logdb = obj[startlimit:endlimit]
 8         page_count,lastpage_count = divmod(obj.count(),pagelimit) 
 9         if lastpage_count:
10             page_count +=1
11         startpage = 1
12         endpage = page_count
13         hrefli=[]
14         hrefli.append('<form style="display: inline;" method="GET" action="%s">每页显示<select name="pagelimit"><option>30</option><option>50</option><option>100</option><option>300</option><option>500</option></select><input type="submit" value = "确定"></form>'%res.path)
15         if limit !=1:
16             hrefli.append('<a class="page" href="%s?limit=%s">%s</a>'%(res.path,limit-1,'上一页'))
17         for x in range(startpage,endpage+1):
18             if limit+3 < x or x <limit -3:
19                 hrefli.append('<a class="page pitch hidden" href="%s?limit=%s">%s</a>'%(res.path,x,x))
20             elif x == limit:
21                 hrefli.append('<a class="page pitch" href="%s?limit=%s">%s</a>'%(res.path,x,x))
22             else:
23                 hrefli.append('<a class="page unpitch" href="%s?limit=%s">%s</a>'%(res.path,x,x))
24         if limit != endpage:
25             hrefli.append('<a class="page" href="%s?limit=%s">%s</a>'%(res.path,limit+1,'下一页'))
26         href=''.join(hrefli)
27         return href,logdb
limit.py

view后端进行登录验证,拉取日志

 1 from django.shortcuts import render,redirect,HttpResponse
 2 from log import models
 3 from log.limit import limit
 4 from django.views.decorators.csrf import csrf_exempt
 5 from functools import wraps
 6 from django.utils.safestring import mark_safe
 7 def auth(func):
 8     @wraps(func)
 9     def check_login(res,*args,**kwargs):
10         try:
11             res.session['name']
12             return func(res,*args,**kwargs)
13         except:
14             return render(res,'login.html')
15     
16     return check_login
17 
18 
19 @csrf_exempt
20 def login(res):
21     if res.method == 'GET':
22         return render(res,'login.html')
23     elif res.method == 'POST':
24         username = res.POST.get('username')
25         passwd = res.POST.get('passwd')
26         if models.login.objects.filter(username=username,passwd=passwd):
27             res.session.set_expiry(3600)
28             res.session['name']=username
29             
30             return redirect('/log.html')
31         else:
32             error = '用户名或密码错误'
33             return render(res,'login.html',{'error':error})
34 
35 @auth
36 @csrf_exempt
37 def log(res):
38     obj = models.log.objects
39     if res.method =='GET':
40         pagelimit = limit()
41         html_lable,logdb = pagelimit.limit(res,obj.all())
42         return render(res,'log.html',{'logdb':logdb,'limit':mark_safe(html_lable)})
43     elif res.method == 'POST':
44         if res.POST.get('search'):
45             from django.db.models import Q
46             data = res.POST.get('search')
47             logdb = obj.filter(Q(time__contains=data)| Q(host__contains=data)| Q(level__contains=data)| Q(message__contains=data))[0:500]
48             return render(res,'log.html',{'logdb':logdb})
49         elif res.POST.get('day'):
50             import time
51             day = int(res.POST.get('day'))-1
52             h_time = time.strftime('%Y-%m-%d',time.localtime(time.time()-86400*day))
53             delete_count = obj.filter(time__lt=h_time).count()
54             obj.filter(time__lt=h_time).delete()
55             return redirect('/log.html')
56     return redirect('/log.html')
57     
58     
views.py

templates前端简单做两个页面,一个用于登录,另一个用于展示和搜索

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7     <title>登录</title>
 8     <style>
 9         .input{width: 300px; height: 20px;margin-top: 10px;}
10     </style>
11 </head>
12 <body style="background-color: royalblue;">
13 
14 <div style="position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);">
15 
16  
17     <form action="/login.html/" method="POST">
18         <h1 style="text-align: center; color: seashell;">日志管理系统</h1>
19         <input class="input" name="username" type="text" placeholder=username> 
20         <br>
21         <input class="input" name="passwd" type="password" placeholder=passwd>
22         <br>
23         <button style="width: 300px;height: 30px; margin-top: 10px;" >登录</button>
24         <span>{{error}}</span>
25     </form>
26 </div>
27 </body>
28 
29 </html>
login.html
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7     <meta http-equiv="Refresh" content="60" >
 8     <title>Document</title>
 9     <style>
10         *{margin: 0;padding: 0;}
11         .top{position: fixed;top: 0px;height: 100px;width: 100%;z-index: 100;background-color: blanchedalmond;}
12         .search{float: right;margin-right: 50px;}
13         .error,.crit,.alert,.emerg{background-color: rgb(243, 67, 67);}
14         .debug,.notice,.info{background-color: cornflowerblue;}
15         .warning{background-color: yellow;}
16         td {white-space:nowrap;}
17         body{background-color:whitesmoke;}
18         .hidden{display:none ;}
19         .pitch{background-color:black;color: white;}
20         .unpitch{background-color: white;color: black;}
21         a{margin-left: 10px;}
22         a:hover{background-color: cornflowerblue;}
23     </style>
24  
25 </head>
26 <body>
27     <div class="top" >
28         <h3 style="text-align: center;">日志管理系统</h3>
29             <form action="/log.html/" method="POST" class="search">
30                 <input type="text" id="search" name="search">
31                 <span>
32                     <input type="submit" value="搜索">
33                 </span>
34                 </form>
35 
36             {{limit}}
37         <form action="/log.html/" method="POST" style="margin-top:10px">
38             <span>清除</span>
39             <select name="day">
40                 <option>3</option>
41                 <option>7</option>
42                 <option>15</option>
43                 <option>30</option>
44             </select>
45             <span>天历史数据</span>
46             <input type="submit" value="确定">
47         </form>
48 
49     </div>
50         <div class = 'message'>
51         <table border="1px" style="width: 100%;">
52             <tr>
53                 <td>time</td>
54                 <td>host</td>
55                 <td>level</td>
56                 <td>message</td>
57             </tr>
58             
59                 {%for mess in logdb%}
60                 <tr class = {{mess.level}}>
61                 <td>{{mess.time}}</td>
62                 <td>{{mess.host}}</td>
63                 <td>{{mess.level}}</td>
64                 <td>{{mess.message}}</td>
65                 </tr>
66                 {%endfor%}
67                 
68         </table>
69         
70         </div>
71 </body>
72 </html>
log.html

日志采集与邮件推送模块

 1 import pymysql,time
 2 class db:
 3     def __init__(self):
 4         self.conn = pymysql.connect(host='127.0.0.1',port = 3306,user = 'root',passwd = 'd****', db='log')
 5         self.coursor = self.conn.cursor()
 6     def write(self,host,level,message):
 7         ltime = time.strftime('%Y-%m-%d',time.localtime(time.time()))
 8         sql = 'insert into swlog_log(host,level,message,time) values("%s","%s","%s","%s")'%(host,level,message,ltime)
 9         self.coursor.execute(sql)
10         self.conn.commit()
11         self.conn.close()
sql.py
 1 import email
 2 import smtplib
 3 from email.header import Header
 4 from email.utils import formataddr
 5 from email.mime.text import MIMEText
 6 class sendemail():
 7     def __init__(self,email_list,content,subject):
 8         self.email_list = email_list
 9         self.content = content
10         self.subject = subject
11     def sendemail(self):
12         msg = MIMEText(self.content,'plain','utf-8')
13         msg['from'] = formataddr(['dark','97****@qq.com'])
14         msg['subject'] = self.subject
15         service = smtplib.SMTP('smtp.qq.com')
16         service.login('97****@qq.com','ilz****')
17         service.sendmail('97****@qq.com',self.email_list,msg.as_string())
18         service.quit()
sendmail.py
 1 import re
 2 def syslog(date):
 3     date = date.replace('\"','\'')
 4     pri = re.findall('\d+',date)[0]
 5     pri = int(pri)
 6     level = re.findall('<\d+>',date)[0]
 7     date = date.replace(level,'').strip()
 8     if pri%8 == 0:
 9         div_class = 'emerg'
10     elif pri%8 == 1:
11         div_class = 'alert'
12     elif pri%8 == 2:
13         div_class = 'crit'
14     elif pri%8 == 3:
15         div_class = 'error'
16     elif pri%8 == 4:
17         div_class = 'warning'
18     elif pri%8 == 5:
19         div_class = 'notice'
20     elif pri%8 == 6:
21         div_class = 'info'
22     elif pri%8 == 7:
23         div_class ='debug '
24     return date,div_class
formstr.py
 1 import socket,re,os,subprocess
 2 from log.sock import formstr,sql
 3 from log.sock.sendmail import sendemail
 4 import time
 5 
 6 def logserver():
 7     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 8     address = ('10.0.64.61',514)
 9     s.bind(address)
10     mail_level = ['error','crit','alert','emerg']
11     while True:
12         data,address = s.recvfrom(10240)
13         data = data.decode(encoding='utf8')
14         data,div_class = formstr.syslog(data)
15         write_db = sql.db()
16         write_db.write(address[0],div_class,data)
17         if div_class in mail_level:
18             title = '主机%s,严重等级%s'%(address[0],div_class)
19             mail = sendemail(['cs11241991@163.com','dark@lonlife-inc.com'],data,title)
20             mail.sendemail()
bin.py

 

 功能测试

 

 

 

 

 

 

 

 

 

 

 

posted @ 2021-08-23 17:49  无限's-blog  阅读(103)  评论(0编辑  收藏  举报