logfury
Logfury is a toolkit for Python library maintainers, offering responsible, low-boilerplate logging of method calls. It implements an 'apiver' import strategy (e.g., `from logfury.v1 import ...`) to ensure API stability, allowing users to explicitly opt into versioned APIs. The library is currently at version 1.0.1, released on October 23, 2021, with a focus on method call tracing and a mature development status.
Warnings
- deprecated Support for Python versions prior to 3.5 was deprecated in v1.0.0. Ensure your environment uses Python 3.5 or newer.
- gotcha Logfury uses an 'apiver' strategy where you explicitly import from `logfury.vX` (e.g., `logfury.v1`). Importing directly from `logfury` (e.g., `from logfury import ...`) is not recommended as it could lead to unexpected behavior or breakage if the default top-level API changes in future versions.
- gotcha Prior to version 1.0.1, there were known issues with decorating entire classes and incorrect ordering of arguments in logged output. These were fixed in v1.0.1.
Install
-
pip install logfury
Imports
- DefaultTraceMeta
from logfury import DefaultTraceMeta
from logfury.v1 import DefaultTraceMeta
- limit_trace_arguments
from logfury.v1 import limit_trace_arguments
- disable_trace
from logfury.v1 import disable_trace
Quickstart
import logging
import six
from logfury.v1 import DefaultTraceMeta, limit_trace_arguments, disable_trace
logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
@six.add_metaclass(DefaultTraceMeta)
class Foo:
def baz(self, a, b, c=None):
return True
def get_blah(self):
return 5
def _hello(self):
pass
@disable_trace
def world(self):
pass
def __repr__(self):
return '<{} object>'.format(self.__class__.__name__)
class Bar(Foo):
def baz(self, a, b, c=None):
b += 1
return super(Bar, self).baz(a, b, c)
@limit_trace_arguments(skip=['password'])
def secret(self, password, other):
pass
a = Foo()
a.baz(1, 2, 3)
a.baz(4, b=8)
a.get_blah() # Not traced by default pattern
a._hello() # Not traced by default pattern
a.world() # Explicitly disabled
b = Bar()
b.baz(5, 6)
b.secret('my_secret', 'other_value')
# Expected output in console for a.baz calls:
# DEBUG:__main__:calling Foo.baz(self=<Foo object>, a=1, b=2, c=3)
# DEBUG:__main__:calling Foo.baz(self=<Foo object>, a=4, b=8)