Skip to content

Instantly share code, notes, and snippets.

@brettschneider
Last active March 11, 2023 17:23
Show Gist options
  • Save brettschneider/80d8b46d0ea5f6d57832bc86cd296ab0 to your computer and use it in GitHub Desktop.
Save brettschneider/80d8b46d0ea5f6d57832bc86cd296ab0 to your computer and use it in GitHub Desktop.
Decorator to make function log calls for later examination
#!/usr/bin/env python
from dataclasses import dataclass
from datetime import datetime, timedelta
from functools import update_wrapper
@dataclass(frozen=True)
class Call:
func: callable
call_time: datetime
duration: timedelta
args: list
kwargs: dict
result: any = None
exception: Exception = None
def __repr__(self):
fn = self.func.__name__
ct = str(self.call_time)
d = str(self.duration)
a = self.args
kw = self.kwargs
r = f"[{str(self.result)}]" if self.result else self.result
e = f"[{self.exception}]" if self.exception else self.exception
return f"Call(func={fn}, call_time={ct}, duration={d}, " \
f"args={a}, kwargs={kw}, result={r}, exception={e}"
class log_calls:
"""Make the decorated function log all calls to it"""
def __init__(self, func):
self.func = func
self.calls: list[Call] = []
update_wrapper(self, func)
def __call__(self, *args, **kwargs):
exc = None
start = datetime.utcnow()
try:
result = self.func(*args, **kwargs)
except Exception as ex:
exc = ex
duration = datetime.utcnow() - start
if exc:
self.calls.append(Call(self.func, start, duration, args, kwargs, None, exc))
raise exc
else:
self.calls.append(Call(self.func, start, duration, args, kwargs, result, None))
return result
if __name__ == '__main__':
@log_calls
def greet(name: str):
if name in ['Sadie', 'Bently']:
raise ValueError("Pets can't be greeted.")
return f"Why hello, {name}."
@log_calls
def farewell(name: str):
return f"See you next time {name}."
print(f"Making attempts to call\n{'-'*80}")
for p in ['Steve', 'Sadie', 'Jen']:
try:
print(greet(p))
print(farewell(p))
except Exception as ex:
print('SOMETHING TERRIBLE HAPPENED!', ex)
print(f"\nGreeting call log\n{'-'*80}")
for c in greet.calls:
print(c)
print(f"\nFarewell call log\n{'-'*80}")
for c in farewell.calls:
print(c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment