X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fipsilon.git;a=blobdiff_plain;f=ipsilon%2Futil%2Flog.py;h=ae851af6578b590a4aecd15cfaa35938e2356681;hp=a010b16d683ac26653b55209b92488fdf18911e4;hb=aa5dc3b417db962a075a092d0d3528010c1059f7;hpb=e85f190d8e081fbbfeadca24781266d1c3e1bba1 diff --git a/ipsilon/util/log.py b/ipsilon/util/log.py index a010b16..ae851af 100644 --- a/ipsilon/util/log.py +++ b/ipsilon/util/log.py @@ -3,8 +3,12 @@ # See the file named COPYING for the project license import cherrypy -import inspect import cStringIO +import inspect +import os +import traceback +import logging + def log_request_response(): '''Log the contents of the request and subsequent response. @@ -79,7 +83,7 @@ def log_request_response(): ''' - #--- Begin local functions --- + # --- Begin local functions --- def indent_text(text, level=0, indent=' '): ''' @@ -133,6 +137,21 @@ def log_request_response(): f.close() return string + def print_param(name, value): + f = cStringIO.StringIO() + + # Might be a multipart Part object, if so format it + if isinstance(value, cherrypy._cpreqbody.Part): # pylint:disable=W0212 + f.write(indent_text("%s:\n" % (name))) + f.write(indent_text(print_part(value), 1)) + else: + # Not a mulitpart, just write it as a string + f.write(indent_text("%s: %s\n" % (name, value))) + + string = f.getvalue() + f.close() + return string + def collapse_body(body): '''The cherrypy response body can be: @@ -168,7 +187,7 @@ def log_request_response(): f.close() return string - #--- End local functions --- + # --- End local functions --- f = cStringIO.StringIO() request = cherrypy.serving.request @@ -177,8 +196,8 @@ def log_request_response(): # # Log the Request # - f.write(indent_text(" [%s] %s\n" % \ - (remote.name or remote.ip, request.request_line), 0)) + f.write(indent_text(" [%s] %s\n" % + (remote.name or remote.ip, request.request_line), 0)) # Request Headers if request.headers: @@ -194,16 +213,10 @@ def log_request_response(): # Multi-valued paramater is in a list if isinstance(value, list): for i, item in enumerate(value): - # Might be a multipart Part object, if so format it - if isinstance(item, cherrypy._cpreqbody.Part): - f.write(indent_text("%s[%s]:\n" % (name, i), 2)) - f.write(indent_text(print_part(item), 3)) - else: - # Not a mulitpart, just write it as a string - f.write(indent_text("%s[%s]: %s\n" % (name, i, item), 2)) + f.write(indent_text(print_param("%s[%d]" % (name, i), + item), 2)) else: - # Just a string value - f.write(indent_text("%s: %s\n" % (name, value), 2)) + f.write(indent_text(print_param(name, value), 2)) # If the body is multipart format each of the parts if request.body.parts: @@ -241,15 +254,72 @@ def log_request_response(): f.close() print string -cherrypy.tools.log_request_response = cherrypy.Tool('on_end_resource', log_request_response) +cherrypy.tools.log_request_response = cherrypy.Tool('on_end_resource', + log_request_response) class Log(object): + @staticmethod + def stacktrace(): + buf = cStringIO.StringIO() + + stack = traceback.extract_stack() + traceback.print_list(stack[:-2], file=buf) + + stacktrace_string = buf.getvalue() + buf.close() + return stacktrace_string + + @staticmethod + def get_class_from_frame(frame_obj): + ''' + Taken from: + http://stackoverflow.com/questions/2203424/ + python-how-to-retrieve-class-information-from-a-frame-object + + At the frame object level, there does not seem to be any way + to find the actual python function object that has been + called. + + However, if your code relies on the common convention of naming + the instance parameter of a method self, then you could do this. + ''' + + args, _, _, value_dict = inspect.getargvalues(frame_obj) + # Is the functions first parameter named 'self'? + if len(args) and args[0] == 'self': + # in that case, 'self' will be referenced in value_dict + instance = value_dict.get('self', None) + if instance: + # return its class + return getattr(instance, '__class__', None) + # return None otherwise + return None + + @staticmethod + def call_location(): + frame = inspect.stack()[2] + frame_obj = frame[0] + filename = frame[1] + line_number = frame[2] + func = frame[3] + + # Only report the last 3 components of the path + filename = os.sep.join(filename.split(os.sep)[-3:]) + + cls = Log.get_class_from_frame(frame_obj) + if cls: + location = '%s:%s %s.%s()' % \ + (filename, line_number, cls.__name__, func) + else: + location = '%s:%s %s()' % (filename, line_number, func) + return location + def debug(self, fact): if cherrypy.config.get('debug', False): - s = inspect.stack() - cherrypy.log('DEBUG(%s): %s' % (s[1][3], fact)) + location = Log.call_location() + cherrypy.log('DEBUG(%s): %s' % (location, fact)) # for compatibility with existing code _debug = debug @@ -258,4 +328,6 @@ class Log(object): cherrypy.log(fact) def error(self, fact): - cherrypy.log.error('ERROR: %s' % fact) + cherrypy.log.error('ERROR: %s' % fact, severity=logging.ERROR) + if cherrypy.config.get('stacktrace_on_error', False): + cherrypy.log.error(Log.stacktrace())