2
0

logger.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. """logging facilities
  2. The way to use this is as follows:
  3. * each module declares its own logger, using:
  4. from .logger import create_logger
  5. logger = create_logger()
  6. * then each module uses logger.info/warning/debug/etc according to the
  7. level it believes is appropriate:
  8. logger.debug('debugging info for developers or power users')
  9. logger.info('normal, informational output')
  10. logger.warning('warn about a non-fatal error or sth else')
  11. logger.error('a fatal error')
  12. ... and so on. see the `logging documentation
  13. <https://docs.python.org/3/howto/logging.html#when-to-use-logging>`_
  14. for more information
  15. * console interaction happens on stderr, that includes interactive
  16. reporting functions like `help`, `info` and `list`
  17. * ...except ``input()`` is special, because we can't control the
  18. stream it is using, unfortunately. we assume that it won't clutter
  19. stdout, because interaction would be broken then anyways
  20. * what is output on INFO level is additionally controlled by commandline
  21. flags
  22. """
  23. import inspect
  24. import logging
  25. def setup_logging(stream=None):
  26. """setup logging module according to the arguments provided
  27. this sets up a stream handler logger on stderr (by default, if no
  28. stream is provided).
  29. """
  30. logging.raiseExceptions = False
  31. l = logging.getLogger('')
  32. sh = logging.StreamHandler(stream)
  33. # other formatters will probably want this, but let's remove
  34. # clutter on stderr
  35. # example:
  36. # sh.setFormatter(logging.Formatter('%(name)s: %(message)s'))
  37. l.addHandler(sh)
  38. l.setLevel(logging.INFO)
  39. return sh
  40. def find_parent_module():
  41. """find the name of a the first module calling this module
  42. if we cannot find it, we return the current module's name
  43. (__name__) instead.
  44. """
  45. try:
  46. frame = inspect.currentframe().f_back
  47. module = inspect.getmodule(frame)
  48. while module is None or module.__name__ == __name__:
  49. frame = frame.f_back
  50. module = inspect.getmodule(frame)
  51. return module.__name__
  52. except AttributeError:
  53. # somehow we failed to find our module
  54. # return the logger module name by default
  55. return __name__
  56. def create_logger(name=None):
  57. """create a Logger object with the proper path, which is returned by
  58. find_parent_module() by default, or is provided via the commandline
  59. this is really a shortcut for:
  60. logger = logging.getLogger(__name__)
  61. we use it to avoid errors and provide a more standard API.
  62. """
  63. return logging.getLogger(name or find_parent_module())