Reputation: 1911
I want to use my own logger class to for all logger instances, the goal is to have consistent text formatting and easily save all records in the same file.
But I'm using a library that create a logger instance when I import it, then log messages when I run my code.
The solution seems to use setLoggerClass but it have to be called before the import stage. Which gives me:
import logging
from utils.logger import MyLogger
logging.setLoggerClass(MyLogger)
import other.packages
# Remove the handlers set on the external logger and replace by mine.
for handler in external_logger.handlers[:]:
external_logger.removeHandler(handler)
external_logger.setup_my_handlers()
# Some code
This is working but looks dirty and doesn't satisfy PEP8 code style guide line. I'm also afraid to break it after any refractory.
Is there any clean way to do this?
Upvotes: 2
Views: 1536
Reputation: 76
There is a library called structlog that handles this case pretty well. On this page they show you how to setup a formatter and set that on the root logger. (You will need to setup logging before any other python package tries to setup logging, 99% of the time this means at the top of your entrypoint file). This method shows how you can now use stdlib and structlog loggers side-by-side while having consistent output (in your case some nice formatting)
Upvotes: 1
Reputation: 11
This code below may solve this problem:
logging.getLogger(external_logger_name).propagate = False
In logging module, it has multi loggers, it is a tree structure, and all other logger is child of "root" logger. When you using:
logging.info('message')
Actually logging module will find all logger which is enabled to logging, You can set one logger's propagate attribute False to disable it.
Upvotes: 1
Reputation: 1749
Use the below function that you can call multiple loggers in the same runtime which can save multiple log files. edit code with your parameters,
import os
import logging
if not os.path.exists(r"logs"):
os.mkdir(r"logs")
def loggerInstance(logger_name, level=logging.DEBUG):
logger = logging.getLogger(logger_name)
logger.setLevel(level)
format_string = '%(asctime)s: %(levelname)s: %(message)s'
log_format = logging.Formatter(format_string, datefmt='%m/%d/%Y %I:%M:%S %p')
# Creating and adding the console handler
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(log_format)
logger.addHandler(console_handler)
# Creating and adding the file handler
file_handler = logging.FileHandler(logger_name, mode='a')
file_handler.setFormatter(log_format)
logger.addHandler(file_handler)
return logger
CRLogger = loggerInstance(f"logs/" + "Log1.log")
CRLogger.info('Log File is Created Successfully')
This should work. if you are running in multiple loop or sessions or runtime, this will create a log each time even if it is runtime under the loop. you should save the log file name differently every time in order to that.
NOTE: if you want to save the log in the same file, keep the same name (xx.log) which will append every new runtime loggings.
Upvotes: 0
Reputation: 44138
I don't know what your package structure is but this is code that should be placed in the __init__.py
file for a package that gets imported before all other packages that uses logging gets imported. If your package structure had a high level package, e.g. my_application, from which all other packages were descended (this would be the ideal situation), as in the following diagram ...
my_application
__init_.py
package_1
__init__.py
package_1_1
__init__.py
package_2
__init__.py
etc.
... then you would want to put the log initialization code in file my_application/__init__.py because this package initialization code will always be executed when any of the above packages is imported. If there is no such parent package, then perhaps there is a package that just happens to be already get imported before all other packages that use logging. Finally, you can always create a new package with just an __init__.py
file into which you place your code and then modify your scripts to import that new package as the first imported package.
Upvotes: 1
Reputation: 74
I think the problem here is library that youre using creating a different logger instance 'when you import' it. Instead write a function in that library that creates a logger instance only when you use it. Then write your code as
import logging
import other.packages
from utils.logger import MyLogger
logging.setLoggerClass(MyLogger)
...function thet creates logger instance...
#more code
Upvotes: 0