2929from sys import stderr
3030
3131
32+ __all__ = [
33+ "Watcher" ,
34+ "watch"
35+ ]
36+
37+
3238class ColourFormatter (Formatter ):
3339 """ Colour formatter for pretty log output.
3440 """
@@ -50,49 +56,117 @@ def format(self, record):
5056
5157
5258class Watcher :
53- """ Log watcher for monitoring driver and protocol activity.
59+ """Log watcher for easier logging setup.
60+
61+ Example::
62+
63+ from neo4j.debug import Watcher
64+
65+ with Watcher("neo4j"):
66+ # DEBUG logging to stderr enabled within this context
67+ ... # do something
68+
69+ .. note:: The Watcher class is not thread-safe. Having Watchers in multiple
70+ threads can lead to duplicate log messages as the context manager will
71+ enable logging for all threads.
72+
73+ :param logger_names: Names of loggers to watch.
74+ :type logger_names: str
75+ :param default_level: Default minimum log level to show.
76+ The level can be overridden by setting the level a level when calling
77+ :meth:`.watch`.
78+ :type default_level: int
79+ :param default_out: Default output stream for all loggers.
80+ The level can be overridden by setting the level a level when calling
81+ :meth:`.watch`.
82+ :type default_out: stream or file-like object
83+ :param colour: Whether the log levels should be indicated with ANSI colour
84+ codes.
85+ :type colour: bool
5486 """
5587
56- handlers = {}
57-
58- def __init__ (self , * logger_names ):
88+ def __init__ (self , * logger_names , default_level = DEBUG , default_out = stderr ,
89+ colour = False ):
5990 super (Watcher , self ).__init__ ()
6091 self .logger_names = logger_names
61- self .loggers = [getLogger (name ) for name in self .logger_names ]
62- self .formatter = ColourFormatter ("%(asctime)s %(message)s" )
92+ self ._loggers = [getLogger (name ) for name in self .logger_names ]
93+ self .default_level = default_level
94+ self .default_out = default_out
95+ self ._handlers = {}
96+
97+ format = "%(threadName)s(%(thread)d) %(asctime)s %(message)s"
98+ if not colour :
99+ format = "[%(levelname)s] " + format
100+
101+ formatter_cls = ColourFormatter if colour else Formatter
102+ self .formatter = formatter_cls (format )
63103
64104 def __enter__ (self ):
105+ """Enable logging for all loggers."""
65106 self .watch ()
66107 return self
67108
68109 def __exit__ (self , exc_type , exc_val , exc_tb ):
110+ """Disable logging for all loggers."""
69111 self .stop ()
70112
71- def watch (self , level = DEBUG , out = stderr ):
113+ def watch (self , level = None , out = None ):
114+ """Enable logging for all loggers.
115+
116+ :param level: Minimum log level to show.
117+ If :const:`None`, the ``default_level`` is used.
118+ :type level: int or :const:`None`
119+ :param out: Output stream for all loggers.
120+ If :const:`None`, the ``default_out`` is used.
121+ :type out: stream or file-like object or :const:`None`
122+ """
123+ if level is None :
124+ level = self .default_level
125+ if out is None :
126+ out = self .default_out
72127 self .stop ()
73128 handler = StreamHandler (out )
74129 handler .setFormatter (self .formatter )
75- for logger in self . loggers :
76- self .handlers [logger .name ] = handler
130+ for logger in self . _loggers :
131+ self ._handlers [logger .name ] = handler
77132 logger .addHandler (handler )
78133 logger .setLevel (level )
79134
80135 def stop (self ):
81- try :
82- for logger in self .loggers :
83- logger .removeHandler (self .handlers [logger .name ])
84- except KeyError :
85- pass
136+ """Disable logging for all loggers."""
137+ for logger in self ._loggers :
138+ try :
139+ logger .removeHandler (self ._handlers .pop (logger .name ))
140+ except KeyError :
141+ pass
142+
143+
144+ def watch (* logger_names , level = DEBUG , out = stderr , colour = False ):
145+ """Quick wrapper for using :class:`.Watcher`.
146+
147+ Create a Wathcer with the given configuration, enable watching and return
148+ it.
149+
150+ Example::
151+
152+ from neo4j.debug import watch
86153
154+ watch("neo4j")
155+ # from now on, DEBUG logging to stderr is enabled in the driver
87156
88- def watch (* logger_names , level = DEBUG , out = stderr ):
89- """ Quick wrapper for using the Watcher.
157+ :param logger_names: Names of loggers to watch.
158+ :type logger_names: str
159+ :param level: see ``default_level`` of :class:`.Watcher`.
160+ :type level: int
161+ :param out: see ``default_out`` of :class:`.Watcher`.
162+ :type out: stream or file-like object
163+ :param colour: see ``colour`` of :class:`.Watcher`.
164+ :type colour: bool
90165
91- :param logger_name: name of logger to watch
92- :param level: minimum log level to show (default DEBUG)
93- :param out: where to send output (default stderr)
94166 :return: Watcher instance
167+ :rtype: :class:`.Watcher`
95168 """
96- watcher = Watcher (* logger_names )
97- watcher .watch (level , out )
169+ watcher = Watcher (* logger_names , colour = colour , default_level = level ,
170+ default_out = out )
171+ watcher .watch ()
98172 return watcher
0 commit comments