簡易報警監控 tail -f 最後一條日誌,通知到釘釘

  1. 支持文件刪除後重新監控日誌
  2. 支持手動編輯文件後,繼續報警
  3. 多進程,支持監聽多個日誌文件,自定義定義羣
  4. 支持自定義日誌處理方法,可以發送到kafka 做日誌收集等等
# coding=utf-8
import json
import os
import sys
import time
from multiprocessing import Process, Queue, Pool

import requests


class Tail(object):
    def __init__(self, file_list):
        self.fileList = file_list
        self.author = "banxia"
        self.__callBack = sys.stdout.write

    def logger(self, message="", type="error"):
        error_log = "./" + type + ".log"
        if message:
            with open(error_log, 'a+') as f:
                f.write(json.dumps({'message': str(message)}))
                f.write("\n")

    def register_callback(self, func):
        self.__callBack = func

    def main_tail(self, file_name, config):
        last_position = 0
        while True:
            last_position = self.__tail(file_name, last_position, config)
            time.sleep(0.1)

    def __tail(self, file_name, last_position=0, config=None):
        count = 0
        if not os.path.isfile(file_name):
            return 0

        with open(file_name, 'r') as f:
            if last_position == 0:
                f.seek(0, 2)
            else:
                f.seek(last_position)
            while True:
                position = f.tell()
                content = f.readline()
                if not content:
                    if count > 60:
                        # print("重新讀取文件:" + str(count))
                        return position
                    time.sleep(0.1)
                    count += 1
                else:
                    try:
                        self.__callBack(content, config)
                    except Exception as e:
                        print(e)
                        self.logger(str(e))

    def run(self):
        pool = Pool(len(self.fileList))
        for config in self.fileList:
            if 'path' not in config:
                continue
            filename = config.get('path')
            func = self.main_tail
            pool.apply_async(func, (filename, config,))
        pool.close()
        pool.join()


class httpclient(object):
    @staticmethod
    def get(url, params=None):
        res = requests.get(url, params)
        return res
        # return res.text.encode('utf-8').decode('unicode_escape')

    @staticmethod
    def postJosn(url, params=None, hds={}):
        hds['Content-Type'] = 'application/json'
        params = json.dumps(params)
        res = requests.post(url, params, headers=hds)
        # return res.text.encode('utf-8').decode('unicode_escape')
        return res


def ding_push(content, config):
    token = config.get('token')
    url = "https://oapi.dingtalk.com/robot/send?access_token=" + token
    msg = {
        "msgtype": "text",
        "text": {
            "content": "通知"
        },
        "at": {
            "atMobiles": [
            ],
            "isAtAll": 'true'
        }
    }
    msg['text']['content'] = "【通知】" + config.get('path') + ":\n" + content
    ret = httpclient.postJosn(url, msg)
    ret_json = ret.json()
    if ret_json['errcode'] != 0:
        print(ret.text)


if __name__ == '__main__':
    file_list = [
        {'path': 'test.log', 'token': '1'},
        {'path': 'test1.log', 'token': '2'}
    ]
    tail = Tail(file_list)
    tail.register_callback(ding_push)
    tail.run()

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