Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/branches/598-sendall/cherrypy/_cplogging.py

Revision 1873 (checked in by fumanchu, 11 months ago)

Silencing the no-handlers "warning" (stderr write!) in stdlib logging.

  • Property svn:eol-style set to native
Line 
1 """CherryPy logging."""
2
3 import datetime
4 import logging
5 # Silence the no-handlers "warning" (stderr write!) in stdlib logging
6 logging.Logger.manager.emittedNoHandlerWarning = 1
7 logfmt = logging.Formatter("%(message)s")
8 import os
9 import rfc822
10 import sys
11
12 import cherrypy
13 from cherrypy import _cperror
14
15
16 class LogManager(object):
17    
18     appid = None
19     error_log = None
20     access_log = None
21    
22     def __init__(self, appid=None, logger_root="cherrypy"):
23         self.logger_root = logger_root
24         self.appid = appid
25         if appid is None:
26             self.error_log = logging.getLogger("%s.error" % logger_root)
27             self.access_log = logging.getLogger("%s.access" % logger_root)
28         else:
29             self.error_log = logging.getLogger("%s.error.%s" % (logger_root, appid))
30             self.access_log = logging.getLogger("%s.access.%s" % (logger_root, appid))
31         self.error_log.setLevel(logging.DEBUG)
32         self.access_log.setLevel(logging.INFO)
33         cherrypy.engine.subscribe('graceful', self.reopen_files)
34    
35     def reopen_files(self):
36         """Close and reopen all file handlers."""
37         for log in (self.error_log, self.access_log):
38             for h in log.handlers:
39                 if isinstance(h, logging.FileHandler):
40                     h.acquire()
41                     h.stream.close()
42                     h.stream = open(h.baseFilename, h.mode)
43                     h.release()
44    
45     def error(self, msg='', context='', severity=logging.DEBUG, traceback=False):
46         """Write to the error log.
47         
48         This is not just for errors! Applications may call this at any time
49         to log application-specific information.
50         """
51         if traceback:
52             msg += _cperror.format_exc()
53         self.error_log.log(severity, ' '.join((self.time(), context, msg)))
54    
55     def __call__(self, *args, **kwargs):
56         """Write to the error log.
57         
58         This is not just for errors! Applications may call this at any time
59         to log application-specific information.
60         """
61         return self.error(*args, **kwargs)
62    
63     def access(self):
64         """Write to the access log."""
65         request = cherrypy.request
66         inheaders = request.headers
67         remote = request.remote
68         response = cherrypy.response
69         outheaders = response.headers
70         tmpl = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
71         s = tmpl % {'h': remote.name or remote.ip,
72                     'l': '-',
73                     'u': getattr(request, "login", None) or "-",
74                     't': self.time(),
75                     'r': request.request_line,
76                     's': response.status.split(" ", 1)[0],
77                     'b': outheaders.get('Content-Length', '') or "-",
78                     'f': inheaders.get('Referer', ''),
79                     'a': inheaders.get('User-Agent', ''),
80                     }
81         try:
82             self.access_log.log(logging.INFO, s)
83         except:
84             self(traceback=True)
85    
86     def time(self):
87         """Return now() in Apache Common Log Format (no timezone)."""
88         now = datetime.datetime.now()
89         month = rfc822._monthnames[now.month - 1].capitalize()
90         return ('[%02d/%s/%04d:%02d:%02d:%02d]' %
91                 (now.day, month, now.year, now.hour, now.minute, now.second))
92    
93     def _get_builtin_handler(self, log, key):
94         for h in log.handlers:
95             if getattr(h, "_cpbuiltin", None) == key:
96                 return h
97    
98    
99     # ------------------------- Screen handlers ------------------------- #
100    
101     def _set_screen_handler(self, log, enable, stream=None):
102         h = self._get_builtin_handler(log, "screen")
103         if enable:
104             if not h:
105                 if stream is None:
106                     stream=sys.stdout
107                 h = logging.StreamHandler(stream)
108                 h.setLevel(logging.DEBUG)
109                 h.setFormatter(logfmt)
110                 h._cpbuiltin = "screen"
111                 log.addHandler(h)
112         elif h:
113             log.handlers.remove(h)
114    
115     def _get_screen(self):
116         h = self._get_builtin_handler
117         has_h = h(self.error_log, "screen") or h(self.access_log, "screen")
118         return bool(has_h)
119    
120     def _set_screen(self, newvalue):
121         self._set_screen_handler(self.error_log, newvalue, stream=sys.stderr)
122         self._set_screen_handler(self.access_log, newvalue)
123     screen = property(_get_screen, _set_screen,
124                       doc="If True, error and access will print to stdout.")
125    
126    
127     # -------------------------- File handlers -------------------------- #
128    
129     def _add_builtin_file_handler(self, log, fname):
130         h = logging.FileHandler(fname)
131         h.setLevel(logging.DEBUG)
132         h.setFormatter(logfmt)
133         h._cpbuiltin = "file"
134         log.addHandler(h)
135    
136     def _set_file_handler(self, log, filename):
137         h = self._get_builtin_handler(log, "file")
138         if filename:
139             if h:
140                 if h.baseFilename != os.path.abspath(filename):
141                     h.close()
142                     log.handlers.remove(h)
143                     self._add_builtin_file_handler(log, filename)
144             else:
145                 self._add_builtin_file_handler(log, filename)
146         else:
147             if h:
148                 h.close()
149                 log.handlers.remove(h)
150    
151     def _get_error_file(self):
152         h = self._get_builtin_handler(self.error_log, "file")
153         if h:
154             return h.baseFilename
155         return ''
156     def _set_error_file(self, newvalue):
157         self._set_file_handler(self.error_log, newvalue)
158     error_file = property(_get_error_file, _set_error_file,
159                           doc="The filename for self.error_log.")
160    
161     def _get_access_file(self):
162         h = self._get_builtin_handler(self.access_log, "file")
163         if h:
164             return h.baseFilename
165         return ''
166     def _set_access_file(self, newvalue):
167         self._set_file_handler(self.access_log, newvalue)
168     access_file = property(_get_access_file, _set_access_file,
169                            doc="The filename for self.access_log.")
170    
171    
172     # ------------------------- WSGI handlers ------------------------- #
173    
174     def _set_wsgi_handler(self, log, enable):
175         h = self._get_builtin_handler(log, "wsgi")
176         if enable:
177             if not h:
178                 h = WSGIErrorHandler()
179                 h.setLevel(logging.DEBUG)
180                 h.setFormatter(logfmt)
181                 h._cpbuiltin = "wsgi"
182                 log.addHandler(h)
183         elif h:
184             log.handlers.remove(h)
185    
186     def _get_wsgi(self):
187         return bool(self._get_builtin_handler(self.error_log, "wsgi"))
188    
189     def _set_wsgi(self, newvalue):
190         self._set_wsgi_handler(self.error_log, newvalue)
191     wsgi = property(_get_wsgi, _set_wsgi,
192                       doc="If True, error messages will be sent to wsgi.errors.")
193
194
195 class WSGIErrorHandler(logging.Handler):
196     "A handler class which writes logging records to environ['wsgi.errors']."
197    
198     def flush(self):
199         """Flushes the stream."""
200         try:
201             stream = cherrypy.request.wsgi_environ.get('wsgi.errors')
202         except (AttributeError, KeyError):
203             pass
204         else:
205             stream.flush()
206    
207     def emit(self, record):
208         """Emit a record."""
209         try:
210             stream = cherrypy.request.wsgi_environ.get('wsgi.errors')
211         except (AttributeError, KeyError):
212             pass
213         else:
214             try:
215                 msg = self.format(record)
216                 fs = "%s\n"
217                 import types
218                 if not hasattr(types, "UnicodeType"): #if no unicode support...
219                     stream.write(fs % msg)
220                 else:
221                     try:
222                         stream.write(fs % msg)
223                     except UnicodeError:
224                         stream.write(fs % msg.encode("UTF-8"))
225                 self.flush()
226             except:
227                 self.handleError(record)
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets