1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.
21
22 Should work under Python versions >= 1.5.2, except that source line
23 information is not available unless 'sys._getframe()' is.
24
25 Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
26
27 To use, simply 'import logging' and log away!
28 """
29
30 import sys, logging, logging.handlers, string, thread, threading, socket, struct, os
31
32 from SocketServer import ThreadingTCPServer, StreamRequestHandler
33
34
35 DEFAULT_LOGGING_CONFIG_PORT = 9030
36
37 if sys.platform == "win32":
38 RESET_ERROR = 10054
39 else:
40 RESET_ERROR = 104
41
42
43
44
45
46
47 _listener = None
48
50 """
51 Read the logging configuration from a ConfigParser-format file.
52
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
63
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
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
88
89 logging._acquireLock()
90 try:
91 try:
92
93 logging._handlers.clear()
94
95 hlist = cp.get("handlers", "keys")
96 if len(hlist):
97 hlist = string.split(hlist, ",")
98 handlers = {}
99 fixups = []
100 for hand in hlist:
101 try:
102 sectname = "handler_%s" % hand
103 klass = cp.get(sectname, "class")
104 opts = cp.options(sectname)
105 if "formatter" in opts:
106 fmt = cp.get(sectname, "formatter")
107 else:
108 fmt = ""
109 klass = eval(klass, vars(logging))
110 args = cp.get(sectname, "args")
111 args = eval(args, vars(logging))
112 h = apply(klass, args)
113 if "level" in opts:
114 level = cp.get(sectname, "level")
115 h.setLevel(logging._levelNames[level])
116 if len(fmt):
117 h.setFormatter(formatters[fmt])
118
119 if klass == logging.handlers.MemoryHandler:
120 if "target" in opts:
121 target = cp.get(sectname,"target")
122 else:
123 target = ""
124 if len(target):
125 fixups.append((h, target))
126 handlers[hand] = h
127 except:
128 pass
129
130 for fixup in fixups:
131 h = fixup[0]
132 t = fixup[1]
133 h.setTarget(handlers[t])
134
135 llist = cp.get("loggers", "keys")
136 llist = string.split(llist, ",")
137 llist.remove("root")
138 sectname = "logger_root"
139 root = logging.root
140 log = root
141 opts = cp.options(sectname)
142 if "level" in opts:
143 level = cp.get(sectname, "level")
144 log.setLevel(logging._levelNames[level])
145 for h in root.handlers[:]:
146 root.removeHandler(h)
147 hlist = cp.get(sectname, "handlers")
148 if len(hlist):
149 hlist = string.split(hlist, ",")
150 for hand in hlist:
151 log.addHandler(handlers[hand])
152
153
154
155
156
157
158
159
160
161 existing = root.manager.loggerDict.keys()
162
163 for log in llist:
164 sectname = "logger_%s" % log
165 qn = cp.get(sectname, "qualname")
166 opts = cp.options(sectname)
167 if "propagate" in opts:
168 propagate = cp.getint(sectname, "propagate")
169 else:
170 propagate = 1
171 logger = logging.getLogger(qn)
172 if qn in existing:
173 existing.remove(qn)
174 if "level" in opts:
175 level = cp.get(sectname, "level")
176 logger.setLevel(logging._levelNames[level])
177 for h in logger.handlers[:]:
178 logger.removeHandler(h)
179 logger.propagate = propagate
180 logger.disabled = 0
181 hlist = cp.get(sectname, "handlers")
182 if len(hlist):
183 hlist = string.split(hlist, ",")
184 for hand in hlist:
185 logger.addHandler(handlers[hand])
186
187
188
189 for log in existing:
190 root.manager.loggerDict[log].disabled = 1
191 except:
192 import traceback
193 ei = sys.exc_info()
194 traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
195 del ei
196 finally:
197 logging._releaseLock()
198
200 """
201 Start up a socket server on the specified port, and listen for new
202 configurations.
203
204 These will be sent as a file suitable for processing by fileConfig().
205 Returns a Thread object on which you can call start() to start the server,
206 and which you can join() when appropriate. To stop the server, call
207 stopListening().
208 """
209 if not thread:
210 raise NotImplementedError, "listen() needs threading to work"
211
212 class ConfigStreamHandler(StreamRequestHandler):
213 """
214 Handler for a logging configuration request.
215
216 It expects a completely new logging configuration and uses fileConfig
217 to install it.
218 """
219 def handle(self):
220 """
221 Handle a request.
222
223 Each request is expected to be a 4-byte length,
224 followed by the config file. Uses fileConfig() to do the
225 grunt work.
226 """
227 import tempfile
228 try:
229 conn = self.connection
230 chunk = conn.recv(4)
231 if len(chunk) == 4:
232 slen = struct.unpack(">L", chunk)[0]
233 chunk = self.connection.recv(slen)
234 while len(chunk) < slen:
235 chunk = chunk + conn.recv(slen - len(chunk))
236
237
238
239
240
241 file = tempfile.mktemp(".ini")
242 f = open(file, "w")
243 f.write(chunk)
244 f.close()
245 fileConfig(file)
246 os.remove(file)
247 except socket.error, e:
248 if type(e.args) != types.TupleType:
249 raise
250 else:
251 errcode = e.args[0]
252 if errcode != RESET_ERROR:
253 raise
254
255 class ConfigSocketReceiver(ThreadingTCPServer):
256 """
257 A simple TCP socket-based logging config receiver.
258 """
259
260 allow_reuse_address = 1
261
262 def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
263 handler=None):
264 ThreadingTCPServer.__init__(self, (host, port), handler)
265 logging._acquireLock()
266 self.abort = 0
267 logging._releaseLock()
268 self.timeout = 1
269
270 def serve_until_stopped(self):
271 import select
272 abort = 0
273 while not abort:
274 rd, wr, ex = select.select([self.socket.fileno()],
275 [], [],
276 self.timeout)
277 if rd:
278 self.handle_request()
279 logging._acquireLock()
280 abort = self.abort
281 logging._releaseLock()
282
283 def serve(rcvr, hdlr, port):
284 server = rcvr(port=port, handler=hdlr)
285 global _listener
286 logging._acquireLock()
287 _listener = server
288 logging._releaseLock()
289 server.serve_until_stopped()
290
291 return threading.Thread(target=serve,
292 args=(ConfigSocketReceiver,
293 ConfigStreamHandler, port))
294
305