Package: logged-groups
Python logged groupsThis package designed to facilitate logging inside classes and functions with@logged_groupdecorator and also makes it possible
to manage logging level and any different things for any logging domain mentioned in log_cfg.jsonThis package maintained onpython-logged-groups github repsitoryby rozhkovdmitriirozhkovdmitrii@yandex.ruBuild packageTo build packagedist/logged-groups-2.1.2.tar.gz, for example, use following command:python setup.py sdistInstallationThen you can install package with the following:pip install dist/logged-groups-2.1.2.tar.gzor install it from pypi:pip install logged-groups==2.1.2or you can install it from git in yourrequirements.txtgit+https://github.com/rozhkovdmitrii/python-logged-groups.git@2.1.2Config fileThere should belog_cfg.jsonin where you uselogged_groupspackage. It's actuallystandard configurationto be used withlogging.config.dictConfig:
As you can see there are some irregular things:logged_groups.ColoredFormatter- to provide colored outputlogged_groups.logging.ContextFilterfilter - to provide "%(context)s" in the related format string. That format won't work if this filter is not set.neonlogger - parental umbrella logger gathers rules forneon.funcsandneon.classesloggers to avoid rules duplication{"version":1,"handlers":{"colored":{"class":"logging.StreamHandler","level":"DEBUG","formatter":"colored","filters":["context_filter"]}},"filters":{"context_filter":{"()":"logged_groups.ContextFilter"}},"formatters":{"colored":{"class":"logged_groups.ColoredFormatter","format":"%(asctime)23s %(levelname)8s %(process)6d:%(threadName)-10s %(name)20s:%(class)-30s  %(context)s %(message)s","style":"%"}},"loggers":{"neon":{"level":"DEBUG","handlers":["colored"],"propagate":false},"root":{"filters":["context_filter"],"level":"DEBUG","propagate":false}}}Logging group featurelogged_groupdecorator is designed to extend your classes and functions with a single logger that is not related to the name of module that is containing them.
From now on it is possible to group logging notes, logged  classes and logged functions in any module with a single logging group and, as a consequence, with a single logger.logged_groupalso extends a structure of logs with new logging attributesclassandclass-id.For each logger related tologged_groupdecorator you can set up different logging levels and others in configuration like for a standard logger.Logging context featureFor eachlogged_group-related logger thecontextlogging record attribute is available to use in a format string.
That context gets started to be available after using it in source code in the following way:fromlogged_groupsimportlogging_contextwithlogging_context(ctx1="value",ctx2="other value"):# here the first logging context is availablewithlogging_context(ctx3="value"):# here the second extended with ctx3 logging context is available# here the first logging context is backHot reloadThe logging configuration can be reloaded on the fly by sending the SIGHUP signal to related python processkill-SIGHUP$(pgreppython)Sampleimportthreadingfromlogged_groupsimportlogged_group,logging_contextimporttime@logged_group("neon.classes")classA:def__init__(self,**kws):self.info("Some information, keep focused on it")defdo_stuff(self,value:int):try:self._do_stuff_impl(value)exceptBaseExceptionase:self.error(f"Failed to do stuff because of error:{e}")def_do_stuff_impl(self,value):self.debug(f"Doing stuff with value:{value}")ifvalue>1000:raiseException(f"Value critically high:{value}")ifvalue>100:self.warning(f"Value higher than 100, it can be wrong:{value}")@logged_group("classes")classB:def__init__(self):foriinrange(0,5):self.debug("Spam spam spam spam spam ")@logged_group("funcs")defcheck_logger(*,logger):logger.info("Hoooray it's working!!!")@logged_group("neon.funcs")defparallel(*,logger):a=A(class_id=33)withlogging_context(user_id="Max",mode="threaded"):try:foriinrange(1,10):time.sleep(1)a.do_stuff(i)ifi==5:raiseException("Something wrong")exceptExceptionase:logger.error(f"Got exception:\"{e}\"")a.do_stuff(777)if__name__=="__main__":a=A(class_id=33)tr=threading.Thread(target=parallel)tr.start()withlogging_context(user_id="Alice")asctx:a1=A(class_id="1")a1.do_stuff(100)time.sleep(4)withlogging_context(req_id="1",mode="support"):a1.do_stuff(101)a1.do_stuff(1001)a1.do_stuff(0)time.sleep(2)withlogging_context(user_id="Bob",req_id="2",mode="processing"):b=B()time.sleep(2)check_logger()tr.join()