1 """CherryPy logging."""
2
3 import datetime
4 import logging
5
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
17
18 appid = None
19 error_log = None
20 access_log = None
21 access_log_format = \
22 '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
23
24 - def __init__(self, appid=None, logger_root="cherrypy"):
36
46
47 - def error(self, msg='', context='', severity=logging.INFO, traceback=False):
48 """Write to the error log.
49
50 This is not just for errors! Applications may call this at any time
51 to log application-specific information.
52 """
53 if traceback:
54 msg += _cperror.format_exc()
55 self.error_log.log(severity, ' '.join((self.time(), context, msg)))
56
58 """Write to the error log.
59
60 This is not just for errors! Applications may call this at any time
61 to log application-specific information.
62 """
63 return self.error(*args, **kwargs)
64
66 """Write to the access log (in Apache/NCSA Combined Log format).
67
68 Like Apache started doing in 2.0.46, non-printable and other special
69 characters in %r (and we expand that to all parts) are escaped using
70 \\xhh sequences, where hh stands for the hexadecimal representation
71 of the raw byte. Exceptions from this rule are " and \\, which are
72 escaped by prepending a backslash, and all whitespace characters,
73 which are written in their C-style notation (\\n, \\t, etc).
74 """
75 request = cherrypy.request
76 remote = request.remote
77 response = cherrypy.response
78 outheaders = response.headers
79 inheaders = request.headers
80
81 atoms = {'h': remote.name or remote.ip,
82 'l': '-',
83 'u': getattr(request, "login", None) or "-",
84 't': self.time(),
85 'r': request.request_line,
86 's': response.status.split(" ", 1)[0],
87 'b': outheaders.get('Content-Length', '') or "-",
88 'f': inheaders.get('Referer', ''),
89 'a': inheaders.get('User-Agent', ''),
90 }
91 for k, v in atoms.items():
92 if isinstance(v, unicode):
93 v = v.encode('utf8')
94 elif not isinstance(v, str):
95 v = str(v)
96
97
98 v = repr(v)[1:-1]
99
100 atoms[k] = v.replace('"', '\\"')
101
102 try:
103 self.access_log.log(logging.INFO, self.access_log_format % atoms)
104 except:
105 self(traceback=True)
106
108 """Return now() in Apache Common Log Format (no timezone)."""
109 now = datetime.datetime.now()
110 month = rfc822._monthnames[now.month - 1].capitalize()
111 return ('[%02d/%s/%04d:%02d:%02d:%02d]' %
112 (now.day, month, now.year, now.hour, now.minute, now.second))
113
115 for h in log.handlers:
116 if getattr(h, "_cpbuiltin", None) == key:
117 return h
118
119
120
121
123 h = self._get_builtin_handler(log, "screen")
124 if enable:
125 if not h:
126 if stream is None:
127 stream=sys.stderr
128 h = logging.StreamHandler(stream)
129 h.setFormatter(logfmt)
130 h._cpbuiltin = "screen"
131 log.addHandler(h)
132 elif h:
133 log.handlers.remove(h)
134
139
143 screen = property(_get_screen, _set_screen,
144 doc="If True, error and access will print to stderr.")
145
146
147
148
150 h = logging.FileHandler(fname)
151 h.setFormatter(logfmt)
152 h._cpbuiltin = "file"
153 log.addHandler(h)
154
169
177 error_file = property(_get_error_file, _set_error_file,
178 doc="The filename for self.error_log.")
179
187 access_file = property(_get_access_file, _set_access_file,
188 doc="The filename for self.access_log.")
189
190
191
192
203
206
209 wsgi = property(_get_wsgi, _set_wsgi,
210 doc="If True, error messages will be sent to wsgi.errors.")
211
212
214 "A handler class which writes logging records to environ['wsgi.errors']."
215
217 """Flushes the stream."""
218 try:
219 stream = cherrypy.request.wsgi_environ.get('wsgi.errors')
220 except (AttributeError, KeyError):
221 pass
222 else:
223 stream.flush()
224
225 - def emit(self, record):
226 """Emit a record."""
227 try:
228 stream = cherrypy.request.wsgi_environ.get('wsgi.errors')
229 except (AttributeError, KeyError):
230 pass
231 else:
232 try:
233 msg = self.format(record)
234 fs = "%s\n"
235 import types
236 if not hasattr(types, "UnicodeType"):
237 stream.write(fs % msg)
238 else:
239 try:
240 stream.write(fs % msg)
241 except UnicodeError:
242 stream.write(fs % msg.encode("UTF-8"))
243 self.flush()
244 except:
245 self.handleError(record)
246