ZeroMQ socket monitoring

This allows a user to log connection events from a ZeroMQ socket to better diagnose connectivity issues. Requires ZeroMQ 4.x.

Conflicts:
	salt/minion.py
This commit is contained in:
Mike Place 2015-02-17 15:12:13 -07:00 committed by Justin Findlay
parent 2fee16b26f
commit 9c225cb84d
3 changed files with 49 additions and 0 deletions

View file

@ -516,6 +516,24 @@
#
#log_granular_levels: {}
# To diagnose issues with minions disconnecting or missing returns, ZeroMQ
# supports the use of monitor sockets # to log connection events. This
# feature requires ZeroMQ 4.0 or higher.
#
# To enable ZeroMQ monitor sockets, set 'zmq_monitor' to 'True' and log at a
# debug level or higher.
#
# A sample log event is as follows:
#
# [DEBUG ] ZeroMQ event: {'endpoint': 'tcp://127.0.0.1:4505', 'event': 512,
# 'value': 27, 'description': 'EVENT_DISCONNECTED'}
#
# All events logged will include the string 'ZeroMQ event'. A connection event
# should be logged on the as the minion starts up and initially connects to the
# master. If not, check for debug log level and that the necessary version of
# ZeroMQ is installed.
#
#zmq_monitor: False
###### Module configuration #####
###########################################

View file

@ -427,6 +427,7 @@ DEFAULT_MINION_OPTS = {
'username': None,
'password': None,
'zmq_filtering': False,
'zmq_monitor': False,
'cache_sreqs': True,
'cmd_safe': True,
}

View file

@ -52,6 +52,13 @@ try:
except ImportError:
pass
try:
import zmq.utils.monitor
HAS_ZMQ_MONITOR = True
except ImportError:
HAS_ZMQ_MONITOR = False
# pylint: enable=import-error
# Import salt libs
from salt.exceptions import (
AuthenticationError, CommandExecutionError, CommandNotFoundError,
@ -1391,6 +1398,28 @@ class Minion(MinionBase):
zmq.TCP_KEEPALIVE_INTVL, self.opts['tcp_keepalive_intvl']
)
def _set_monitor_socket(self):
if not HAS_ZMQ_MONITOR or not self.opts['zmq_monitor']:
return
self.monitor_socket = self.socket.get_monitor_socket()
t = threading.Thread(target=self._socket_monitor, args=(self.monitor_socket,))
t.start()
def _socket_monitor(self, monitor):
event_map = {}
for name in dir(zmq):
if name.startswith('EVENT_'):
value = getattr(zmq, name)
event_map[value] = name
while monitor.poll():
evt = zmq.utils.monitor.recv_monitor_message(monitor)
evt.update({'description': event_map[evt['event']]})
log.debug("ZeroMQ event: {0}".format(evt))
if evt['event'] == zmq.EVENT_MONITOR_STOPPED:
break
monitor.close()
log.trace("event monitor thread done!")
def _set_reconnect_ivl(self):
recon_delay = self.opts['recon_default']
@ -1740,6 +1769,7 @@ class Minion(MinionBase):
self._set_reconnect_ivl()
self._setsockopts()
self._set_monitor_socket()
self.socket.connect(self.master_pub)
self.poller.register(self.socket, zmq.POLLIN)