使用zabbix_sender主动发送监控数据到zabbix server
zabbix_sender:
zabbix提供的二进制程序,可以用来发送数据到zabbix server,具体用法如下:
>>> zabbix_sender -z 10.0.0.1 -p 10051 -s "rs_solrmaster" -k "get_number_of_solr_index_update" -o 4 需要注意的是get_number_of_solr_index_update这个key是需要事先创建在rs_solrmaster这台主机上的,并且是zabbix trapper类型的,并且是zabbix trapper类型的,并且是zabbix trapper类型的。 #usage: zabbix_sender [-Vhv] {[-zpsI] -ko | [-zpI] -T -i -r} [-c ] #Options: # -c --config 配置文件的绝对路径 # -z --zabbix-server zabbix server或者zabbix proxy的ip地址 # -p --port zabbix server或者zabbix proxy的端口,默认是10051 # -s --host 主机名,指的是zabbix里配制的主机名 # -I --source-address 源ip,干嘛使得 # -k --key zabbix trapper key名字 # -o --value 需要发送的监控项值 # -i --input-file <input type="text" /> 通过文件的方式批量发送数据,每行一个纪录,格式为hostname,key,value,使用空格分割,如果hostname有空格,使用双引号。 >>> cat trapper_key.txt "zabbix server" key1 10 "zabbix proxy" key2 20 10.0.0.2 key3 30 >>> zabbix_sender -z 10.0.0.1 -i trapper_key.txt
如此,我们便可以随时随地的向zabbix发送监控数据了,由于zabbix只提供了zabbix_sender这个二进制程序来发送数据,如果要 在程序中调用,直接调用一个二进程程序是一种很丑陋的做法,那么有没有更优雅的办法呢(zabbix的api部分并没有trapper key的相关说明)。有,注意前方高能。
zabbix_sender跟zabbix_server的通信方式是tcp协议的,也就是说zabbix_sender发送给一个DATA段为固定格式 的tcp数据包给zabbix_server,然后server端解析并处理请求。所以这个DATA段的数据格式如果能确定,那我们就可以使用程序来模拟 zabbix_sender了。
先来看两篇文章:
zabbix sender协议的研究 | itnihao
zabbix sender 2.0 协议文档
从中可以整理出一个完整的zabbix_sender请求包的格式如下:
源端口 | 目标端口 | ||||||||||||||||||||||||||||||
32位序列号 | |||||||||||||||||||||||||||||||
32位确认号 | |||||||||||||||||||||||||||||||
4位首部长度 | 保留(6位) | URG | ACK | PSH | PST | SYN | FIN | 16位窗口大小 | |||||||||||||||||||||||
16位校验和 | 16位紧急指针 | ||||||||||||||||||||||||||||||
可选项 | |||||||||||||||||||||||||||||||
Z | B | X | D | 协议版本 | 8位数据长度 | 请求或者响应的json数据 |
可以看到基本的zabbix_sender数据协议即为’Z”B”X”D’ + 1位的协议版本号 + 8位的数据长度 + json数据组成,如文档,请求的json数据格式为:
{ "request":"sender data", "data":[ { "host":"Host name 1", "key":"item_key", "value":"33"}, { "host":"Host name 2", "key":"item_key", "value":"55" } ] }
这样,基本的程序逻辑就出来了,即为:
♠ 构建符合zabbix_sender协议的数据包,格式为 ‘4sBqns’ (n为json串的长度)
♠ 发送数据包至zabbix_server的端口
♠ 处理响应
如下为一个python的实现示例:
#!/usr/bin/env python import struct import json import socket class zabbix_sender: def __init__(self,zbx_server_host,zbx_server_port): self.zbx_server_host=zbx_server_host self.zbx_server_port=zbx_server_port self.zbx_header='ZBXD' self.zbx_protocols_version=1 self.zbx_send_value={'request':'sender data','data':[]} def adddata(self,host,key,value): add_data={'host':host,'key':key,'value':value} self.zbx_send_value['data'].append(add_data) #按照协议封装数据包 def makesenddata(self): zbx_send_json=json.dumps(self.zbx_send_value) zbx_send_json_len=len(zbx_send_json) self.zbx_send_data=struct.pack("<4sBq"+str(zbx_send_json_len)+"s",'ZBXD',1,zbx_send_json_len,zbx_send_json) def send(self): self.makesenddata() zbx_server_socket=socket.socket() zbx_server_socket.connect((self.zbx_server_host,self.zbx_server_port)) zbx_server_write_df=zbx_server_socket.makefile('wb') zbx_server_write_df.write(self.zbx_send_data) zbx_server_write_df.close() zbx_server_read_df=zbx_server_socket.makefile('rb') zbx_response_package=zbx_server_read_df.read() zbx_server_read_df.close() #按照协议解数据包 zbx_response_data=struct.unpack("<4sBq"+str(len(zbx_response_package) - struct.calcsize("<4sBq"))+"s",zbx_response_package) return zbx_response_data[3] if __name__ == '__main__': zabbix_sender=zabbix_sender('10.0.0.1',10051) zabbix_sender.adddata('solrmaster','get_number_of_solr_index_update',60) response=zabbix_sender.send() print response