148

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.

vvvvv
  • 25,404
  • 19
  • 49
  • 81
daydreamer
  • 87,243
  • 191
  • 450
  • 722

9 Answers9

217

The root logger always defaults to WARNING level. Try calling

logging.getLogger().setLevel(logging.INFO)

and you should be fine.

Ztyx
  • 14,100
  • 15
  • 78
  • 114
  • this works well, but I think I will have to change it in every python file I have right? there is no global setting for LOGGING – daydreamer Jul 19 '12 at 13:29
  • 1
    No, you only need to call it once. The logger is built as a hierarchy with and all logging boils down to a *root logger*. By not specifying any argument to `getLogger()`, it is returning you the root logger. As long as you don't modify the other loggers you only need to modify the root logger. – Ztyx Sep 24 '12 at 21:14
  • 25
    Do you know why logging.basicConfig(level=logging.INFO) doesn't work? I can't see it clearly on the documentation. – Doppelganger Dec 24 '12 at 12:30
  • Isn't `logging.basicConfig(level=logging.INFO)` the preferred way to do that? – Jacktose Mar 06 '18 at 18:57
  • 1
    @P1h3r1e3d13 If you only have a single root logger that's likely best-practises, yes. – Ztyx Mar 07 '18 at 17:49
  • 19
    This Does not work on Python 3.5: `Python 3.5.2 (default, Nov 12 2018, 13:43:14)` `[GCC 5.4.0 20160609] on linux` `>>> import logging` `>>> rootLog = logging.getLogger()` `>>> rootLog.setLevel(logging.INFO)` `>>> rootLog.info('all the kings horses')` `>>> rootLog.warning('all the kings men')` `all the kings men` – Jeff K Apr 18 '19 at 18:55
  • 2
    FWIW, this post explains why the root logger and logging module level method calls are best avoided: https://www.electricmonk.nl/log/2017/08/06/understanding-pythons-logging-module/ The tl;dr is: "Don’t log directly against the root logger. That means: no logging.basicConfig() and no usage of module-level loggers such as logging.warning(), as they have unintended side-effects." – Owen May 13 '19 at 17:28
  • 17
    @jeffk, same with me 3.6.8 doesn't print info messages even when setLevel is set to logging.INFO – Robert Lugg Feb 14 '20 at 20:20
  • 1
    @RobertLugg Same here in 3.7, set my logger to logging.INFO and nothing is showing up unless I use logger.warning() – Amundeep Singh Jun 25 '20 at 00:41
  • Use "root" to actually set the root. I.E. "logging.root.setLevel(logging.NOTSET)" – Sirmabus Sep 09 '20 at 05:38
  • Will this method have unintended consequences? I'm just afraid that reconfiguring root logger after having child loggers is not the best idea. I'm not well-versed in python's logging, – Nuclear03020704 Apr 11 '21 at 08:09
  • This will not work for Python 3.2 and later, since root logger without explict handlers will use the logging.lastResort handler and its level is WARNING. See also the official doc: https://docs.python.org/3/howto/logging.html#what-happens-if-no-configuration-is-provided. – jdhao May 27 '22 at 07:37
  • Sometimes defining a stream helps: `logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)` – Alexander C Feb 22 '23 at 21:39
49

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)
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
  • 12
    I'm wondering why `basicConfig()` doesn't work for me, although `logging.getLogger().setLevel()` suitably work? – Shayan Amani Jun 20 '19 at 14:33
  • 5
    @ShayanAmani - According to the documentation, "This function does nothing if the root logger already has handlers configured, unless the keyword argument force is set to True." – vy32 Mar 18 '21 at 00:59
30

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)

Orly
  • 400
  • 3
  • 5
  • 1
    This is the only thing that worked for me. I had a line with `logging.error("Connection timed out!")` and even with the `level=logging.DEBUG` in the `basicConfig()`, it wouldn't print to console. Adding the handler did, thanks so much!! – BruceWayne Mar 21 '19 at 17:52
  • Keep in mind that the handler you are using is playing a role. If, for example, your code had the NullHandler, nothing would be printed regardless of the logging lever. – George Apr 15 '19 at 01:32
  • Same here - if i omit the level argument in `basicConfig` or set it above INFO then the console logger will never log anything. If i leave out `basicConfig` then i can call `setLevel` on a logger all day (and i can see the level change by calling `getEffectiveLevel`) but it will never log anything below `WARNING` level. I'm not actually sure that that isnt the correct behaviour but its not what I was expecting. – Hal Apr 23 '20 at 22:59
16

This will work

import logging

logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

logger.info('its working')
Deepak Chauhan
  • 782
  • 7
  • 10
6

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.

Steven C. Howell
  • 16,902
  • 15
  • 72
  • 97
4

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
KFL
  • 17,162
  • 17
  • 65
  • 89
0

For those using absl.logging, the equivalent command is

from absl import logging
logging.set_verbosity(logging.INFO)
Bremsstrahlung
  • 686
  • 1
  • 9
  • 23
0

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

Danny Vu
  • 101
  • 2
  • 2
0

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

jdhao
  • 24,001
  • 18
  • 134
  • 273