I have a question regarding logging module in Python.
If I instantiate a logger and set its level to INFO without adding any handlers, then I expect that info messages will be printed on the screen.
However, in reality, warning messages are printed but info messages are not.
After adding explicitly a handler, both levels are printed.
Precisely, the following small script:
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.info("This is an info message")
logger.warning("This is a warning message")
print("*** Add a stream handler explicitly")
handler = logging.StreamHandler()
logger.addHandler(handler)
logger.info("This is an info message")
logger.warning("This is a warning message")
gives output
This is a warning message
*** Add a stream handler explicitly
This is an info message
This is a warning message
(checked in Python 3.7.6 and 3.8.2).
I would expect that either no messages are printed without a handler, or both levels are printed after setting level to INFO.
I suggest you use loguru. It's a really simple to use tool and for me it's very intuitive.
You can add a default logger just using this line:
from loguru import logger
If you want to change the logging level, just setup the logger like this:
logger.remove() # This disables the default logger
logger.add(sys.stderr, level="INFO") # This adds a default logger (format and colors included) but at the logging level you need
And that's it. All the scripts that use the loguru logger in your code will be set up like this. By default it outputs to stderr but you can change it however you need.
I tried below code only to find that my logs are getting printed in console.
What mistake I am doing here?
import logging
logging.basicConfig(filename="logger.log",
format='%(asctime)s %(message)s',
filemode='w')
logger=logging.getLogger()
logger.setLevel(logging.INFO)
logger.info("An information")
I am running this code as a fastapi project via uvicorn server.
Pass the log level to run method
uvicorn.run("example:app", host='localhost', port=8000, reload=True, log_level='info')
Use logger
from uvicorn.config import logger
logger.info('Your Comment')
I'm using Python 3.4 on Mac OSX. I have the following code to setup a logger:
LOGGER = logging.getLogger(PROGRAM_NAME)
LOGGER.setLevel(logging.DEBUG)
LOGGER.propagate = False
LOGGER_FH = logging.FileHandler(WORKING_DIR + "/syslog.log", 'a')
LOGGER_FH.setLevel(logging.DEBUG)
LOGGER_FH.setFormatter(logging.Formatter('%(name)s: [%(levelname)s] %(message)s'))
LOGGER.addHandler(LOGGER_FH)
LOGGER_SH = logging.handlers.SysLogHandler(address='/var/run/syslog',
facility=logging.handlers.SysLogHandler.LOG_USER)
LOGGER_SH.setLevel(logging.DEBUG)
LOGGER_SH.setFormatter(logging.Formatter('%(name)s: [%(levelname)s] %(message)s'))
LOGGER.addHandler(LOGGER_SH)
The FileHandler works perfectly, and I'm able to see all expected messages at all logging levels show up in the log. The SysLogHandler doesn't work correctly. I'm unable to see any LOGGER.info() or LOGGER.debug() messages in the syslog output. I can see error and warning messages, but not info or debug. Even tweaking the /etc/syslog.conf file has no effect (even after explicitly reloading the syslog daemon with launchctl). What am I missing here ?
Try: address='/dev/log'
It's a bit confusing from the doc, but "address" is expected to be a unix domain socket, not a file.
I am working in linux and the process rsyslogd is listening to port 514.
The following code can't write into /var/log/syslog.
Is anybody know what is the problem?
import logging
import logging.handlers
root_logger = logging.getLogger()
root_logger.setLevel(config.get_value("log_level"))
syslog_hdlr = SysLogHandler(address='/dev/log', facility=SysLogHandler.LOG_DAEMON)
syslog_hdlr.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(name)s: %(levelname)s %(message)s')
syslog_hdlr.setFormatter(formatter)
root_logger.addHandler(syslog_hdlr)
logger = logging.getLogger("imapcd.daemon")
logger.debug('test')
This code works fine in my system if I make some changes:
import logging.handlers as sh
syslog_hdlr = sh.SysLogHandler(address='/dev/log', facility=sh.SysLogHandler.LOG_DAEMON)
and
root_logger.setLevel(logging.DEBUG)
So check the logging level you are getting from config is not more restrictive than DEBUG (ex: if it is set to INFO no debug messages are printed).
If you still don't see anything on syslog try to use the syslog module and see if you get anything from there:
import syslog
syslog.syslog(syslog.LOG_ERR, "MY MESSAGE")
When I log an event with logging.info, it doesn't appear in the Python terminal.
import logging
logging.info('I am info') # no output
In contrast, events logged with logging.warn do appear in the terminal.
import logging
logging.warn('I am warning') # outputs "I am warning"
Is there a environment level change I can to make logging.info print to the console? I want to avoid making changes in each Python file.
The root logger always defaults to WARNING level. Try calling
logging.getLogger().setLevel(logging.INFO)
and you should be fine.
Like #ztyx said that default logger level is WARNING. You have to set it to a lower level
You can do it by using logging.basicConfig and setting logger level:
logging.basicConfig(level=logging.DEBUG)
The above solutions didn't work for me, but the code here did:
# set up logging to file
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
datefmt='%m-%d %H:%M',
filename='/temp/myapp.log',
filemode='w')
# define a Handler which writes INFO messages or higher to the sys.stderr
console = logging.StreamHandler()
console.setLevel(logging.INFO)
# add the handler to the root logger
logging.getLogger('').addHandler(console)
(I omitted parts of the code for the sake of readability)
This will work
import logging
logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.info('its working')
In more recent versions of Python 3 (tested with Python 3.8), console logging requires creating a console handler to correctly show info messages.
The following example is modified from the Configuring Logging example in the Python documentation:
import logging
# create logger
logger = logging.getLogger('__name__')
level = logging.INFO
logger.setLevel(level)
# ----> console info messages require these lines <----
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(level)
# add ch to logger
logger.addHandler(ch)
# -----------------------------------------------------
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
Running the above code generates the following output:
info message
warn message
error message
critical message
Here is this same code without the console handler.
import logging
# create logger
logger = logging.getLogger('__name__')
level = logging.INFO
logger.setLevel(level)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
Without the console handler, the output does not include the info message:
warn message
error message
critical message
I do not understand why this is the case as it seems unnecessary.
What's the minimum required code for a working module-level logger? I did an experiment (with python version 3.8.6).
The take-away is:
logging.basicConfig() is needed (however, specifying level=... is NOT needed)
it's necessary to configure the root logger: logging.getLogger().setLevel(...)
So, a minimum working example is:
The library/module code does NOT need to configure the logger:
# library/module code: lib.py
import logging
LOGGER = logging.getLogger('x.y.z')
def some_function():
LOGGER.info("hi")
The application code need to configure the logger with 2 lines at minimum:
# Application Code
import logging, lib
logging.basicConfig()
logging.getLogger().setLevel(logging.INFO) # configure root logger
main() # code that will trigger lib
Here's the experiment:
In [1]: import logging
In [2]: lg = logging.getLogger('x.y.z')
In [3]: lg.info(1)
In [4]: logging.basicConfig()
In [5]: lg.info(1)
In [6]: logging.basicConfig(level=logging.INFO)
In [7]: lg.info(1)
In [8]: logging.basicConfig()
In [9]: logging.getLogger().setLevel(logging.INFO)
In [10]: lg.info(1)
INFO:x.y.z:1
For those using absl.logging, the equivalent command is
from absl import logging
logging.set_verbosity(logging.INFO)
If you are using Django to power your server, you just simply need to change the log level in your settings.py file as such:
"handlers": {
"console": {
-- "level": "WARNING",
++ "level": "INFO",
"class": "logging.StreamHandler",
"formatter": "stackdriver",
}
},
More examples in the documentation here:
https://docs.djangoproject.com/en/4.0/topics/logging/#configuring-logging-1
logging.info() will use the root logger for logging.
According to official doc,
if you do not set an explicit handler for the logger, a special handler called lastResort will be used.
See the code here. By default the logging level of lastResort (it is stream handler) is 30.
we can change its level to output info message.
# setting both the logger and handler's level will work as expected.
logger.setLevel(logging.DEBUG)
logging.lastResort.setLevel(logging.DEBUG)
However, this is like a hack and never a encouraged action.
Using logging.basicConfig()
If we want to do logging real quick, we can use the method logging.basicConfig.
logging.basicConfig(level=logging.DEBUG)
This will create the logger. The logger.level will be the level we set here.
A stream handler will be also created, with level NOTSET.
Without a level param, the default level for root logger is WARNING.
reference
logger logging without handler: logger logging without a handler