Package: rolog
Async friendly logging classes for Python 3Features:logging classes usingasync/awaitfor logshandling of six logging levels, like in built-in logging modulebuilt-in support for flushing of log records (e.g. making a web request, or writing to a database, everynrecords)flushing supports max retries, configurable delays, number of attempts, and fallback target in case of failuresupport for several targets per loggercan be used to asynchronously log to different destinations (for example, web api integration, DBMS, etc.)logged records support any kind of desired arguments and data structurescompletely abstracted fromdestinationof log entriescan be used with built-inloggingmodule, for sync logging and touse built-in logging classesintegrated withrodi dependency injection library, to support injection of loggers by activated class nameInstallationpipinstallrologClasses and log levelsClassDescriptionLogLevelInt enum:NONE, DEBUG, INFORMATION, WARNING, ERROR, CRITICALLogTargetbase for classes that are able to send log records to a certain destinationLoggerclass responsible for creating log records and sending them to appropriate targets, by levelLoggerFactoryconfiguration class, responsible for holding configuration of targets and providing instances of loggersLogRecordlog record created by loggers, sent to configured targets by a loggerExceptionLogRecordlog record created by loggers, including exception informationFlushLogTargetabstract class, derived ofLogTarget, handling records in groups, storing them in memoryBasic useAs with the built-inloggingmodule,Loggerclass is not meant to be instantiated directly, but rather obtained using a configuredLoggerFactory.Example:importasynciofromrologimportLoggerFactory,Logger,LogTargetclassPrintTarget(LogTarget):asyncdeflog(self,record):awaitasyncio.sleep(.1)print(record.message,record.args,record.data)factory=LoggerFactory()factory.add_target(PrintTarget())logger=factory.get_logger(__name__)loop=asyncio.get_event_loop()asyncdefexample():awaitlogger.info('Lorem ipsum')# log methods support any argument and keyword argument:# these are stored in the instances of LogRecord, it is responsibility of LogTarget(s)# to handle these extra parameters as desiredawaitlogger.info('Hello, World!',1,2,3,cool=True)loop.run_until_complete(example())Flushing targetsrologhas built-in support for log targets that flush messages in groups, this is necessary to optimize for example
reducing the number of web requests when sending log records to a web api, or enabling bulk-insert inside a database.
Below is an example of flush target class that sends log records to some web api, in groups of500:fromtypingimportListfromrologimportFlushLogTarget,LogRecordclassSomeLogApiFlushLogTarget(FlushLogTarget):def__init__(self,http_client):super().__init__()self.http_client=http_clientasyncdeflog_records(self,records:List[LogRecord]):# NB: implement here your own logic to make web requests to send log records# to a web api, such as Azure Application Insights# (see for example https://pypi.org/project/asynapplicationinsights/)passFlush targets handle retries with configurable and progressive delays, when logging a group of records fails.
By default, in case of failure a flush target tries to log records3 times, using a progressive delay of0.6 seconds * attempt number,
finally falling back to a configurable fallback target if logging always failed. Warning messages are issued, using built-inWarningsmodule to notify of these failures.These parameters are configurable using constructor parametersfallback_target,max_size,retry_delay,progressive_delay.classFlushLogTarget(LogTarget,ABC):"""Base class for flushing log targets: targets that send the log records(created by loggers) to the appropriate destination in groups."""def__init__(self,queue:Optional[Queue]=None,max_length:int=500,fallback_target:Optional[LogTarget]=None,max_retries:int=3,retry_delay:float=0.6,progressive_delay:bool=True):Flushing when application stopsSince flushing targets hold log records in memory before flushing them, it's necessary to flush when an application stops.
Assuming that a singleLoggerFactoryis configured in the configuration root of an application, this
can be done conveniently, by calling thedisposemethod of the logger factory.# on application shutdown:awaitlogger_factory.dispose()Dependency injectionrologis integrated withrodi dependency injection library, to support injection of loggers per activated class name.
When a class that expects a parameter ofrolog.Loggertype is activated, it receives a logger for the category of the class name itself.
For more information, please refer to thededicated page in project wiki.DocumentationPlease refer to documentation in the project wiki:https://github.com/RobertoPrevato/rolog/wiki.Develop and run tests locallypipinstall-rdev_requirements.txt# run tests using automatic discovery:pytest