Skip to content

[Bug]: matplotlib.set_loglevel() adds a console handler #23646

Closed

Description

@l-johnston

Bug summary

matplotlib.set_loglevel() adds a logging console handler which then leads to duplicate messages in application code. The best practice is to allow the application code to add the handlers to its logger along with formatting, filtering, etc. The existing #13264 attempted to address this.

Code for reproduction

import logging
import matplotlib as mpl
mpl_logger = logging.getLogger("matplotlib")
mpl.set_loglevel("debug")
mpl_logger.hasHandlers()
logger = logging.getLogger()
ch = logging.StreamHandler()
logger.addHandler(ch)
logger.setLevel(logging.DEBUG)
import matplotlib.pyplot as plt

Actual outcome

True
DEBUG:matplotlib:CACHEDIR=C:\Users\ljohnsto.matplotlib
CACHEDIR=C:\Users\ljohnsto.matplotlib
DEBUG:matplotlib.font_manager:Using fontManager instance from C:\Users\ljohnsto.matplotlib\fontlist-v330.json
Using fontManager instance from C:\Users\ljohnsto.matplotlib\fontlist-v330.json

Expected outcome

False
CACHEDIR=C:\Users\ljohnsto.matplotlib
Using fontManager instance from C:\Users\ljohnsto.matplotlib\fontlist-v330.json

Additional information

The workaround is:

In [1]: import logging
In [2]: import matplotlib as mpl
In [3]: mpl_logger = logging.getLogger("matplotlib")
In [4]: mpl.set_loglevel("debug")
In [5]: mpl_logger_handlers = mpl_logger.handlers.copy()
In [6]: for h in mpl_logger_handlers:
   ...:     mpl_logger.removeHandler(h)
   ...:
In [7]: logger = logging.getLogger()
In [8]: ch = logging.StreamHandler()
In [9]: logger.addHandler(ch)
In [10]: logger.setLevel(logging.DEBUG)
In [11]: import matplotlib.pyplot as plt
CACHEDIR=C:\Users\ljohnsto\.matplotlib
Using fontManager instance from C:\Users\ljohnsto\.matplotlib\fontlist-v330.json
'''

### Operating system

Windows

### Matplotlib Version

3.5.2

### Matplotlib Backend

TkAgg

### Python version

3.9.13

### Jupyter version

_No response_

### Installation

pip

Activity

  1. jklymak commented on Aug 17, 2022

    @jklymak
    Member

    Yes agreed. But set_loglevel is meant to be a helper for endusers (eg our application) versus for downstream applications. Set matplotlibs log levels using the logging library if you have a downstream application.

  2. l-johnston commented on Aug 19, 2022

    @l-johnston
    ContributorAuthor

    @jklymak

    • The documentation for matplotlib.set_loglevel() doesn't indicate that Matplotlib is using the standard library logging. So, I thought I had to opt-in to get logging information through this function call.
    • It appears to me that the top level module matplotlib represents the library and matplotlib.pyplot represents the application - is this correct?
    • If so, perhaps move set_loglevel() to pyplot and provide a documentation section for logging generally.
  3. jklymak commented on Aug 19, 2022

    @jklymak
    Member

    A link to the standard logging library would make sense. I don't really see the point of a deprecation cycle for the top-level set_loglevel - it is already also exposed as pyplot.set_loglevel.

  4. tacaswell commented on Aug 19, 2022

    @tacaswell
    Member

    The documentation for matplotlib.set_loglevel() doesn't indicate that Matplotlib is using the standard library logging. So, I thought I had to opt-in to get logging information through this function call.

    fair, will open a PR to fix that. I'm also thinking about adding a keyword arguement to opt-opt of us trying to install a handler.

    It appears to me that the top level module matplotlib represents the library and matplotlib.pyplot represents the application - is this correct?

    We have not articulated in so many words, but this seems right. Historically the distinction has been a bit fuzzy, but we are slowly pushing things towards this state.

  5. added this to the v3.7.0 milestone on Aug 19, 2022
  6. tacaswell commented on Oct 20, 2022

    @tacaswell
    Member
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions