I have this code which works just fine for me.
import logging
import logging.handlers
logger = None
def create_logger():
global logger
logger = logging.getLogger('Logger')
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler("C:/Users/user/Desktop/info.log", maxBytes=1000000, backupCount=20)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
create_logger()
logger.info("Text info")
logger.debug("Text debug")
logger.warning("Text warning")
logger.error("Text error")
logger.critical("Text critical")
And the output looks great:
2017-12-19 15:06:43,021 - Logger - INFO - Text info
2017-12-19 15:06:43,021 - Logger - DEBUG - Text debug
2017-12-19 15:06:43,022 - Logger - WARNING - Text warning
2017-12-19 15:06:43,022 - Logger - ERROR - Text error
2017-12-19 15:06:43,022 - Logger - CRITICAL - Text critical
Well, I want to add a new logging level like this:
logger.message("Text message")
And the output should be like this
2017-12-19 15:06:43,022 - Logger - MESSAGE - Text message
Thanks
Configuring Logging Creating loggers, handlers, and formatters explicitly using Python code that calls the configuration methods listed above. Creating a logging config file and reading it using the fileConfig() function. Creating a dictionary of configuration information and passing it to the dictConfig() function.
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.
You can change the logging level or trace level (also called the debug level) of a running process by sending a USR1 or USR2 signal to the process. Sending a USR1 signal changes the logging level and sending a USR2 signal changes the trace level.
Python Logging Levels There are six log levels in Python; each level is associated with an integer that indicates the log severity: NOTSET=0, DEBUG=10, INFO=20, WARN=30, ERROR=40, and CRITICAL=50.
From Logging documentation (emphasis added):
Defining your own levels is possible, but should not be necessary, as the existing levels have been chosen on the basis of practical experience. However, if you are convinced that you need custom levels, great care should be exercised when doing this, and it is possibly a very bad idea to define custom levels if you are developing a library. That’s because if multiple library authors all define their own custom levels, there is a chance that the logging output from such multiple libraries used together will be difficult for the using developer to control and/or interpret, because a given numeric value might mean different things for different libraries.
An overview of default logging levels:
But if you still want to, you can make your own log level:
In the logging
-module, _levelToName
and _nameToLevel
are mappings between logging names and levels. Instead of manually adding to them, the addLevelName()
function does this for you.
Here, a new logging level called MESSAGE is added with log level 25:
import logging
# Define MESSAGE log level
MESSAGE = 25
# "Register" new loggin level
logging.addLevelName(MESSAGE, 'MESSAGE') # addLevelName(25, 'MESSAGE')
# Verify
assert logging.getLevelName(MESSAGE) == 'MESSAGE'
If you don't want to make your own logger class but still wants to log other log levels, then you can use the Logger.log(level, msg)
-method on the traditional loggers:
logging.log(MESSAGE, 'This is a message')
def message(self, msg, *args, **kwargs):
if self.isEnabledFor(MESSAGE):
self._log(MESSAGE, msg, args, **kwargs)
Make the message()
-function available in logging
:
logging.message = message
# or setattr(logging, 'message', message)
Make the message()
-function available in the logger:
logging.Logger.message = message
# or setattr(logging.Logger, 'message', message)
You could make your own logger class to make a message(msg)
-method, to be used similarily as the others (e.g. info(msg)
, warning(msg)
, etc.)
In the following example, a new logger is made with a message(msg)
-method to log MESSAGE:
class MyLogger(logging.Logger):
def message(self, msg, *args, **kwargs):
if self.isEnabledFor(MESSAGE):
self._log(MESSAGE, msg, args, **kwargs)
I'm not sure of what's the best way to make it work with logging.getLogger(name)
, but below are two approaches.
Ref. comments, I believe the first approach is better:
Either make the new logger the default logging class, which means new logger instances will be of the MyLogger
class instead of the default logging.Logger
class:
logging.setLoggerClass(MyLogger)
logger = logging.getLogger('A new logger name')
logger.message('This seems to work')
assert isInstance(logger, MyLogger)
Or just make an instance of the logger and add it to the loggerDict
in the active logging.Manager
instance (EDIT: not recommended, see comments):
my_logger = MyLogger('Foo')
logging.Logger.manager.loggerDict['Foo'] = my_logger
logger = logging.getLogger('Foo')
logger.message('This is the same instance as my_logger')
assert logger is my_logger
# Use the new logger class
logger.warning('Custom log levels might be a bad idea')
logger.message('Here is a message')
# Log with custom log level:
logger.log(MESSAGE, 'This is a message')
This assumes that MESSAGE
is predefined as an integer numerical value representing the log level. (E.g. 25 as previously mentioned)
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