發送Django error log 到企業微信,python+微信實現即時告警

發送Django error log 到企業微信,python+微信實現即時告警

Django的logging系統十分好用,使用file,mail_admins之類的handlers可以快捷地實現保存日誌到文件,發送錯誤日誌給管理員的功能。但是,如果能直接將應用的錯誤日誌發送到手機上,實現即時告警,豈不是更好?



註冊企業微信1

  1. 首先需要註冊一個企業微信賬號,地址是:
    https://work.weixin.qq.com/wework_admin/register_wx?from=myhome

    注意

    註冊過程如果是爲企業使用要選擇企業,然後上傳企業的資質證明,如果是個人註冊,選擇團隊,然後輸入自己的身份證號即可完成註冊.
  2. 然後進入企業應用頁面,添加一個應用,添加完成後,進入應用頁面:
    這裏寫圖片描述

    • 這裏的agentid和secret需要留意, 後續的發送信息api需要它們。
    • 另外我們還需要corpid,在我的企業-企業信息中可以找到。

使用企業微信API發送消息

  1. 測試使用企業微信API發送消息:
    企業微信API:發送消息
    例子:

    
    #! /usr/bin/env python
    
    
    # -*- coding: utf-8 -*-
    
    
    import requests
    import json
    
    
    def get_token():
    
       url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken'
       values = {
           'corpid': '<YOUR CORPID>',
           'corpsecret': '<YOUR SECRET>',
          }
       req = requests.post(url, params=values)
       data = json.loads(req.text)
       return data["access_token"]
    
    
    def send_msg():
       url = ("https://qyapi.weixin.qq.com/cgi-bin/message/send"
              "?access_token={}").format(get_token())
       values = {
           # "touser": "@all",
           "toparty": "2",
           "msgtype": "text",
           "agentid": "<YOUR AGENTID>",
           "text": {
               "content": u"報警測試,toparty: 2"
           },
           }
    
       req = requests.post(url, json.dumps(values))
       print(values, req)
    
    
    if __name__ == '__main__':
       send_msg()

    其中toparty:2,意爲向id爲2的部門的所有成員發送消息。
    使用touser:@all, 可以向所有人發送信息。

發送django的log到企業微信

  1. 配置Django的logging系統
    接下來我們需要配置一下django的logging系統,來發送ERROR級別的log到企業微信。
    我的思路是可以參照django自帶的AdminEmailHandler寫一個WechatAlarmHandler。
    代碼如下:

    import logging
    import requests
    import json
    from copy import copy
    
    
    from django.core.cache import cache
    from django.views.debug import ExceptionReporter
    
    
    class WechatAlarmHandler(logging.Handler):
        """An exception log handler that sends log entries to wechat alarm bot.
    
        If the request is passed as the first argument to the log record,
        request data will be provided in the email report.
        """
    
        def __init__(self):
            logging.Handler.__init__(self)
    
        def emit(self, record):
            try:
                request = record.request
                subject = '%s (%s IP): %s' % (
                    record.levelname,
                    ('internal' if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS # NOQA
                     else 'EXTERNAL'),
                    record.getMessage()
                )
            except Exception:
                subject = '%s: %s' % (
                    record.levelname,
                    record.getMessage()
                )
                request = None
            subject = self.format_subject(subject)
    
            # Since we add a nicely formatted traceback on our own, create a copy
            # of the log record without the exception data.
            no_exc_record = copy(record)
            no_exc_record.exc_info = None
            no_exc_record.exc_text = None
    
            if record.exc_info:
                exc_info = record.exc_info
            else:
                exc_info = (None, record.getMessage(), None)
    
            reporter = ExceptionReporter(request, is_email=True, *exc_info)
            message = "%s\n\n%s" % (
                self.format(no_exc_record), reporter.get_traceback_text())
            self.send_msg(subject, message)
    
        def send_msg(self, subject, message, *args, **kwargs):
            WechatAlarm().send_msg('{}'.format(subject))
    
        def format_subject(self, subject):
            """
            Escape CR and LF characters.
            """
            return subject.replace('\n', '\\n').replace('\r', '\\r')
    
    
    class WechatAlarm:
        def __init__(self, corpid='<YOUR CORPID>',
                     corpsecret='<YOUR SECRET>',
                     agentid='<YOUR AGENTID>', partyid='<YOUR PARTYID>'):
            self.corpid = corpid
            self.partyid = partyid
            self.key = 'wechat_send_alarm_key'
            self.corpsecret = corpsecret
            self.agentid = agentid
    
        def get_token(self):
            token = cache.get(self.key)
            if token:
                return token
            else:
                url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken'
                values = {
                    'corpid': self.corpid,
                    'corpsecret': self.corpsecret,
                   }
                req = requests.post(url, params=values)
                data = json.loads(req.text)
                cache.set(self.key, data["access_token"], 7200)
                return data["access_token"]
    
        def send_msg(self, content=None):
            url = ("https://qyapi.weixin.qq.com/cgi-bin/message/send"
                   "?access_token={}").format(self.get_token())
            values = {
                # "touser": "@all",
                "toparty": self.partyid,
                "msgtype": "text",
                "agentid": self.agentid,
                "text": {
                    "content": content,
                },
                }
    
            return requests.post(url, json.dumps(values))
    

    再配置一下django的settings裏的LOGGING:

    GGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'verbose': {
                'format': '[%(asctime)s](%(levelname)s)<%(name)s.%(funcName)s>{%(process)d/%(thread)d} : %(message)s'
            },
            'simple': {
                'format': '%(levelname)s %(message)s'
            },
        },
        'filters': {
            'require_debug_false': {
                '()': 'django.utils.log.RequireDebugFalse'
            }
        },
        'handlers': {
            'null': {
                'level': 'DEBUG',
                'class': 'django.utils.log.NullHandler',
            },
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
                'formatter': 'simple'
            },
            'mail_admins': {
                'level': 'ERROR',
                'class': 'django.utils.log.AdminEmailHandler',
                'filters': ['require_debug_false'],
            },
            'send_wechat': {
                'level': 'ERROR',
                'class': 'utils.log.WechatAlarmHandler',   # your handler path
            },
            'file': {
                'level': 'INFO',
                'class': 'logging.handlers.TimedRotatingFileHandler',
                'formatter': 'verbose',
                'filename': webservice_logfile,
                'when': 'D'
            },
        },
        'loggers': {
            '': {
                'handlers': ['file', 'mail_admins', 'send_wechat'],
                'propagate': True,
                'level': 'ERROR',
            },
            'django': {
                'handlers': ['file', 'mail_admins'],
                'propagate': True,
                'level': 'ERROR',
            },
            'django.request': {
                'handlers': ['file', 'mail_admins', ],
                'level': 'ERROR',
                'propagate': True,
            },
        }
    }
    

    即,在handler裏增加了一個send_wechat, 在loggers裏的handers裏增加了send_wechat。

這樣django的error log就會通過企業微信發送到手機了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章