| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- """pyzmq log watcher.
- Easily view log messages published by the PUBHandler in zmq.log.handlers
- Designed to be run as an executable module - try this to see options:
- python -m zmq.log -h
- Subscribes to the '' (empty string) topic by default which means it will work
- out-of-the-box with a PUBHandler object instantiated with default settings.
- If you change the root topic with PUBHandler.setRootTopic() you must pass
- the value to this script with the --topic argument.
- Note that the default formats for the PUBHandler object selectively include
- the log level in the message. This creates redundancy in this script as it
- always prints the topic of the message, which includes the log level.
- Consider overriding the default formats with PUBHandler.setFormat() to
- avoid this issue.
- """
- # encoding: utf-8
- # Copyright (C) PyZMQ Developers
- # Distributed under the terms of the Modified BSD License.
- import argparse
- from datetime import datetime
- from typing import Dict
- import zmq
- parser = argparse.ArgumentParser('ZMQ Log Watcher')
- parser.add_argument('zmq_pub_url', type=str, help='URL to a ZMQ publisher socket.')
- parser.add_argument(
- '-t',
- '--topic',
- type=str,
- default='',
- help='Only receive messages that start with this topic.',
- )
- parser.add_argument(
- '--timestamp', action='store_true', help='Append local time to the log messages.'
- )
- parser.add_argument(
- '--separator',
- type=str,
- default=' | ',
- help='String to print between topic and message.',
- )
- parser.add_argument(
- '--dateformat',
- type=str,
- default='%Y-%d-%m %H:%M',
- help='Set alternative date format for use with --timestamp.',
- )
- parser.add_argument(
- '--align',
- action='store_true',
- default=False,
- help='Try to align messages by the width of their topics.',
- )
- parser.add_argument(
- '--color',
- action='store_true',
- default=False,
- help='Color the output based on the error level. Requires the colorama module.',
- )
- args = parser.parse_args()
- if args.color:
- import colorama
- colorama.init()
- colors = {
- 'DEBUG': colorama.Fore.LIGHTCYAN_EX,
- 'INFO': colorama.Fore.LIGHTWHITE_EX,
- 'WARNING': colorama.Fore.YELLOW,
- 'ERROR': colorama.Fore.LIGHTRED_EX,
- 'CRITICAL': colorama.Fore.LIGHTRED_EX,
- '__RESET__': colorama.Fore.RESET,
- }
- else:
- colors = {}
- ctx = zmq.Context()
- sub = ctx.socket(zmq.SUB)
- sub.subscribe(args.topic.encode("utf8"))
- sub.connect(args.zmq_pub_url)
- topic_widths: Dict[int, int] = {}
- while True:
- try:
- if sub.poll(10, zmq.POLLIN):
- topic, msg = sub.recv_multipart()
- topics = topic.decode('utf8').strip().split('.')
- if args.align:
- topics.extend(' ' for extra in range(len(topics), len(topic_widths)))
- aligned_parts = []
- for key, part in enumerate(topics):
- topic_widths[key] = max(len(part), topic_widths.get(key, 0))
- fmt = ''.join(('{:<', str(topic_widths[key]), '}'))
- aligned_parts.append(fmt.format(part))
- if len(topics) == 1:
- level = topics[0]
- else:
- level = topics[1]
- fields = {
- 'msg': msg.decode('utf8').strip(),
- 'ts': (
- datetime.now().strftime(args.dateformat) + ' '
- if args.timestamp
- else ''
- ),
- 'aligned': (
- '.'.join(aligned_parts)
- if args.align
- else topic.decode('utf8').strip()
- ),
- 'color': colors.get(level, ''),
- 'color_rst': colors.get('__RESET__', ''),
- 'sep': args.separator,
- }
- print('{ts}{color}{aligned}{sep}{msg}{color_rst}'.format(**fields))
- except KeyboardInterrupt:
- break
- sub.disconnect(args.zmq_pub_url)
- if args.color:
- print(colorama.Fore.RESET)
|