基于python的open-falcon 多日志多关键字监控插件

最近公司业务运维对日志要求关键字监控,网上的open-logdog是基于go语言开发的插件,编译测试发现有些问题不符合自己公司的要求,迫于时间压力,使用python进行了改造,满足多日志、多关键字、忽略大小写及定时推送数据到接口,主代码如下:

#!/usr/bin/python
# coding=utf-8

import sys
import re
import time
from commands import getstatusoutput as getcmd
import threading
import subprocess
from collections import Counter as counter
import sched
from config import conf

class LogMonitor(object):

    def __init__(self):
        self.logfile = '/tmp/info.log'
        self.tmp = []
        self.data = {}
        self.key = {}
        self.schedule = sched.scheduler(time.time, time.sleep)

        self.type_post = [
            "LogKeys"
        ]
        self.data_post = {
            "metric": conf["metric"],
            "endpoint": "",
            "timestamp": 1,
            "step": conf["timer"],
            "value": 0,
            "counterType": "GAUGE",
            "tags": ""
        }

    def timer(self):
        self.post(inc=conf["timer"])

    def watch_file(self, path, logname, keywords):
        logfile = path + logname
        try:
            popen = subprocess.Popen('tail -f ' + logfile, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            while True:
                line = popen.stdout.readline().strip()
                if re.findall(r'(?i)%s' % keywords, line):
                    rt = map(str.lower, re.findall(r'(?i)%s' % keywords, line))
                    for k in rt:
                        self.tmp.append(k)
                    self.key[logname] = counter(self.tmp)
                    self.data.update(self.key)

        except Exception, e:
            print e

    def collect_data(self):
        try:
            import json
        except:
            import simplejson as json
        data = ""
        timestamp = int(time.time())
        _, hostname = getcmd('hostname')
        _, ip = getcmd(''' ip a|awk '{if($0~/inet .* brd/ && $2~/^10|^192.168|^172.(1[6-9]|2[1-9]|3[0-1])/) {gsub("/.*|^ | $","",$0); print $2;exit}}' ''')
        endpoint = hostname + "-" + ip
        for i in conf.get("files"):
            logname = i.get("logname")
            keywords = i.get("keywords")
            for key in keywords:
                self.data_post["timestamp"] = timestamp
                self.data_post["endpoint"] = endpoint
                self.data_post["tags"] = "log="+logname + ",key=" + key
                if self.data.get(logname):
                    if self.data.get(logname).get(key.lower()):
                        self.data_post["value"] = self.data.get(logname).get(key.lower())
                    else:
                        self.data_post["value"] = 0
                else:
                    self.data_post["value"] = 0


                data_t = json.dumps(self.data_post)
                if data == "":
                    data = "%s" % (data_t)
                else:
                    data = data + ",%s" % data_t
        return data

    def post(self, cmd='', inc=60):
        url = conf.get("agent")
        data = self.collect_data()
        data = "[%s]" % (data)
        cmd = "/usr/bin/curl -X POST -d  '%s' %s" % (data, url)
        getcmd(cmd)
        self.record('info',data)
        self.tmp = []
        self.key = {}
        self.data = {}
        self.schedule.enter(inc, 0, self.post, (cmd, inc))
        self.schedule.run()

    def record(self, level, messages):
        import logging
        logger = logging.getLogger()
        if not logger.handlers:
            logger.setLevel(logging.DEBUG)
            w_log = logging.FileHandler(self.logfile)
            # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s : %(message)s')
            formatter = logging.Formatter('%(asctime)s-%(levelname)s:  %(message)s')
            w_log.setFormatter(formatter)
            logger.addHandler(w_log)

        if level.lower() == "info":
            logger.info(messages)
        elif level.lower() == "debug":
            logger.debug(messages)
        elif level.lower() == "warn":
            logger.warning(messages)
        elif level.lower() == "error":
            logger.error(messages)
        else:
            logger.info(messages)

    def echo(self, messages, color='green', backgroud=False, raw=False):
        backgroud = '4' if backgroud else '3'

        color_dict = {'red': '1', 'green': '2', 'yellow': '3', 'blue': '4', 'purple': '5', }
        if color in color_dict:
            msgs = '\033[%s%sm%s\033[0m' % (backgroud, color_dict.get(color), messages)
        else:
            msgs = messages

        if raw:
            v = raw_input(msgs).strip()
        else:
            print(msgs)
            v = None
        if color == "red":
            self.record('error', messages)
        elif color == "yellow":
            self.record('warn', messages)
        else:
            self.record('info', messages)

        return v

def main():
   
    u = LogMonitor()
    data = conf.get("files")
    threads = []
    nloops = range(len(data) + 1)
    for v in data:
        keywords = '|'.join(v.get("keywords"))
        path = v.get("path")
        logname = v.get("logname")
        t = threading.Thread(target=u.watch_file, args=(path, logname, keywords))
        threads.append(t)


    t1 = threading.Thread(target=u.timer, args=())
    threads.append(t1)


    for i in nloops:
        threads[i].start()


    for i in nloops:
        threads[i].join()


if __name__ == '__main__':
    try:
        main()
    except BaseException as e:
        print e
配置文件config.py如下:

conf = {
  "metric": "log",
  "timer": 30,
  "agent": "http://127.0.0.1:1988/v1/push",
  "files": [
    {
      "path": "/root/test/tmp/",
      "logname": "host.log",
      "keywords": ["error", "test"]
    },
    {
      "path": "/root/test/tmp/",
      "logname": "host2.log",
      "keywords": ["error", "test"]
    }

  ]
}
日志如下:

2018-01-31 16:36:36,612-INFO:  [{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=error", "timestamp": 1517387796, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=test", "timestamp": 1517387796, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=error", "timestamp": 1517387796, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=test", "timestamp": 1517387796, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30}]
2018-01-31 16:37:06,672-INFO:  [{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=error", "timestamp": 1517387826, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=test", "timestamp": 1517387826, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=error", "timestamp": 1517387826, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=test", "timestamp": 1517387826, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30}]
2018-01-31 16:37:36,692-INFO:  [{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=error", "timestamp": 1517387856, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=test", "timestamp": 1517387856, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=error", "timestamp": 1517387856, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=test", "timestamp": 1517387856, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30}]
2018-01-31 16:38:06,732-INFO:  [{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=error", "timestamp": 1517387886, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=test", "timestamp": 1517387886, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=error", "timestamp": 1517387886, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=test", "timestamp": 1517387886, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30}]
2018-01-31 16:38:55,310-INFO:  [{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=error", "timestamp": 1517387935, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=test", "timestamp": 1517387935, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=error", "timestamp": 1517387935, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=test", "timestamp": 1517387935, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30}]
2018-01-31 16:39:25,366-INFO:  [{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=error", "timestamp": 1517387965, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host.log,key=test", "timestamp": 1517387965, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=error", "timestamp": 1517387965, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30},{"endpoint": "zww-192.168.138.136", "tags": "log=host2.log,key=test", "timestamp": 1517387965, "metric": "log", "value": 0, "counterType": "GAUGE", "step": 30}]
因为要适配的系统环境比较多,很多python模块没法直接使用,可以看到我这里是直接使用的curl进行的post,实际情况可以根据自己需求进行更改。

插件功能主要就是进行多日志多关键的过滤并按配置时间进行推送数据(如:timer:30,即每30s推送这期间出现的关键字次数)



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值