Skip to content

Instantly share code, notes, and snippets.

@AFirooz
Last active April 29, 2025 05:30
Show Gist options
  • Save AFirooz/bb6a9112b6d0c516b5a4de36ee6232e1 to your computer and use it in GitHub Desktop.
Save AFirooz/bb6a9112b6d0c516b5a4de36ee6232e1 to your computer and use it in GitHub Desktop.
Misc Test
# =================================================================================
# Name : cancerlog.py
# Author : Ali Firooz
# Version : 0.0.1
# Copyright : Copyright © 2023 Ali Firooz. All Rights Reserved.
# Description : based on: https://ankitbko.github.io/blog/2021/04/logging-in-python/
# Usage :
# =================================================================================
# TODO:
# 1. Add functionality to log other levels (info, warning, error, critical)
# 2. Figure out how to use MyLogger class. Or better yet,
# how to tell each decorated function to use a specific logging level.
# 3. Add functionality to log to console.
# 4. finish the "Usage" section.
import logging
import varname as vn
import functools
import inspect
from os import path
from typing import Union
def dprint(*args, **kwargs):
"""
Use this instead of print() to have variable print in a nice way.
:param new_line: If you want an extra new line between each print.
:param args: The variable(s) you want to debug.
:param kwargs: If you have a function applied to a variable (like len()), use this.
:return: None
"""
if 'new_line' in kwargs.keys():
new_line = kwargs.pop('new_line')
else:
new_line = False
if 'end' in kwargs.keys():
end = kwargs.pop('end')
else:
end = '\n'
if 'debug' in kwargs.keys():
debug = kwargs.pop('debug')
else:
debug = False
# try:
allvars = vn.argname('args')
for t_key, t_val in zip(allvars, args):
print(f"{t_key}: {t_val}")
print() if new_line else None
for t_key, t_val in kwargs.items():
print(f"{t_key}: {t_val}")
print() if new_line else None
print(end=end)
if debug:
print('------------------')
print(f"args: \n{args}\n\n"
f"kwargs: \n{kwargs}")
print('------------------')
# except Exception as e:
# print('------------------')
# print(args)
# print(kwargs)
# print(e)
# print('------------------')
class MyLogger:
# Constructor for initializing the logging system with a default logging level of DEBUG.
def __init__(self, level=logging.DEBUG, filename="runtime.log"):
self.debugf = '%(asctime)s - %(levelname)s - %(message)s'
if level == logging.DEBUG:
logging.basicConfig(level=level, format=self.debugf, filename=filename)
# Method for getting a logger by name.
def get_logger(self, name=None):
return logging.getLogger(name)
# Function to get a default logger using the MyLogger class.
def get_default_logger():
return MyLogger().get_logger()
def _getprefix(func=None) -> str:
# Get the filename where the decorated function is defined.
try:
function_filename = path.split(inspect.getfile(func))[1]
filename = f"{function_filename} -"
except Exception:
filename: str = "file:UNKNOWN -"
# get class name
# todo: need to check if this works
try:
clsname = func.__qualname__
clsname = f"cls:{clsname} -"
except Exception:
clsname = "cls/func:UNKNOWN -"
return f"cls/func:{clsname} {filename}"
# Decorator function logme that can be used to log function calls and exceptions.
def logme(_func=None, *, my_logger: Union[MyLogger, logging.Logger] = None):
# Decorator function that wraps another function with logging functionality.
def decorator_log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Get the prefix (class_name.function_name - file_name) for the log message.
prefix = _getprefix(func)
# Get the default logger if my_logger is not provided.
logger = get_default_logger()
try:
if my_logger is None:
# capture first arg to check for `self`
first_args = next(iter(args), None)
# does kwargs have any logger
logger_params = [
x
for x in kwargs.values()
if isinstance(x, logging.Logger) or isinstance(x, MyLogger)
] + [
# does args have any logger
x
for x in args
if isinstance(x, logging.Logger) or isinstance(x, MyLogger)
]
# is first argument `self`
if hasattr(first_args, "__dict__"):
logger_params = logger_params + [
# does class (dict) members have any logger
x for x in first_args.__dict__.values()
if isinstance(x, logging.Logger) or isinstance(x, MyLogger)
]
# get the next/first/default logger
h_logger = next(iter(logger_params), MyLogger())
else:
# logger is passed explicitly to the decorator
h_logger = my_logger
if isinstance(h_logger, MyLogger):
logger = h_logger.get_logger(func.__name__)
else:
logger = h_logger
# Prepare a signature of the function call with its arguments and keyword arguments.
args_repr = [repr(a) for a in args]
kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
signature = ", ".join(args_repr + kwargs_repr)
# Log the function call with its signature.
logger.debug(f"{prefix} Called with args {signature}")
except Exception:
pass
try:
# Call the original function and capture its result.
result = func(*args, **kwargs)
return result
except Exception as e:
# Log an exception if one is raised during the function call and re-raise it.
logger.exception(f"{prefix} Exception raised. exception: \n{str(e)}")
raise e
return wrapper
# Check if this decorator is used with or without parentheses.
if _func is None:
# Return the decorator function when no arguments are provided.
return decorator_log
else:
# Return the decorated function when arguments are provided.
return decorator_log(_func)
if __name__ == '__main__':
pass
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
from cancerlog import logme
@logme
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
class something:
def __init__(self):
pass
@logme
def clsfunc(self):
print("clsfunc is running")
if __name__ == '__main__':
# Input a number
num = 5
if num < 0:
print("Factorial is not defined for negative numbers.")
else:
result = factorial(num)
print(f"The factorial of {num} is {result}")
s = something()
s.clsfunc()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment