I have multiple modules that use the same utils.py
package. How do I make the logger in utils.py
differ without having to pass the logger variable from the callers(i.e. ClassA or ClassB)?
Very simple sample codes are as following. In reality, I have a lot of functions and classes in utils.py
, and that's why I don't want to pass the logger
variable into utils.py
.
~/test-two-loggers$ tree .
├── main.py
├── configs.py
├── ClassA.py
├── ClassB.py
└── utils.py
0 directories, 5 files
main.py
import ClassA
import ClassB
ClassA.func()
ClassB.func()
ClassA.py
import utils
import configs
import logging
def func():
logger = logging.getLogger("classA")
logger.info("in ClassA")
utils.common_func(logger) # I want to change this line!!!!
ClassB.py
import utils
import configs
import logging
def func():
logger = logging.getLogger("classB")
logger.info("in ClassB")
utils.common_func(logger) # I want to change this line!!!!
utils.py
def common_func(logger): # I want to change this line!!!!
# do a lot of things ClassA and ClassB both need to do
logger.info("in utils - step one finished")
# do a lot of things ClassA and ClassB both need to do
logger.info("in utils - step two finished")
# do a lot of things ClassA and ClassB both need to do
logger.info("in utils - step three finished")
configs.py
import logging.config
logging_config = {
"version": 1,
"formatters": {
"formatter_a": {
"format": u"[A][%(levelname)s] %(module)s.%(lineno)d: %(message)s"
},
"formatter_b": {
"format": u"[B][%(levelname)s] %(module)s.%(lineno)d: %(message)s"
},
},
"handlers": {
"console_a": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "formatter_a",
"stream": "ext://sys.stdout"
},
"console_b": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "formatter_b",
"stream": "ext://sys.stdout"
},
},
"loggers": {
"classA": {
"level": "DEBUG",
"handlers": ["console_a"],
"propagate": "no"
},
"classB": {
"level": "DEBUG",
"handlers": ["console_b"],
"propagate": "no"
},
},
}
logging.config.dictConfig(logging_config)
Result I want:
~/test-two-loggers$ python main.py
[A][INFO] ClassA.7: in ClassA
[A][INFO] utils.3: in utils - step one finished
[A][INFO] utils.5: in utils - step two finished
[A][INFO] utils.7: in utils - step three finished
[B][INFO] ClassB.7: in ClassB
[B][INFO] utils.3: in utils - step one finished
[B][INFO] utils.5: in utils - step two finished
[B][INFO] utils.7: in utils - step three finished
But I want another solution other than this. I don't want to pass the logger
variable into utils
.
You can firstly implement your own logger class by deriving from logging. Logger, in which you override the methods you target. And then you pass the logger class to the logging system by using logging. setLoggerClass.
You can set a different logging level for each logging handler but it seems you will have to set the logger's level to the "lowest". In the example below I set the logger to DEBUG, the stream handler to INFO and the TimedRotatingFileHandler to DEBUG. So the file has DEBUG entries and the stream outputs only INFO.
Looks like you're looking for something like implicit parameters.
This is something Python doesn't have (Explicit is better than implicit).
But, as always, there is a more or less elegant way to emulate it:
class LoggerWrapper:
def __init__(self, logger_name):
self.logger = logging.getLogger(logger_name)
def common_func(self):
pass # do stuff here
logger = LoggerWrapper('classA')
logger.common_func()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With