Changeset 1984
- Timestamp:
- 06/22/08 16:11:54
- Files:
-
- trunk/cherrypy/_cplogging.py (modified) (2 diffs)
- trunk/cherrypy/test/logtest.py (added)
- trunk/cherrypy/test/test.py (modified) (1 diff)
- trunk/cherrypy/test/test_core.py (modified) (4 diffs)
- trunk/cherrypy/test/test_logging.py (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/_cplogging.py
r1948 r1984 19 19 error_log = None 20 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"' 21 23 22 24 def __init__(self, appid=None, logger_root="cherrypy"): … … 62 64 63 65 def access(self): 64 """Write to the access log (in Apache/NCSA Combined Log format).""" 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 """ 65 75 request = cherrypy.request 66 inheaders = request.headers67 76 remote = request.remote 68 77 response = cherrypy.response 69 78 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 } 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 # Fortunately, repr(str) escapes unprintable chars, \n, \t, etc 97 # and backslash for us. All we have to do is strip the quotes. 98 v = repr(v)[1:-1] 99 # Escape double-quote. 100 atoms[k] = v.replace('"', '\\"') 101 81 102 try: 82 self.access_log.log(logging.INFO, s )103 self.access_log.log(logging.INFO, self.access_log_format % atoms) 83 104 except: 84 105 self(traceback=True) trunk/cherrypy/test/test.py
r1908 r1984 375 375 'test_httpauth', 376 376 'test_httplib', 377 'test_logging', 377 378 'test_objectmapping', 378 379 'test_misc_tools', trunk/cherrypy/test/test_core.py
r1978 r1984 13 13 14 14 15 log_file = os.path.join(localDir, "test.log")16 log_access_file = os.path.join(localDir, "access.log")17 15 favicon_path = os.path.join(os.getcwd(), localDir, "../favicon.ico") 18 16 … … 419 417 420 418 cherrypy.config.update({ 421 'log.error_file': log_file,422 419 'environment': 'test_suite', 423 420 'server.max_request_body_size': 200, … … 425 422 }) 426 423 appconf = { 427 '/': {'log.access_file': log_access_file},428 424 '/method': {'request.methods_with_bodies': ("POST", "PUT", "PROPFIND")}, 429 425 } … … 489 485 msg = "Illegal response status from server ('error' is non-numeric)." 490 486 self.assertErrorPage(500, msg) 491 492 def testLogging(self):493 f = open(log_access_file, "wb")494 f.write("")495 f.close()496 f = open(log_file, "wb")497 f.write("")498 f.close()499 500 self.getPage("/flatten/as_string",501 headers=[('Referer', 'http://www.cherrypy.org/'),502 ('User-Agent', 'Mozilla/5.0')])503 self.assertBody('content')504 self.assertStatus(200)505 506 self.getPage("/flatten/as_yield")507 self.assertBody('content')508 self.assertStatus(200)509 510 data = open(log_access_file, "rb").readlines()511 512 host = self.HOST513 if host == '0.0.0.0':514 # INADDR_ANY, which should respond on localhost.515 host = "127.0.0.1"516 if host == '::':517 # IN6ADDR_ANY, which should respond on localhost.518 host = "::1"519 intro = '%s - - [' % host520 521 if not data[0].startswith(intro):522 self.fail("%r doesn't start with %r" % (data[0], intro))523 haslength = False524 for k, v in self.headers:525 if k.lower() == 'content-length':526 haslength = True527 line = data[-2].strip()528 if haslength:529 if not line.endswith('] "GET %s/flatten/as_string HTTP/1.1" 200 7 '530 '"http://www.cherrypy.org/" "Mozilla/5.0"'531 % self.prefix()):532 self.fail(line)533 else:534 if not line.endswith('] "GET %s/flatten/as_string HTTP/1.1" 200 - '535 '"http://www.cherrypy.org/" "Mozilla/5.0"'536 % self.prefix()):537 self.fail(line)538 539 if not data[-1].startswith(intro):540 self.fail("%r doesn't start with %r" % (data[-1], intro))541 haslength = False542 for k, v in self.headers:543 if k.lower() == 'content-length':544 haslength = True545 line = data[-1].strip()546 if haslength:547 self.assert_(line.endswith('] "GET %s/flatten/as_yield HTTP/1.1" 200 7 "" ""'548 % self.prefix()))549 else:550 self.assert_(line.endswith('] "GET %s/flatten/as_yield HTTP/1.1" 200 - "" ""'551 % self.prefix()))552 553 ignore = helper.webtest.ignored_exceptions554 ignore.append(ValueError)555 try:556 # Test that tracebacks get written to the error log.557 self.getPage("/error/page_method")558 self.assertInBody("raise ValueError()")559 data = open(log_file, "rb").readlines()560 self.assertEqual(data[0].strip().endswith('HTTP Traceback (most recent call last):'), True)561 self.assertEqual(data[-3].strip().endswith('raise ValueError()'), True)562 finally:563 ignore.pop()564 487 565 488 def testSlashes(self):

