Skip to content

Instantly share code, notes, and snippets.

@vathpela
Created April 21, 2016 19:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vathpela/e4275a6687cd4168f5d1f8e759e2a78f to your computer and use it in GitHub Desktop.
Save vathpela/e4275a6687cd4168f5d1f8e759e2a78f to your computer and use it in GitHub Desktop.
#!/usr/bin/python3
# this is just a simple logger, so I can have a logger to show you
class Logger(object):
def __init__(self):
self.loglevel = 0
def __call__(self, level, msg):
import time
if self.loglevel >= level:
print("%s %s" % (time.asctime(), msg))
logger = Logger()
# this is the thing having log points added to it
class ExampleClass(object):
_trace_points = {"foo":"show_state"}
def __init__(self):
self._state = 1
@property
def state(self):
return self._state
def show_state(self):
print("self.state: %d" % (self.state,))
return 4
# here is the magic you don't need to see
class LogEditor(object):
def __init__(self, parent, child, level, logtypes):
self.parent = parent
self.child = child
self.method = getattr(parent, child)
self.level = level
self.logtypes = logtypes
def __call__(self, *args, **kwds):
stack = traceback.extract_stack()
if "ingress" in self.logtypes:
logger(3, "ingress %s(args=%s, kwds=%s)" % (self.method.__name__, args, kwds))
if "traceback" in self.logtypes:
import traceback
stack = "\n" + "".join(traceback.format_stack()).rstrip()
logger(3, stack)
ret = self.method(self=self.__real_object__, *args[1:], **kwds)
if "egress" in self.logtypes:
logger(3, "egress %s() = %s" % (self.method.__name__, ret))
return ret
def __real_init__(self, *args, **kwds):
self.__real_object__ = self.parent.__new__(self.parent, *args, **kwds)
self.__fake_init__(self=self.__real_object__, *args, **kwds)
return None
def add_logging(parent, child, level, logtypes=["ingress", "egress"]):
if hasattr(parent, "_trace_points") and child in parent._trace_points:
child = parent._trace_points[child]
old = getattr(parent, child)
if isinstance(old, LogEditor):
for logtype in logtypes:
if not logtype in old.logtypes:
old.logtypes.append(logtype)
else:
newlogger = LogEditor(parent, child, level, logtypes)
setattr(parent, child, newlogger)
setattr(newlogger, '__fake_init__', parent.__init__)
setattr(parent, '__init__', newlogger.__real_init__)
# make kickstart drive these lines via something more or less something like:
#
# %logging
# method ExampleClass.foo --level 3
# method ExampleClass.foo --level 3 --traceback
#
add_logging(ExampleClass, "foo", 3)
add_logging(ExampleClass, "foo", 3, logtypes=["traceback"])
# and then here's the normal usage code:
x = ExampleClass()
print("run with loglevel=0:")
x.show_state()
print("run with loglevel=3:")
logger.loglevel = 3
x.show_state()
trillian:~/devel/local/pylog$ ./foo.py
run with loglevel=0:
self.state: 1
run with loglevel=3:
Thu Apr 21 15:58:12 2016 ingress show_state(args=(), kwds={})
Thu Apr 21 15:58:12 2016
File "./foo.py", line 84, in <module>
x.show_state()
File "./foo.py", line 43, in __call__
stack = "\n" + "".join(traceback.format_stack()).rstrip()
self.state: 1
Thu Apr 21 15:58:12 2016 egress show_state() = 4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment