My logging module: MyLog.py
import logging
class MyLogC(logging.Filterer):
def __init__(self):
self.myLogger = logging.getLogger('')
self.myLogger.setLevel(logging.DEBUG)
self.myLogFile = logging.FileHandler("./ex.log","w")
self.myLogger.addHandler(self.myLogFile)
self.myLogFormatter= logging.Formatter('%(asctime)s %(levelname)s %(message)s')
self.myLogFile.setLevel(logging.DEBUG)
self.myLogFile.setFormatter(self.myLogFormatter)
def MyLogger(self):
return self.myLogger
In other module: MyTh.py
import MyLog
class MyThread(threading.Thread):
def __init__(self,name,value):
threading.Thread.__init__(self,None,MyClient,name,(),None,None)
...
self.logger=MyLog.MyLogC.MyLogger
def run(self):
...
self.logger.info("abc")
and using
self.logger=MyLog.MyLogC.MyLogger
But I am getting ('function' object has no attribute 'info') error while using:
self.logger.info("abc")
How can I make this work?
You are expecting self.logger to be a logger instance, but currently MyLog.MyLogC is a class, and the MyLogger is a method on that class.
Try self.logger = MyLog.MyLogC().MyLogger() (note the parens).
This first creates a MyLogC object, then invokes the MyLogger method on it to get the actual logger instance.
Related
Given my code, I would create a root logger instance logger = GlobalLogger(level=10).logger in __init__.py and include it in submodules where I need logging. Is there a better way to create this class instead of calling the attribute .logger to get the root logging class, or a better design approach overall?
import typing
import logging
class GlobalLogger:
MINIMUM_GLOBAL_LEVEL = logging.DEBUG
GLOBAL_HANDLER = logging.StreamHandler()
LOG_FORMAT = "[%(asctime)s] - %(levelname)s - [%(name)s.%(funcName)s:%(lineno)d] - %(message)s"
LOG_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
def __init__(self, level: typing.Union[int, str] = MINIMUM_GLOBAL_LEVEL):
self.level = level
self.logger = self._get_logger()
self.log_format = self._log_formatter()
self.GLOBAL_HANDLER.setFormatter(self.log_format)
def _get_logger(self):
logger = logging.getLogger(__name__)
logger.setLevel(self.level)
logger.addHandler(self.GLOBAL_HANDLER)
return logger
def _log_formatter(self):
return logging.Formatter(fmt=self.LOG_FORMAT, datefmt=self.LOG_DATETIME_FORMAT)
There is no point to do this, because loggers in Python are already managed by one global manager instance in the stdlib logging/__init__.py file.
Instead, just use logger = logging.getLogger(name) to get/create a logger at the top of each module which needs to log events. If you provide the same name you will get the same logger back, using logging.getLogger(__name__) to have one logger per module is just a popular convention.
How can I declare a custom logger with custom logging method in the main.py and then use the same object (!) in all the files that main.py uses:
eg
#main.py
import logging
from additional import bar
class CustomLogger(logging.Logger):
def __init__(self)
self.foo = None
def log(self, message):
apply_external_method(self.foo, message)
print(message)
logger = logging.getLogger('the_only_logger') # Should be CustomLogger
logger.foo = "foo"
And
# additional.py
logger = logging.getLogger('the_only_logger') # Should be CustomLogger and foo should be set
I have two solutions for you,
first, if you want to use a specific object you can add it to every constructor to get a logger object.
the second thing is you can make the logger write to a file and every file will create a new object but will write to the same file.
hope it's help(:
Thanks to #Klaus D, I figured out I need to set CustomHandler, and I need to do only once, after that logger can be shared across files with logger = logging.getLogger('same-logger-name')
# main.py
import logging
from additional import foo
class CustomHandler(logging.Handler):
def __init__(self, queue, *args, **kwargs):
self.queue = queue
print("Init", id(queue))
super(CustomHandler, self).__init__(*args, **kwargs)
def emit(self, record):
print("Log")
print(self.format(record))
logger = logging.getLogger('2')
logger.setLevel(logging.DEBUG)
handler = CustomHandler("custom object")
logger.addHandler(handler)
logger.debug('information')
foo()
and
# additional.py
import logging
logger = logging.getLogger('2')
def foo():
# will be printed with "Log" before it
logger.debug('information from 2nd file')
I am using a class to create logs for a program I am developing. in the log files I am getting duplicate lines. My code is as follows:
import logging
class Log():
def __init__(self,name=''):
self.name='name'
def InitLog(self,name):
self.logger = logging.getLogger(name)
self.hdlr = logging.FileHandler('/'+name+'.log')
self.formatter = logging.Formatter('%(message)s')
self.hdlr.setFormatter(self.formatter)
self.logger.addHandler(self.hdlr)
self.logger.setLevel(logging.INFO)
def E(self,msg):
self.logger.error(msg)
def I(self,msg):
self.logger.info(msg)
Calling the logger:
# Setup Log
log_url_thread_worker=Log()
log_url_thread_worker.InitLog(cyberlocker)
# Logging something
log_url_thread_worker.I(error)
can anyone see if im doing something stupid?
thanks
I will try to resume as much as possible. I have this class I wrote:
Logging class
import logging, logging.handlers.TimedRotatingFileHandler
class Logger(object):
def __init__(self, log_filename):
logging.basicConfig(format='%(asctime)s %(message)s')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
loghandler = TimedRotatingFileHandler(
log_filename, when="midnight", backupCount=50
)
loghandler.setFormatter(formatter)
self.logger = logging.getLogger()
self.logger.setLevel(logging.INFO)
self.logger.addHandler(loghandler)
def getLogger(self):
return self.logger
It works good indeed, now the problem arises when I have a script that uses a Logger instance and within that script I instantiate a class that uses a Logger too, something like this:
Script
import ClassA
A = ClassA()
log = Logger(log_filename='script_logger.log')
logger = log.getLogger()
logger.info('Initiated Script')
while True:
logger.info('Looping')
A.run()
What my class looks like:
ClassA module
class ClassA(object):
def __init__(self):
log = Logger(log_filename='class_logger.log')
self.logger = log.getLogger()
self.logger.info('Started ClassA')
def run(self):
self.logger.info('Into method run')
Now I expect to have 2 separate log files, class_logger.log and script_logger.log that works OK, but both files have exactly the same content line by line.
So script_logger.log and class_logger.log have the following content:
Started classA
Initiated Script
Looping
Into method run
Looping
Into method run
...
Any clues ?
The reason is the class and script have the same logger object when you do logging.getLogger(). It's a singleton. If you want different loggers then you should pass the logger name e.g logging.getLogger('logger1')
Typically libraries do logging.getLogger(__name__) so that each module gets a different logger. refer http://docs.python.org/2/library/logging.html#logger-objects
I have modified your code so that it works as expected now
import logging, logging.handlers
from logging.handlers import TimedRotatingFileHandler
class Logger(object):
def __init__(self, log_filename, name):
logging.basicConfig(format='%(asctime)s %(message)s')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
loghandler = TimedRotatingFileHandler(
log_filename, when="midnight", backupCount=50
)
loghandler.setFormatter(formatter)
self.logger = logging.getLogger(name)
self.logger.setLevel(logging.INFO)
self.logger.addHandler(loghandler)
def getLogger(self):
return self.logger
class ClassA(object):
def __init__(self):
log = Logger(log_filename='class_logger.log', name="Class")
self.logger = log.getLogger()
self.logger.info('Started ClassA')
def run(self):
self.logger.info('Into method run')
A = ClassA()
log = Logger(log_filename='script_logger.log', name="Script")
logger = log.getLogger()
logger.info('Initiated Script')
for x in range(5):
logger.info('Looping')
A.run()
A.py
# logging object
logger = ""
def log():
"""
a log handle
"""
global logger, doc_log
import logging.handlers
logger = logging.getLogger("autons_log")
logger.setLevel(logging.DEBUG)
MAX_SIZE = 800 * 1024 * 1024
LOG_PATH = doc_log + "/autons_log.log"
fh = logging.handlers.RotatingFileHandler(LOG_PATH, maxBytes=MAX_SIZE, backupCount=8)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
def get_log():
"""
get the object of logger
"""
global logger
return logger
and B.py
def hello():
"""
"""
import autons_nc
print autons_nc.get_log()
print type(autons_nc.get_log())
autons_nc.get_log().debug('hello')
I want to use the object of logger in B.py,But this way can't work.
the type of get_log() is "type 'str'" not "class 'logging.Logger'".
So, another way can solve it? Thank you
By the way, autons_nc.py is A.py
You initialise logger to a string:
logger = ""
This is changed in log() to refer to an instance of logging.Logger. You don't say that you're actually calling log() before checking the type of logger -- are you?