29
29
from sys import stderr
30
30
31
31
32
+ __all__ = [
33
+ "Watcher" ,
34
+ "watch"
35
+ ]
36
+
37
+
32
38
class ColourFormatter (Formatter ):
33
39
""" Colour formatter for pretty log output.
34
40
"""
@@ -50,49 +56,117 @@ def format(self, record):
50
56
51
57
52
58
class 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
54
86
"""
55
87
56
- handlers = {}
57
-
58
- def __init__ (self , * logger_names ):
88
+ def __init__ (self , * logger_names , default_level = DEBUG , default_out = stderr ,
89
+ colour = False ):
59
90
super (Watcher , self ).__init__ ()
60
91
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 )
63
103
64
104
def __enter__ (self ):
105
+ """Enable logging for all loggers."""
65
106
self .watch ()
66
107
return self
67
108
68
109
def __exit__ (self , exc_type , exc_val , exc_tb ):
110
+ """Disable logging for all loggers."""
69
111
self .stop ()
70
112
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
72
127
self .stop ()
73
128
handler = StreamHandler (out )
74
129
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
77
132
logger .addHandler (handler )
78
133
logger .setLevel (level )
79
134
80
135
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
86
153
154
+ watch("neo4j")
155
+ # from now on, DEBUG logging to stderr is enabled in the driver
87
156
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
90
165
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)
94
166
:return: Watcher instance
167
+ :rtype: :class:`.Watcher`
95
168
"""
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 ()
98
172
return watcher
0 commit comments