3

When importing an external package such as open3d that uses Pythons logging functionality, my own logging gets printed twice.

See this example:

import logging
import open3d as o3d

logger = logging.getLogger(__name__)


def main():
    # set base level of logger on a module level
    logger.setLevel(logging.DEBUG) 
    # create file handler which logs even debug messages
    fh = logging.FileHandler('log.log')
    fh.setLevel(logging.DEBUG)
    # create console handler with a higher log level
    ch = logging.StreamHandler()
    ch.setLevel(logging.INFO)
    # create formatter and add it to the handlers
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)
    # add the handlers to the logger
    logger.addHandler(fh)
    logger.addHandler(ch)


    logger.info('This gets printed twice to console and once to log file.')


if __name__=="__main__":
    main()

Console output:

2022-03-29 15:06:20,533 - __main__ - INFO - This gets printed twice to console and once to log file.
INFO - 2022-03-29 15:06:20,533 - test - This gets printed twice to console and once to log file.

What would be the standard way to handle such a case where a logger exists in a external package? Is there a possibility to catch the logger from open3d and incorporate its messages into my own logger? Can I mute it altogether? Thanks for the help!

Solution that worked for me:
With the hint from @Cargo23's answer and the help of this question, I was able to inspect all the loggers and handlers and found a StreamHandler in the RootLogger. With these lines just after the imports I was able to remove it:

rootlogger = logging.getLogger() 
rootlogger.handlers.pop() 

Although, I am not fully satisfied with this solution, as it does not seem very generic.

grisly
  • 41
  • 4

1 Answers1

1

The short answer is, yes you can. Its always been a hassle when I've done this, but here are some guide posts:

The logging library has lists of the active loggers, formatters, and handlers that you can access.

Ultimately, you want to remove the handler that your library is adding. I think that the handler can be attached to their logger and/or the root logger.

I think you can even just remove all the handlers and then add your own back in.

Hope it helps!

Cargo23
  • 3,064
  • 16
  • 25
  • 1
    OK thanks, that pointed me in the right direction. With the help of [this](https://stackoverflow.com/questions/3630774/logging-remove-inspect-modify-handlers-configured-by-fileconfig) post I was able to inspect all the loggers and handlers and found a StreamHandler in the RootLogger. With these lines just after the imports I was able to remove it: `rootlogger = logging.getLogger()` `rootlogger.handlers.pop()` All in all, this still feels a bit hacky though. – grisly Mar 29 '22 at 14:21
  • Agreed, I think that libraries are discouraged from adding their own handlers for this reason. Can you upvote my answer if it was helpful? – Cargo23 Mar 29 '22 at 14:58