zabbix 自定义监控--监控redis

环境:CentOS6.5
Python:2.7

1、添加redis监控脚本(端口自动发现脚本)
discovery_redis_port.py

#!/usr/bin/env python 
import os
import json 
import commands

[stat, rtv] = commands.getstatusoutput(r''' sudo netstat -tlpn |grep redis-serv|grep 0.0.0.0|awk '{print $4}'|awk -F: '{print $2}' ''')
ports = []
for port in  rtv.split('\n'):
        r = os.path.basename(port.strip())
        ports += [{'{#REDISPORT}':r}]
[stat, rtv] = commands.getstatusoutput(r''' /usr/bin/python discovery_redis_conf.py ''')
print json.dumps({'data':ports},sort_keys=True,indent=4,separators=(',',':'))

ps:由于涉及到有些redis设置有密码而有些没密码,所以这里写了一个自动搜索对应端口的密码的脚本,搜索目录为/usr/local下放置的所有redis目录,本脚本完成redis端口发现和redis端口对应的passwd的查找,代码生成的conf文件可以手工维护,如新增,不会被代码下次执行覆盖,但是如果key值冲突则会被代码以搜索到的内容覆盖。代码如下
discovery_redis_conf.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json 
import commands
import os
import pprint

def Get_File_Path():
    rootdir = "/usr/local"
    file_path_list = []
    for parent,dirnames,filenames in os.walk(rootdir):
        for filename in filenames:
            if filename == "redis.conf":
                file_path = parent + os.sep + filename
                file_path_list.append(file_path)
    return file_path_list

def Get_Dict(file_path):
    result = {}
    with open(file_path) as f:
        all_text = f.read()
        [ result.update({i.split(' ')[0]:i.split(' ')[1]}) for i in all_text.splitlines() if i.strip() and not i.strip().startswith('#') ]
    return result

def Get_Conf_Dict(file_path_list):
    dict = {}
    for file in file_path_list:
        result = Get_Dict(file)
        port = result.get('port', 'None')
        requirepass = result.get('requirepass', '')
        dict[port] = requirepass 
    return dict

def Get_Old_Conf(conf_file_path):
    if os.path.exists(conf_file_path):
        with open('redis_conf.json', 'r') as json_file:   
            dict = json.load(json_file)['data']
    else:
        dict = {} 
    return dict    

if __name__ == '__main__':
    old_conf_path = 'redis_conf.json'
    dict = Get_Old_Conf('redis_conf.json') 
    file_path_list = Get_File_Path()
    dict = Get_Conf_Dict(file_path_list)
    conf_dict = {'data':dict}
    pprint.pprint(conf_dict)
    with open('redis_conf.json', 'w') as json_file:   
        json.dump(conf_dict, json_file, ensure_ascii=False)
    [stat, rtv] = commands.getstatusoutput(r'''sudo chown zabbix:zabbix redis_conf.json ''')

两个脚本放置到同一个目录下,执行第一个脚本:

{
    "data":[
        {
            "{#REDISPORT}":"6379"
        },
        {
            "{#REDISPORT}":"6390"
        },
        {
            "{#REDISPORT}":"6500"
        }
    ]
}

ps:zabbix对自动发现脚本返回的数据类型有要求,必须是这种的json格式的数据
自动发现脚本添加之后就是添加处理方法,为了满足一台主机上安装有多个redis且密码各不相同的情况,不能简单用一句话搞定所有的情况,所以也需要一个脚本来搞定,如下:
redis_t.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json 
import commands
import os
import string
import pprint
from sys import argv

def Get_Mb(str):
    str = str.upper()
    if "MB" in str:
        return int(string.atoi(str[0:-2]))
    elif "M" in str:
        return int(string.atoi(str[0:-1])*1000.0/1024)
    if "GB" in str:
        return int(string.atoi(str[0:-2])*1024)
    elif "G" in str:
        return int(string.atoi(str[0:-1])*1000)
    if "KB" in str:
        return int(string.atoi(str[0:-2])/1024)
    elif "K" in str:
        return int(string.atoi(str[0:-1])*1000.0/1024/1024)
    return int(string.atoi(str)/1024.0/1024)

def Get_Passwd():
    name,port,str = argv
    passwd = ''
    with open("/etc/zabbix/scripts/redis_conf.json", 'r') as load_f:
        load_dict = json.load(load_f)
    for i in load_dict['data'].keys():
        if i == port:
            passwd = load_dict['data'][i]
    if passwd == '':
        passwd = "passwd"
    return passwd

def Get_Info(port, passwd):
    result = {}
    comm = "sudo /usr/local/bin/redis-cli -h 127.0.0.1 -a \"" +  passwd + "\" -p " + port +" info"
    [stat, rtv] = commands.getstatusoutput(comm)
    [ result.update({i.split(':')[0]:i.split(':')[1]}) for i in rtv.splitlines() if i.strip() and not i.strip().startswith('#') ]
    return result
    
def Get_Count_Mem_Fconf():
    result = {}
    path = INFO.get('config_file', 'None')
    with open(path, 'r') as f:
        text = f.read()
    [ result.update({i.split(' ')[0]:i.split(' ')[1]}) for i in text.splitlines() if i.strip() and not i.strip().startswith('#')]
        tmp_cm = result.get('maxmemory', 'None')
    f_cm = Get_Mb(tmp_cm)
    return f_cm

def Get_Count_mem(port, passwd):
    comm = "sudo /usr/local/bin/redis-cli -h 127.0.0.1 -a \"" +  passwd + "\" -p " + port +" config get maxmemory"
    [stat, rtv] = commands.getstatusoutput(comm)
    tmpl = []
    for i in rtv.splitlines():
        tmpl.append(i)
    if tmpl[0] == 'maxmemory': 
        f_cm = Get_Mb(tmpl[1])
    else:
        f_cm = Get_Count_Mem_Fconf()
    return f_cm

if __name__ == '__main__':
    name,port,str = argv
    if str == "proportion" or str == "count_mem":
        passwd = Get_Passwd()
        INFO = Get_Info(port, passwd)
        conf_file = INFO.get('config_file', 'None')
        count_mem = Get_Count_mem(port, passwd)
        if str == "count_mem":
            print count_mem
        else:
            used_mem = string.atoi(INFO.get('used_memory'))/1024.0/1024
            used_mem = int(used_mem)
            mem_proportion = used_mem / float(count_mem)*100
            print mem_proportion
    else:
        passwd = ''
        with open("/etc/zabbix/scripts/redis_conf.json", 'r') as load_f:
            load_dict = json.load(load_f)
        for i in load_dict['data'].keys():
            if i == port:
                passwd = load_dict['data'][i]
        if passwd == '':
            passwd = "passwd"
        comm = "sudo /usr/local/bin/redis-cli -h 127.0.0.1 -a \"" +  passwd + "\" -p " + port +" info|grep " + str + "|cut -d : -f2"
        [stat, rtv] = commands.getstatusoutput(comm)
        print rtv

这里对可分配最大内存有个细节处理,因为redis可以使用命令动态修改内存大小,所以这里是优先选择命令获取redis的实时可分配最大内存,但测试中发现有些客户端连接成功之后执行命令时提示没有config命令,无法完成获取(貌似是redis3以上的都是这样),对于这种情况的redis,取其INFO中获取到的config_file中配置的最大可分配内存大小,如果没有设置,则默认使用128MB大小的内存。
ps:其实如果只是监控redis info中显示的信息,其实只用其中20%的代码就足够,剩下的80%都是为了监控redis可分配的最大内存以及已使用内存所占的百分比
测试我们的自定义脚本

[~~ scripts]# python redis_t.py 6500 memory_rss
8687616
[~~ scripts]# python redis_t.py 6500 count_mem
1024.0

ps:这里的设置的总内存我是把拿到的数据换算成了Mb为单位,而上面的那个数据是B为单位的,因为对于INFO中拿到的数据没做换算处理
到这里我们的自定义方法基本算测试通过了,都可以拿到我们想要的数据,然后就是告诉zabbix来调用我们的监控脚本--添加zabbix键值
键值可以添加在zabbix/zabbix_agentd.conf中,也可以在zabbix目录下新建zabbix_agentd.d和scripts目录来分别存放键值配置和脚本,建议对每个需要新加的键值单独新建一个.conf结尾的文件,如redis.conf等,文件内容如下:

UserParameter=redis.discovery,/etc/zabbix/scripts/discovery_redis_port.py
#这个是自动发现脚本
UserParameter=redis_stats[*], /etc/zabbix/scripts/redis_t.py $1 $2
#这个是监控的具体处理方法

到这里基本就只剩下调试了,先使用zabbix server端进行测试,如果你的zabbix是使用zabbix用户启动运行,不出意外会出现sudo 什么no tty之类的错误(忘记对错误做记录、~~),这个是因为普通用户调用sudo时需要tty窗口输入密码什么,可以设置为不需密码,需要修改/etc/sudoers文件,在文件末尾新增如下内容:

#zabbix ALL=(root) NOPASSWD:/bin/netstat,NOPASSWD: /home/admin/redisCS/redis/src/redis-cli
#上面这种方法是比较安全的做法,只设置监控中需要用到的命令,但是很容易有没发现的命令一直报错、、、
zabbix ALL=(ALL) NOPASSWD: ALL
#这个方法简单省事,相对没那么安全
#Defaults   requiretty  这行要注释掉

还有就是记得所有脚本记得chown到zabbix用户哦
然后重启zabbix-agent

CentOS6:/etc/init.d/zabbix-agent restart
CentOS7:systemctl restart zabbix-agent

登录zabbix server端主机进行测试
测试自动发现端口的脚本

[root@hz-zabbix ~]# zabbix_get -s 192.168.9.142 -k redis.discovery
{
    "data":[
        {
            "{#REDISPORT}":"6379"
        },
        {
            "{#REDISPORT}":"6390"
        },
        {
            "{#REDISPORT}":"6500"
        }
    ]
}

测试获取监控项

[root@hz-zabbix~]# zabbix_get -s 192.168.9.142 -k redis_stats[6500,count_mem]
1024.0

ps:这里如果有看不懂第二个参数的朋友可以仔细看下脚本不难发现这个参数是用来对INFO命令获取的结果进行筛选的,至于获取总内存和百分比的两个参数更是完全可以由我们的代码随便写成什么都可以,比如这里我把可分配总内存写成了count_mem,在代码中做相应的处理即可

对于python和zabbix我都是一个初学者,代码可能只是勉强可以运行,连异常捕获都没做,欢迎大家找茬指正,共勉。

下一篇介绍怎么添加监控模板。——添加监控模板

纯手打,如需转载,请注明出处:http://www.jianshu.com/p/f304cee5ca6e

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 155,348评论 4 355
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 65,906评论 1 283
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,191评论 0 235
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,295评论 0 201
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,606评论 3 283
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,107评论 1 202
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,507评论 2 305
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,217评论 0 193
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,848评论 1 234
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,183评论 2 238
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,734评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,084评论 2 247
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,608评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,921评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,627评论 0 190
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,103评论 2 261
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,054评论 2 257

推荐阅读更多精彩内容

  • Zabbix简介 Zabbix官方网站Zabbix中文文档 本文系统环境是CentOS7x86_64, Zabbi...
    Zhang21阅读 7,842评论 0 37
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,076评论 18 139
  • 使命这个词,二十多年来始终觉得高高在上,与我这个连自己都活不出彩的普通人距离太遥远,至少暂时不敢去想像自己会承担一...
    小鱿鱼123阅读 178评论 0 0
  • 23岁,或许25岁才是个分水岭,我曾简单的以为事情大都会理所应当的发生,我会和前女友理所应当的结婚生子,走完余生,...
    皮卡丘的丘阅读 158评论 0 0
  • 有言:线鸡长膘,绵羊下羔,丝茧成缲。 偶遇,赣南崇义客家山村畜牧站的骆医师就地摆开阉鸡刀、镊子、棕...
    胡记胡说阅读 3,774评论 0 2