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

root/tags/cherrypy-3.1.0beta2/cherrypy/_cplogging.py

Revision 1812 (checked in by fumanchu, 1 year ago)

Fix for #747 (log.screen should send error log messages to stderr).

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

Hosted by WebFaction

Log in as guest/cpguest to create tickets