debuggers.hg

view tools/python/logging/logging-0.4.9.2/logging/config.py @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children dae98734f12e
line source
1 # Copyright 2001-2004 by Vinay Sajip. All Rights Reserved.
2 #
3 # Permission to use, copy, modify, and distribute this software and its
4 # documentation for any purpose and without fee is hereby granted,
5 # provided that the above copyright notice appear in all copies and that
6 # both that copyright notice and this permission notice appear in
7 # supporting documentation, and that the name of Vinay Sajip
8 # not be used in advertising or publicity pertaining to distribution
9 # of the software without specific, written prior permission.
10 # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12 # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 """
18 Configuration functions for the logging package for Python. The core package
19 is based on PEP 282 and comments thereto in comp.lang.python, and influenced
20 by Apache's log4j system.
22 Should work under Python versions >= 1.5.2, except that source line
23 information is not available unless 'sys._getframe()' is.
25 Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
27 To use, simply 'import logging' and log away!
28 """
30 import sys, logging, logging.handlers, string, thread, threading, socket, struct, os
32 from SocketServer import ThreadingTCPServer, StreamRequestHandler
35 DEFAULT_LOGGING_CONFIG_PORT = 9030
37 if sys.platform == "win32":
38 RESET_ERROR = 10054 #WSAECONNRESET
39 else:
40 RESET_ERROR = 104 #ECONNRESET
42 #
43 # The following code implements a socket listener for on-the-fly
44 # reconfiguration of logging.
45 #
46 # _listener holds the server object doing the listening
47 _listener = None
49 def fileConfig(fname, defaults=None):
50 """
51 Read the logging configuration from a ConfigParser-format file.
53 This can be called several times from an application, allowing an end user
54 the ability to select from various pre-canned configurations (if the
55 developer provides a mechanism to present the choices and load the chosen
56 configuration).
57 In versions of ConfigParser which have the readfp method [typically
58 shipped in 2.x versions of Python], you can pass in a file-like object
59 rather than a filename, in which case the file-like object will be read
60 using readfp.
61 """
62 import ConfigParser
64 cp = ConfigParser.ConfigParser(defaults)
65 if hasattr(cp, 'readfp') and hasattr(fname, 'readline'):
66 cp.readfp(fname)
67 else:
68 cp.read(fname)
69 #first, do the formatters...
70 flist = cp.get("formatters", "keys")
71 if len(flist):
72 flist = string.split(flist, ",")
73 formatters = {}
74 for form in flist:
75 sectname = "formatter_%s" % form
76 opts = cp.options(sectname)
77 if "format" in opts:
78 fs = cp.get(sectname, "format", 1)
79 else:
80 fs = None
81 if "datefmt" in opts:
82 dfs = cp.get(sectname, "datefmt", 1)
83 else:
84 dfs = None
85 f = logging.Formatter(fs, dfs)
86 formatters[form] = f
87 #next, do the handlers...
88 #critical section...
89 logging._acquireLock()
90 try:
91 try:
92 #first, lose the existing handlers...
93 logging._handlers.clear()
94 #now set up the new ones...
95 hlist = cp.get("handlers", "keys")
96 if len(hlist):
97 hlist = string.split(hlist, ",")
98 handlers = {}
99 fixups = [] #for inter-handler references
100 for hand in hlist:
101 sectname = "handler_%s" % hand
102 klass = cp.get(sectname, "class")
103 opts = cp.options(sectname)
104 if "formatter" in opts:
105 fmt = cp.get(sectname, "formatter")
106 else:
107 fmt = ""
108 klass = eval(klass, vars(logging))
109 args = cp.get(sectname, "args")
110 args = eval(args, vars(logging))
111 h = apply(klass, args)
112 if "level" in opts:
113 level = cp.get(sectname, "level")
114 h.setLevel(logging._levelNames[level])
115 if len(fmt):
116 h.setFormatter(formatters[fmt])
117 #temporary hack for FileHandler and MemoryHandler.
118 if klass == logging.handlers.MemoryHandler:
119 if "target" in opts:
120 target = cp.get(sectname,"target")
121 else:
122 target = ""
123 if len(target): #the target handler may not be loaded yet, so keep for later...
124 fixups.append((h, target))
125 handlers[hand] = h
126 #now all handlers are loaded, fixup inter-handler references...
127 for fixup in fixups:
128 h = fixup[0]
129 t = fixup[1]
130 h.setTarget(handlers[t])
131 #at last, the loggers...first the root...
132 llist = cp.get("loggers", "keys")
133 llist = string.split(llist, ",")
134 llist.remove("root")
135 sectname = "logger_root"
136 root = logging.root
137 log = root
138 opts = cp.options(sectname)
139 if "level" in opts:
140 level = cp.get(sectname, "level")
141 log.setLevel(logging._levelNames[level])
142 for h in root.handlers[:]:
143 root.removeHandler(h)
144 hlist = cp.get(sectname, "handlers")
145 if len(hlist):
146 hlist = string.split(hlist, ",")
147 for hand in hlist:
148 log.addHandler(handlers[hand])
149 #and now the others...
150 #we don't want to lose the existing loggers,
151 #since other threads may have pointers to them.
152 #existing is set to contain all existing loggers,
153 #and as we go through the new configuration we
154 #remove any which are configured. At the end,
155 #what's left in existing is the set of loggers
156 #which were in the previous configuration but
157 #which are not in the new configuration.
158 existing = root.manager.loggerDict.keys()
159 #now set up the new ones...
160 for log in llist:
161 sectname = "logger_%s" % log
162 qn = cp.get(sectname, "qualname")
163 opts = cp.options(sectname)
164 if "propagate" in opts:
165 propagate = cp.getint(sectname, "propagate")
166 else:
167 propagate = 1
168 logger = logging.getLogger(qn)
169 if qn in existing:
170 existing.remove(qn)
171 if "level" in opts:
172 level = cp.get(sectname, "level")
173 logger.setLevel(logging._levelNames[level])
174 for h in logger.handlers[:]:
175 logger.removeHandler(h)
176 logger.propagate = propagate
177 logger.disabled = 0
178 hlist = cp.get(sectname, "handlers")
179 if len(hlist):
180 hlist = string.split(hlist, ",")
181 for hand in hlist:
182 logger.addHandler(handlers[hand])
183 #Disable any old loggers. There's no point deleting
184 #them as other threads may continue to hold references
185 #and by disabling them, you stop them doing any logging.
186 for log in existing:
187 root.manager.loggerDict[log].disabled = 1
188 except:
189 import traceback
190 ei = sys.exc_info()
191 traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
192 del ei
193 finally:
194 logging._releaseLock()
196 def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
197 """
198 Start up a socket server on the specified port, and listen for new
199 configurations.
201 These will be sent as a file suitable for processing by fileConfig().
202 Returns a Thread object on which you can call start() to start the server,
203 and which you can join() when appropriate. To stop the server, call
204 stopListening().
205 """
206 if not thread:
207 raise NotImplementedError, "listen() needs threading to work"
209 class ConfigStreamHandler(StreamRequestHandler):
210 """
211 Handler for a logging configuration request.
213 It expects a completely new logging configuration and uses fileConfig
214 to install it.
215 """
216 def handle(self):
217 """
218 Handle a request.
220 Each request is expected to be a 4-byte length,
221 followed by the config file. Uses fileConfig() to do the
222 grunt work.
223 """
224 import tempfile
225 try:
226 conn = self.connection
227 chunk = conn.recv(4)
228 if len(chunk) == 4:
229 slen = struct.unpack(">L", chunk)[0]
230 chunk = self.connection.recv(slen)
231 while len(chunk) < slen:
232 chunk = chunk + conn.recv(slen - len(chunk))
233 #Apply new configuration. We'd like to be able to
234 #create a StringIO and pass that in, but unfortunately
235 #1.5.2 ConfigParser does not support reading file
236 #objects, only actual files. So we create a temporary
237 #file and remove it later.
238 file = tempfile.mktemp(".ini")
239 f = open(file, "w")
240 f.write(chunk)
241 f.close()
242 fileConfig(file)
243 os.remove(file)
244 except socket.error, e:
245 if type(e.args) != types.TupleType:
246 raise
247 else:
248 errcode = e.args[0]
249 if errcode != RESET_ERROR:
250 raise
252 class ConfigSocketReceiver(ThreadingTCPServer):
253 """
254 A simple TCP socket-based logging config receiver.
255 """
257 allow_reuse_address = 1
259 def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
260 handler=None):
261 ThreadingTCPServer.__init__(self, (host, port), handler)
262 logging._acquireLock()
263 self.abort = 0
264 logging._releaseLock()
265 self.timeout = 1
267 def serve_until_stopped(self):
268 import select
269 abort = 0
270 while not abort:
271 rd, wr, ex = select.select([self.socket.fileno()],
272 [], [],
273 self.timeout)
274 if rd:
275 self.handle_request()
276 logging._acquireLock()
277 abort = self.abort
278 logging._releaseLock()
280 def serve(rcvr, hdlr, port):
281 server = rcvr(port=port, handler=hdlr)
282 global _listener
283 logging._acquireLock()
284 _listener = server
285 logging._releaseLock()
286 server.serve_until_stopped()
288 return threading.Thread(target=serve,
289 args=(ConfigSocketReceiver,
290 ConfigStreamHandler, port))
292 def stopListening():
293 """
294 Stop the listening server which was created with a call to listen().
295 """
296 global _listener
297 if _listener:
298 logging._acquireLock()
299 _listener.abort = 1
300 _listener = None
301 logging._releaseLock()