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

前情概要

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

功能

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

目录结构

.
├── acl
│ └── acl.py
├── swlog
│ ├── admin.py
│ ├── apps.py
│ ├── form.py
│ ├── limit.py
│ ├── migrations
│ ├── models.py
│ ├── sock
│ │ ├── bin.py
│ │ ├── formstr.py
│ │ ├── sendmail.py
│ │ ├── sql.py
│ │ └── text.py
│ ├── tests.py
│ └── views.py
├── log
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── statics
│ └── jquery-3.6.0.js
└── templates
├── log.html
└── login.html

urls

from django.contrib import admin
from django.urls import path
from log import views
import threading
from log.sock.bin import logserver
urlpatterns = [
    path('admin/', admin.site.urls),
    path('login.html/', views.login),
    path('log.html/', views.log),
]
t1 = threading.Thread(target=logserver)
t1.start()

后端分页

class limit:

    def limit(self,res,obj):
        limit = int(res.GET.get('limit',1))
        pagelimit = int(res.GET.get('pagelimit',50))
        startlimit = (limit-1)*pagelimit
        endlimit = limit*pagelimit
        logdb = obj[startlimit:endlimit]
        page_count,lastpage_count = divmod(obj.count(),pagelimit) 
        if lastpage_count:
            page_count +=1
        startpage = 1
        endpage = page_count
        hrefli=[]
        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)
        if limit !=1:
            hrefli.append('<a class="page" href="%s?limit=%s">%s</a>'%(res.path,limit-1,'上一页'))
        for x in range(startpage,endpage+1):
            if limit+3 < x or x <limit -3:
                hrefli.append('<a class="page pitch hidden" href="%s?limit=%s">%s</a>'%(res.path,x,x))
            elif x == limit:
                hrefli.append('<a class="page pitch" href="%s?limit=%s">%s</a>'%(res.path,x,x))
            else:
                hrefli.append('<a class="page unpitch" href="%s?limit=%s">%s</a>'%(res.path,x,x))
        if limit != endpage:
            hrefli.append('<a class="page" href="%s?limit=%s">%s</a>'%(res.path,limit+1,'下一页'))
        href=''.join(hrefli)
        return href,logdb

views.py后端进行登录验证,拉取日志

from django.shortcuts import render

# Create your views here.
from django.shortcuts import render,redirect,HttpResponse
from log import models
from log.limit import limit
from django.views.decorators.csrf import csrf_exempt
from functools import wraps
from django.utils.safestring import mark_safe
def auth(func):
    @wraps(func)
    def check_login(res,*args,**kwargs):
        try:
            res.session['name']
            return func(res,*args,**kwargs)
        except:
            return render(res,'login.html')
    
    return check_login


@csrf_exempt
def login(res):
    if res.method == 'GET':
        return render(res,'login.html')
    elif res.method == 'POST':
        username = res.POST.get('username')
        passwd = res.POST.get('passwd')
        if models.login.objects.filter(username=username,passwd=passwd):
            res.session.set_expiry(3600)
            res.session['name']=username
            
            return redirect('/log.html')
        else:
            error = 'usernam or pwd error'
            return render(res,'login.html',{'error':error})
@auth
@csrf_exempt
def log(res):
    obj = models.log.objects
    if res.method =='GET':
        pagelimit = limit()
        html_lable,logdb = pagelimit.limit(res,obj.all())
        return render(res,'log.html',{'logdb':logdb,'limit':mark_safe(html_lable)})
    elif res.method == 'POST':
        if res.POST.get('search'):
            from django.db.models import Q
            data = res.POST.get('search')
            logdb = obj.filter(Q(time__contains=data)| Q(host__contains=data)| Q(level__contains=data)| Q(message__contains=data))[0:500]
            return render(res,'log.html',{'logdb':logdb})
        elif res.POST.get('day'):
            import time
            day = int(res.POST.get('day'))-1
            h_time = time.strftime('%Y-%m-%d',time.localtime(time.time()-86400*day))
            delete_count = obj.filter(time__lt=h_time).count()
            obj.filter(time__lt=h_time).delete()
            return redirect('/log.html')
    return redirect('/log.html')

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

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>login</title>
    <style>
        .input{width: 300px; height: 20px;margin-top: 10px;}
    </style>
</head>
<body style="background-color: royalblue;">

<div style="position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);">

 
    <form action="/login.html/" method="POST">
        <h1 style="text-align: center; color: seashell;">日志管理系统</h1>
        <input class="input" name="username" type="text" placeholder=username> 
        <br>
        <input class="input" name="passwd" type="password" placeholder=passwd>
        <br>
        <button style="width: 300px;height: 30px; margin-top: 10px;" >登录</button>
        <span>{{error}}</span>
    </form>
</div>
</body>

</html>

log.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Refresh" content="60" >   
    <title>syslog</title>
    <style>
        *{margin: 0;padding: 0;}
        .top{position: fixed;top: 0px;height: 100px;width: 100%;z-index: 100;background-color: blanchedalmond;}
        .search{float: right;margin-right: 50px;}
        .error,.crit,.alert,.emerg{background-color: rgb(243, 67, 67);}
        .debug,.notice,.info{background-color: cornflowerblue;}
        .warning{background-color: yellow;}
        td {white-space:nowrap;}
        body{background-color:whitesmoke;}
        .hidden{display:none ;}
        .pitch{background-color:black;color: white;}
        .unpitch{background-color: white;color: black;}
        a{margin-left: 10px;}
        a:hover{background-color: cornflowerblue;}
    </style>
 
</head>
<body>
    <div class="top" >
        <h3 style="text-align: center;">日志管理系统</h3>
            <form action="/log.html/" method="POST" class="search">
                <input type="text" id="search" name="search">
                <span>
                    <input type="submit" value="搜索">
                </span>
                </form>

            {{limit}}
        <form action="/log.html/" method="POST" style="margin-top:10px">
            <span>清除</span>
            <select name="day">
                <option>3</option>
                <option>7</option>
                <option>15</option>
                <option>30</option>
            </select>
            <span>天历史数据</span>
            <input type="submit" value="确定">
        </form>

    </div>
        <div class = 'message'>
        <table border="1px" style="width: 100%;">
            <tr>
                <td>time</td>
                <td>host</td>
                <td>level</td>
                <td>message</td>
            </tr>
            
                {%for mess in logdb%}
                <tr class = {{mess.level}}>
                <td>{{mess.time}}</td>
                <td>{{mess.host}}</td>
                <td>{{mess.level}}</td>
                <td>{{mess.message}}</td>
                </tr>
                {%endfor%}
                
        </table>
        
        </div>
</body>
</html>

日志采集与邮件推送模块

sql.py

import pymysql,time
class db:
    def __init__(self):
        self.conn = pymysql.connect(host='127.0.0.1',port = 3306,user = 'root',passwd = 'xxxx', db='log')
        self.coursor = self.conn.cursor()
    def write(self,host,level,message):
        ltime = time.strftime('%Y-%m-%d',time.localtime(time.time()))
        sql = 'insert into log_log(host,level,message,time) values("%s","%s","%s","%s")'%(host,level,message,ltime)
        self.coursor.execute(sql)
        self.conn.commit()
        self.conn.close()

sendmail.py

import email
import smtplib
from email.header import Header
from email.utils import formataddr
from email.mime.text import MIMEText
class sendemail():
    def __init__(self,email_list,content,subject):
        self.email_list = email_list
        self.content = content
        self.subject = subject
    def sendemail(self):
        msg = MIMEText(self.content,'plain','utf-8')
        msg['from'] = formataddr(['dark','976584601@qq.com'])
        msg['subject'] = self.subject
        service = smtplib.SMTP('smtp.qq.com')
        service.login('976584601@qq.com','password')
        service.sendmail('976584601@qq.com',self.email_list,msg.as_string())
        service.quit()

formstr.py

import re
def syslog(date):
    date = date.replace('\"','\'')
    pri = re.findall('\d+',date)[0]
    pri = int(pri)
    level = re.findall('<\d+>',date)[0]
    date = date.replace(level,'').strip()
    if pri%8 == 0:
        div_class = 'emerg'
    elif pri%8 == 1:
        div_class = 'alert'
    elif pri%8 == 2:
        div_class = 'crit'
    elif pri%8 == 3:
        div_class = 'error'
    elif pri%8 == 4:
        div_class = 'warning'
    elif pri%8 == 5:
        div_class = 'notice'
    elif pri%8 == 6:
        div_class = 'info'
    elif pri%8 == 7:
        div_class ='debug '
    return date,div_class

bin.py

import socket,re,os,subprocess
from log.sock import formstr,sql
from log.sock.sendmail import sendemail
import time

def logserver():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    address = ('10.0.0.1',514)
    s.bind(address)
    mail_level = ['error','crit','alert','emerg']
    while True:
        data,address = s.recvfrom(10240)
        data = data.decode(encoding='utf8')
        data,div_class = formstr.syslog(data)
        write_db = sql.db()
        write_db.write(address[0],div_class,data)
        if div_class in mail_level:
            title = '主机%s,严重等级%s'%(address[0],div_class)
            mail = sendemail(['cs11241991@163.com'],data,title)
            mail.sendemail()

Leave a Reply

Your email address will not be published. Required fields are marked *

X