PageRenderTime 69ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/IPython/parallel/apps/logwatcher.py

https://github.com/cboos/ipython
Python | 114 lines | 78 code | 10 blank | 26 comment | 0 complexity | 2e113b7167c7d35fff4a39aa19610060 MD5 | raw file
  1. """
  2. A simple logger object that consolidates messages incoming from ipcluster processes.
  3. Authors:
  4. * MinRK
  5. """
  6. #-----------------------------------------------------------------------------
  7. # Copyright (C) 2011 The IPython Development Team
  8. #
  9. # Distributed under the terms of the BSD License. The full license is in
  10. # the file COPYING, distributed as part of this software.
  11. #-----------------------------------------------------------------------------
  12. #-----------------------------------------------------------------------------
  13. # Imports
  14. #-----------------------------------------------------------------------------
  15. import logging
  16. import sys
  17. import zmq
  18. from zmq.eventloop import ioloop, zmqstream
  19. from IPython.config.configurable import LoggingConfigurable
  20. from IPython.utils.traitlets import Int, Unicode, Instance, List
  21. #-----------------------------------------------------------------------------
  22. # Classes
  23. #-----------------------------------------------------------------------------
  24. class LogWatcher(LoggingConfigurable):
  25. """A simple class that receives messages on a SUB socket, as published
  26. by subclasses of `zmq.log.handlers.PUBHandler`, and logs them itself.
  27. This can subscribe to multiple topics, but defaults to all topics.
  28. """
  29. # configurables
  30. topics = List([''], config=True,
  31. help="The ZMQ topics to subscribe to. Default is to subscribe to all messages")
  32. url = Unicode('tcp://127.0.0.1:20202', config=True,
  33. help="ZMQ url on which to listen for log messages")
  34. # internals
  35. stream = Instance('zmq.eventloop.zmqstream.ZMQStream')
  36. context = Instance(zmq.Context)
  37. def _context_default(self):
  38. return zmq.Context.instance()
  39. loop = Instance(zmq.eventloop.ioloop.IOLoop)
  40. def _loop_default(self):
  41. return ioloop.IOLoop.instance()
  42. def __init__(self, **kwargs):
  43. super(LogWatcher, self).__init__(**kwargs)
  44. s = self.context.socket(zmq.SUB)
  45. s.bind(self.url)
  46. self.stream = zmqstream.ZMQStream(s, self.loop)
  47. self.subscribe()
  48. self.on_trait_change(self.subscribe, 'topics')
  49. def start(self):
  50. self.stream.on_recv(self.log_message)
  51. def stop(self):
  52. self.stream.stop_on_recv()
  53. def subscribe(self):
  54. """Update our SUB socket's subscriptions."""
  55. self.stream.setsockopt(zmq.UNSUBSCRIBE, '')
  56. if '' in self.topics:
  57. self.log.debug("Subscribing to: everything")
  58. self.stream.setsockopt(zmq.SUBSCRIBE, '')
  59. else:
  60. for topic in self.topics:
  61. self.log.debug("Subscribing to: %r"%(topic))
  62. self.stream.setsockopt(zmq.SUBSCRIBE, topic)
  63. def _extract_level(self, topic_str):
  64. """Turn 'engine.0.INFO.extra' into (logging.INFO, 'engine.0.extra')"""
  65. topics = topic_str.split('.')
  66. for idx,t in enumerate(topics):
  67. level = getattr(logging, t, None)
  68. if level is not None:
  69. break
  70. if level is None:
  71. level = logging.INFO
  72. else:
  73. topics.pop(idx)
  74. return level, '.'.join(topics)
  75. def log_message(self, raw):
  76. """receive and parse a message, then log it."""
  77. if len(raw) != 2 or '.' not in raw[0]:
  78. self.log.error("Invalid log message: %s"%raw)
  79. return
  80. else:
  81. topic, msg = raw
  82. # don't newline, since log messages always newline:
  83. topic,level_name = topic.rsplit('.',1)
  84. level,topic = self._extract_level(topic)
  85. if msg[-1] == '\n':
  86. msg = msg[:-1]
  87. self.log.log(level, "[%s] %s" % (topic, msg))