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