1、rabbitmq添加监控专用账号

rabbitmqctl add_user zabbix zabbixpass
rabbitmqctl set_user_tags zabbix monitoring

#对何种资源具有配置、写、读的权限set_permissions [-p <vhostpath>] <user> <conf> <write> <read>,如'^(amq\.gen.*|amq\.default)$'可以匹配server生成的和默认的exchange,'^$'不匹配任何资源,下面可以根据实际情况调整权限
rabbitmqctl set_permissions -p / zabbix ".*" ".*" ".*"
rabbitmqctl list_user_permissions zabbix
Listing permissions for user "zabbix"
/	.*	.*	.*

2、把scripts文件放在目录/etc/zabbix/scripts/rabbitmq

参考下载地址:https://github.com/jasonmcintosh/rabbitmq-zabbix

[root@centos74 ~]$ cat /etc/zabbix/zabbix_agentd.d/userparameter_rabbitmq.conf 
UserParameter=rabbitmq.discovery_queue,/etc/zabbix/script/rabbitmq/list_rabbit_queues.sh
UserParameter=rabbitmq.discovery_shovels,/etc/zabbix/script/rabbitmq/list_rabbit_shovels.sh
UserParameter=rabbitmq.discovery_nodes,/etc/zabbix/script/rabbitmq/list_rabbit_nodes.sh
UserParameter=rabbitmq[*],/etc/zabbix/script/rabbitmq/rabbitmq-status.sh $1 $2 $3

[root@centos74 ~]$ cd /etc/zabbix/script/rabbitmq/
[root@centos74 rabbitmq]# pwd
/etc/zabbix/scripts/rabbitmq
[root@centos74 rabbitmq]# chown zabbix:zabbix ./*
[root@centos74 rabbitmq]# chmod 755 ./*
[root@centos74 rabbitmq]# ll -a
total 44
drwxr-xr-x 2 root   root    4096 Dec  7 17:19 .
drwxr-xr-x 3 root   root    4096 Dec  7 17:18 ..
-rwxr-xr-x 1 zabbix zabbix 12428 Dec  7 16:31 api.py
-rwxr-xr-x 1 zabbix zabbix   390 Oct 26  2016 list_rabbit_nodes.sh
-rwxr-xr-x 1 zabbix zabbix   392 Oct 26  2016 list_rabbit_shovels.sh
-rwxr-xr-x 1 zabbix zabbix   392 Oct 26  2016 list_rabbit_queues.sh
-rwxr-xr-x 1 zabbix zabbix   136 Dec  7 16:22 .rab.auth
-rwxr-xr-x 1 zabbix zabbix   748 Oct 26  2016 rabbitmq-status.sh

[root@centos74 rabbitmq]# cat .rab.auth 
USERNAME=zabbix
PASSWORD=zabbixpass
CONF=/etc/zabbix/zabbix_agent.conf
LOGLEVEL=INFO
LOGFILE=/var/log/zabbix/rabbitmq_zabbix.log
PORT=15672
#.rab.auth 配置文件参数说明
USERNAME:rabbitmq管理界面登录用户名
PASSWORD:rabbitmq管理界面登录密码
CONF:指定 zabbix_agentd 配置文件路径
LOGLEVEL:指定日志级别,如果监控调试OK,可将此值改为INFO
LOGFILE:指定日志文件路径
PORT:指定rabbitmq管理访问端口

[root@centos74 rabbitmq]# chown zabbix:zabbix /var/log/zabbix/rabbitmq_zabbix.log
[root@centos74 rabbitmq]# chmod 755 /var/log/zabbix/rabbitmq_zabbix.log

[root@centos74 rabbitmq]# cat list_rabbit_nodes.sh
#!/bin/bash
#
# https://github.com/jasonmcintosh/rabbitmq-zabbix
#
cd "$(dirname "$0")"
. .rab.auth

if [[ -z "$HOSTNAME" ]]; then
    HOSTNAME=`hostname`
fi
if [[ -z "$NODE" ]]; then
    NODE=`hostname`
fi

./api.py --username=$USERNAME --password=$PASSWORD --check=list_nodes --filter="$FILTER" --conf=$CONF --hostname=$HOSTNAME --node="$NODE" --loglevel=${LOGLEVEL} --logfile=${LOGFILE}

[root@centos74 rabbitmq]# cat list_rabbit_shovels.sh
#!/bin/bash
#
# https://github.com/jasonmcintosh/rabbitmq-zabbix
#
cd "$(dirname "$0")"
. .rab.auth

if [[ -z "$HOSTNAME" ]]; then
    HOSTNAME=`hostname`
fi
if [[ -z "$NODE" ]]; then
    NODE=`hostname`
fi

./api.py --username=$USERNAME --password=$PASSWORD --check=list_shovels --filter="$FILTER"  --hostname=$HOSTNAME --node="$NODE"  --conf=$CONF  --loglevel=${LOGLEVEL} --logfile=${LOGFILE}


[root@centos74 rabbitmq]# cat  list_rabbit_queues.sh
#!/bin/bash
#
# https://github.com/jasonmcintosh/rabbitmq-zabbix
#
cd "$(dirname "$0")"
. .rab.auth

if [[ -z "$HOSTNAME" ]]; then
    HOSTNAME=`hostname`
fi
if [[ -z "$NODE" ]]; then
    NODE=`hostname`
fi

./api.py --username=$USERNAME --password=$PASSWORD --check=list_queues --filter="$FILTER" --conf=$CONF --hostname=$HOSTNAME --node="$NODE"  --loglevel=${LOGLEVEL} --logfile=${LOGFILE}

[root@centos74 rabbitmq]# cat rabbitmq_status.sh
#!/bin/bash
#
# https://github.com/jasonmcintosh/rabbitmq-zabbix
#
cd "$(dirname "$0")"
. .rab.auth

if [[ -z "$HOSTNAME" ]]; then
    HOSTNAME=`hostname`
fi
if [[ -z "$NODE" ]]; then
    NODE=`hostname`
fi

./api.py --username=$USERNAME --password=$PASSWORD --check=list_shovels --filter="$FILTER"  --hostname=$HOSTNAME --node="$NODE"  --conf=$CONF  --loglevel=${LOGLEVEL} --logfile=${LOGFILE}

[root@centos74 rabbitmq]# cat api.py
#!/usr/bin/env /usr/bin/python
'''Python module to query the RabbitMQ Management Plugin REST API and get
results that can then be used by Zabbix.
https://github.com/jasonmcintosh/rabbitmq-zabbix
'''
import json
import optparse
import socket
import urllib2
import subprocess
import tempfile
import os
import logging


class RabbitMQAPI(object):
    '''Class for RabbitMQ Management API'''

    def __init__(self, user_name='guest', password='guest', host_name='',
                 port=15672, conf='/etc/zabbix/zabbix_agentd.conf', senderhostname=None):
        self.user_name = user_name
        self.password = password
        self.host_name = host_name or socket.gethostname()
        self.port = port
        self.conf = conf or '/etc/zabbix/zabbix_agentd.conf'
        self.senderhostname = senderhostname

    def call_api(self, path):
        '''Call the REST API and convert the results into JSON.'''
        url = 'http://{0}:{1}/api/{2}'.format(self.host_name, self.port, path)
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
        password_mgr.add_password(None, url, self.user_name, self.password)
        handler = urllib2.HTTPBasicAuthHandler(password_mgr)
        logging.debug('Issue a rabbit API call to get data on ' + path + " against " + self.host_name)
        return json.loads(urllib2.build_opener(handler).open(url).read())

    def list_queues(self, filters=None):
        '''
        List all of the RabbitMQ queues, filtered against the filters provided
        in .rab.auth. See README.md for more information.
        '''
        queues = []
        if not filters:
            filters = [{}]
        for queue in self.call_api('queues'):
            logging.debug("Discovered queue " + queue['name'] + ", checking to see if it's filtered...")
            for _filter in filters:
                check = [(x, y) for x, y in queue.items() if x in _filter]
                shared_items = set(_filter.items()).intersection(check)
                if len(shared_items) == len(_filter):
                    element = {'{#VHOSTNAME}': queue['vhost'],
                               '{#QUEUENAME}': queue['name']}
                    queues.append(element)
                    logging.debug('Discovered queue '+queue['vhost']+'/'+queue['name'])
                    break
        return queues

    def list_shovels(self, filters=None):
        '''
        List all of the RabbitMQ shovels, filtered against the filters provided
        in .rab.auth. See README.md for more information.
        '''
        shovels = []
        if not filters:
            filters = [{}]
        try:
            for shovel in self.call_api('shovels'):
                logging.debug("Discovered shovel " + shovel['name'] + ", checking to see if it's filtered...")
                for _filter in filters:
                    check = [(x, y) for x, y in shovel.items() if x in _filter]
                    shared_items = set(_filter.items()).intersection(check)
                    if len(shared_items) == len(_filter):
                        element = {'{#VHOSTNAME}': shovel['vhost'],
                                   '{#SHOVELNAME}': shovel['name']}
                        shovels.append(element)
                        logging.debug('Discovered shovel '+shovel['vhost']+'/'+shovel['name'])
                        break
            return shovels
        except urllib2.HTTPError as err:
            if err.code == 404:
                return shovels
            else:
                raise err

    def list_nodes(self):
        '''Lists all rabbitMQ nodes in the cluster'''
        nodes = []
        for node in self.call_api('nodes'):
            # We need to return the node name, because Zabbix
            # does not support @ as an item parameter
            name = node['name'].split('@')[1]
            element = {'{#NODENAME}': name,
                       '{#NODETYPE}': node['type']}
            nodes.append(element)
            logging.debug('Discovered nodes '+name+'/'+node['type'])
        return nodes

    def check_queue(self, filters=None):
        '''Return the value for a specific item in a queue's details.'''
        return_code = 0
        if not filters:
            filters = [{}]

        rdatafile = tempfile.NamedTemporaryFile(delete=False)

        for queue in self.call_api('queues'):
            success = False
            logging.debug("Filtering out by " + str(filters))
            for _filter in filters:
                check = [(x, y) for x, y in queue.items() if x in _filter]
                shared_items = set(_filter.items()).intersection(check)
                if len(shared_items) == len(_filter):
                    success = True
                    break
            if success:
                self._prepare_data(queue, rdatafile)

        rdatafile.close()
        return_code = self._send_data(rdatafile)
        os.unlink(rdatafile.name)
        return return_code

    def check_shovel(self, filters=None):
        '''Return the value for a specific item in a shovel's details.'''
        return_code = 0
        if not filters:
            filters = [{}]

        rdatafile = tempfile.NamedTemporaryFile(delete=False)

        for shovel in self.call_api('shovels'):
            success = False
            logging.debug("Filtering out by " + str(filters))
            for _filter in filters:
                check = [(x, y) for x, y in shovel.items() if x in _filter]
                shared_items = set(_filter.items()).intersection(check)
                if len(shared_items) == len(_filter):
                    success = True
                    break
            if success:
                key = '"rabbitmq.shovels[{0},shovel_{1},{2}]"'
                key = key.format(shovel['vhost'], 'state', shovel['name'])
                value = shovel.get('state', 0)
                logging.debug("SENDER_DATA: - %s %s" % (key,value))
                rdatafile.write("- %s %s\n" % (key, value))


        rdatafile.close()
        return_code = self._send_data(rdatafile)
        os.unlink(rdatafile.name)
        return return_code

    def _prepare_data(self, queue, tmpfile):
        '''Prepare the queue data for sending'''
        for item in ['memory', 'messages', 'messages_unacknowledged',
                     'consumers']:
            key = '"rabbitmq.queues[{0},queue_{1},{2}]"'
            key = key.format(queue['vhost'], item, queue['name'])
            value = queue.get(item, 0)
            logging.debug("SENDER_DATA: - %s %s" % (key,value))
            tmpfile.write("- %s %s\n" % (key, value))
        ##  This is a non standard bit of information added after the standard items
        for item in ['deliver_get', 'publish']:
            key = '"rabbitmq.queues[{0},queue_message_stats_{1},{2}]"'
            key = key.format(queue['vhost'], item, queue['name'])
            value = queue.get('message_stats', {}).get(item, 0)
            logging.debug("SENDER_DATA: - %s %s" % (key,value))
            tmpfile.write("- %s %s\n" % (key, value))
			

    def _send_data(self, tmpfile):
        '''Send the queue data to Zabbix.'''
        args = 'zabbix_sender -vv -c {0} -i {1}'
        if self.senderhostname:
            args = args + " -s " + self.senderhostname
        return_code = 0
        process = subprocess.Popen(args.format(self.conf, tmpfile.name),
                                           shell=True, stdout=subprocess.PIPE,
                                           stderr=subprocess.PIPE)
        out, err = process.communicate()
        logging.debug("Finished sending data")
        return_code = process.wait()
        logging.info("Found return code of " + str(return_code))
        if return_code == 1:
            logging.error(out)
            logging.error(err)
        else:
            logging.debug(err)
            logging.debug(out)
        return return_code

    def check_aliveness(self):
        '''Check the aliveness status of a given vhost.'''
        return self.call_api('aliveness-test/%2f')['status']

    def check_server(self, item, node_name):
        '''First, check the overview specific items'''
        if item == 'message_stats_deliver_get':
          return self.call_api('overview').get('message_stats', {}).get('deliver_get_details', {}).get('rate',0)
        elif item == 'message_stats_publish':
          return self.call_api('overview').get('message_stats', {}).get('publish_details', {}).get('rate',0)
        elif item == 'rabbitmq_version':
          return self.call_api('overview').get('rabbitmq_version', 'None')
        '''Return the value for a specific item in a node's details.'''
        node_name = node_name.split('.')[0]
        nodeInfo = self.call_api('nodes')
        for nodeData in nodeInfo:
            logging.debug("Checking to see if node name {0} is in {1} for item {2} found {3} nodes".format(node_name, nodeData['name'], item, len(nodeInfo)))
            if node_name in nodeData['name'] or len(nodeInfo) == 1:
                logging.debug("Got data from node {0} of {1} ".format(node_name, nodeData.get(item)))
                return nodeData.get(item)
        return 'Not Found'


def main():
    '''Command-line parameters and decoding for Zabbix use/consumption.'''
    choices = ['list_queues', 'list_shovels', 'list_nodes', 'queues', 'shovels', 'check_aliveness',
               'server']
    parser = optparse.OptionParser()
    parser.add_option('--username', help='RabbitMQ API username',
                      default='guest')
    parser.add_option('--password', help='RabbitMQ API password',
                      default='guest')
    parser.add_option('--hostname', help='RabbitMQ API host',
                      default=socket.gethostname())
    parser.add_option('--port', help='RabbitMQ API port', type='int',
                      default=15672)
    parser.add_option('--check', type='choice', choices=choices,
                      help='Type of check')
    parser.add_option('--metric', help='Which metric to evaluate', default='')
    parser.add_option('--filters', help='Filter used queues (see README)')
    parser.add_option('--node', help='Which node to check (valid for --check=server)')
    parser.add_option('--conf', default='/etc/zabbix/zabbix_agentd.conf')
    parser.add_option('--senderhostname', default='', help='Allows including a sender parameter on calls to zabbix_sender')
    parser.add_option('--logfile', help='File to log errors (defaults to /var/log/zabbix/rabbitmq_zabbix.log)', default='/var/log/zabbix/rabbitmq_zabbix.log')
    parser.add_option('--loglevel', help='Defaults to INFO', default='INFO')
    (options, args) = parser.parse_args()
    if not options.check:
        parser.error('At least one check should be specified')
    logging.basicConfig(filename=options.logfile or "/var/log/zabbix/rabbitmq_zabbix.log", level=logging.getLevelName(options.loglevel or "INFO"), format='%(asctime)s %(levelname)s: %(message)s')

    logging.debug("Started trying to process data")
    api = RabbitMQAPI(user_name=options.username, password=options.password,
                      host_name=options.hostname, port=options.port,
                      conf=options.conf, senderhostname=options.senderhostname)
    if options.filters:
        try:
            filters = json.loads(options.filters)
        except KeyError:
            parser.error('Invalid filters object.')
    else:
        filters = [{}]
    if not isinstance(filters, (list, tuple)):
        filters = [filters]
    if options.check == 'list_queues':
        print json.dumps({'data': api.list_queues(filters)})
    elif options.check == 'list_nodes':
        print json.dumps({'data': api.list_nodes()})
    elif options.check == 'list_shovels':
        print json.dumps({'data': api.list_shovels()})
    elif options.check == 'queues':
        print api.check_queue(filters)
    elif options.check == 'shovels':
        print api.check_shovel(filters)
    elif options.check == 'check_aliveness':
        print api.check_aliveness()
    elif options.check == 'server':
        if not options.metric:
            parser.error('Missing required parameter: "metric"')
        else:
            if options.node:
                print api.check_server(options.metric, options.node)
            else:
                print api.check_server(options.metric, api.host_name)

if __name__ == '__main__':
    main()

3、测试脚本能否正常取值

[root@centos74 rabbitmq]# ./list_rabbit_nodes.sh 
{"data": [{"{#NODETYPE}": "disc", "{#NODENAME}": "centos74"}]}
[root@centos74 rabbitmq]# ./list_rabbit_queues.sh 
{"data": [{"{#VHOSTNAME}": "/", "{#QUEUENAME}": "aliveness-test"}]}
[root@centos74 rabbitmq]# ./rabbitmq-status.sh list_queues
{"data": [{"{#VHOSTNAME}": "/", "{#QUEUENAME}": "aliveness-test"}]}
[root@centos74 rabbitmq]# ./rabbitmq-status.sh list_nodes
{"data": [{"{#NODETYPE}": "disc", "{#NODENAME}": "centos74"}]}

4、在zabbix-proxy或者zabbix-server节点测试取值是否正常

[root@centos rabbitmq]#  zabbix_get -s 192.168.110.9 -p 10050 -k rabbitmq[check_aliveness]
ok
[root@centos rabbitmq]#  zabbix_get -s 192.168.110.9 -p 10050 -k rabbitmq[server,disk_free]
536561291264
[root@centos rabbitmq]# zabbix_get -s 192.168.110.9 -p 10050 -k rabbitmq[queues]
127
[root@centos rabbitmq]# zabbix_get -s 192.168.110.9 -p 10050 -k rabbitmq[list_nodes]
{"data": [{"{#NODETYPE}": "disc", "{#NODENAME}": "centos74"}, {"{#NODETYPE}": "ram", "{#NODENAME}": "centos75"}]}

[root@centos rabbitmq]#  zabbix_get -s 192.168.110.9 -p 10050 -k rabbitmq.discovery_nodes
{"data": [{"{#NODETYPE}": "disc", "{#NODENAME}": "centos74"}, {"{#NODETYPE}": "ram", "{#NODENAME}": "centos75"}]}

#键值参数说明
rabbitmq[list_queues],rabbitmq.discovery_queue  #列出所有RabbitMQ队列
rabbitmq[list_nodes] ,rabbitmq.discovery_nodes  #列出集群中的所有rabbitMQ节点,相当于rabbitmqctl cluster_status
rabbitmq[queues]  #返回队列详细信息中特定项的值。
rabbitmq[check_aliveness] #状态监测正常ok,检查给定主机的活动状态。
rabbitmq[server,disk_free] #磁盘剩余空间,以字节表示
rabbitmq[server,mem_used]  #内存使用字节

#[server,*]后面第二个参数说明
disk_free   磁盘剩余空间,以字节表示
disk_free_limit    磁盘报警的阀值
fd_used    使用掉的文件描述符数量
fd_total   可用的文件描述符数量
io_read_avg_time      读操作平均时间,毫秒为单位
io_read_bytes        总共读入磁盘数据大小,以字节为单位
io_read_count        总共读操作的数量
io_seek_avg_time      seek操作的平均时间,毫秒单位
io_seek_count        seek操作总量
io_sync_avg_time      fsync操作的平均时间,毫秒为单位
io_sync_count        fsync操作的总量
io_write_avg_time      每个磁盘写操作的平均时间,毫秒为单位
io_write_bytes       写入磁盘数据总量,以字节为单位
io_write_count       磁盘写操作总量
mem_used           内存使用字节
mem_limit          内存报警阀值,默认是总的物理内存的40%
mnesia_disk_tx_count   需要写入到磁盘的Mnesia事务的数量
mnesia_ram_tx_count    不需要写入到磁盘的Mnesia事务的数量
msg_store_write_count  写入到消息存储的消息数量
msg_store_read_count   从消息存储读入的消息数量
proc_used         Erlang进程的使用数量
proc_total        Erlang进程的最大数量
queue_index_journal_write_count    写入到队列索引日志的记录数量。每条记录表示一个被发布到队列,从消息队列中被投递出或者在消息队列中被确认的消息
queue_index_read_count     从队列索引读出的记录数量
queue_index_write_count    写入到队列索引的记录数量
sockets_used        以socket方式使用掉的文件描述符数量
partitions         
uptime           自从Erlang VM启动时,运行的时间,单位好毫秒
run_queue         等待运行的Erlang进程数量
processors        检测到被Erlang进程使用到的内核数量
net_ticktime       当前设置的内核tick time

5、然后在zabbix server管理页面配置对应监控项和触发器

以下面几个键值为例,添加监控
rabbitmq[list_nodes] 
rabbitmq[queues]
rabbitmq[check_aliveness]
rabbitmq[server,disk_free]

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐