I have a custom logging class, which has the following format:
log_format = "%(asctime)s.%(msecs)d %(levelname)-8s [%(processName)s] [%(threadName)s] %(filename)s:%(lineno)d --- %(message)s"
My project tree looks something like this:
.
├── exceptions.py
├── logger.py
├── settings.py
└── main.py
In main.py I import my custom Logger
from logger.py
. On several places I perform logging using the following syntax:
Logger.info("Transcribed audio successfully.")
However when looking at the logs, the filename
and lineno
params are always referring to my Logger
class, not the actual function from main.py
which invoked the logging:
2023-02-15 10:48:06,241.241 INFO [MainProcess] [MainThread] logger.py:38 --- Transcribed audio successfully.
Is there a way to change this? I would like that the log entry states something like:
2023-02-15 10:48:06,241.241 INFO [MainProcess] [MainThread] main.py:98 --- Transcribed audio successfully.
This is my logger.py
file:
import logging
from logging.handlers import RotatingFileHandler
class Logger:
log_format = "%(asctime)s.%(msecs)d %(levelname)-8s [%(processName)s] [%(threadName)s] %(filename)s:%(lineno)d --- %(message)s"
@staticmethod
def setup_single_logger(name, logfile, level):
handler = RotatingFileHandler(logfile, mode='a', maxBytes=1024 * 1024, backupCount=10)
handler.setFormatter(logging.Formatter(Logger.log_format))
logger = logging.getLogger(name)
logger.setLevel(level)
logger.addHandler(handler)
return logger
@staticmethod
def setup_logging():
Logger.info_logger = Logger.setup_single_logger('INFO', '/path/to/your/logfile.log', logging.INFO)
@staticmethod
def info(msg, *args, **kwargs):
Logger.info_logger.info(msg, *args, **kwargs)
Logger.setup_logging()
And an example main.py
is:
from logger import Logger
Logger.info("Transcribed audio successfully.")
The problem is that you setup and create your logger in logging.py
. So when you call Logger.info
from main, the actual call of info
on the logger object is done inside logger.py
. You just created an interface for yourself to the logger object, but the underlying call is still the one specifying the attributes of the message.
What you could do is leave only the setup in logger.py
, and let main.py
have its own logger object.
So log.py
(changed name due to clashes) can be:
import logging
from logging.handlers import RotatingFileHandler
def basic_config():
log_format = "%(asctime)s.%(msecs)d %(levelname)-8s [%(processName)s] [%(threadName)s] %(filename)s:%(lineno)d --- %(message)s"
handler = RotatingFileHandler('logfile.log', mode='a', maxBytes=1024 * 1024, backupCount=10)
handler.setFormatter(logging.Formatter(log_format))
logging.basicConfig(handlers=(handler,), level=logging.INFO)
(I felt like the use of the class was not necessary)
And main.py
:
import log
import logging
log.basic_config()
logger = logging.getLogger(__file__)
logger.info("test")
Now the log file I got from running once with your code and once with mine was:
2023-02-15 13:14:30,275.275 INFO [MainProcess] [MainThread] log.py:23 --- test
2023-02-15 13:18:51,358.358 INFO [MainProcess] [MainThread] main.py:7 --- test