logger.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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('some intricate details you usually do not care about')
  9. logger.info('verbose progress information')
  10. logger.warning('some non-error condition that must always be reported')
  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. * advanced verbosity filters, based on what i described in
  21. https://github.com/borgbackup/borg/pull/233#issuecomment-145100222
  22. may eventually be implemented
  23. """
  24. import inspect
  25. import logging
  26. import sys
  27. def setup_logging(args, stream=None):
  28. """setup logging module according to the arguments provided
  29. this sets up a stream handler logger on stderr (by default, if no
  30. stream is provided) and verbosity levels.
  31. """
  32. logging.raiseExceptions = False
  33. l = logging.getLogger('')
  34. sh = logging.StreamHandler(stream)
  35. # other formatters will probably want this, but let's remove
  36. # clutter on stderr
  37. # example:
  38. # sh.setFormatter(logging.Formatter('%(name)s: %(message)s'))
  39. l.addHandler(sh)
  40. levels = {None: logging.WARNING,
  41. 0: logging.WARNING,
  42. 1: logging.INFO,
  43. 2: logging.DEBUG}
  44. # default to WARNING, -v goes to INFO and -vv to DEBUG
  45. l.setLevel(levels[args.verbose])
  46. return sh,
  47. def find_parent_module():
  48. """find the name of a the first module calling this module
  49. if we cannot find it, we return the current module's name
  50. (__name__) instead.
  51. """
  52. try:
  53. frame = inspect.currentframe().f_back
  54. module = inspect.getmodule(frame)
  55. while module is None or module.__name__ == __name__:
  56. frame = frame.f_back
  57. module = inspect.getmodule(frame)
  58. return module.__name__
  59. except AttributeError:
  60. # somehow we failed to find our module
  61. # return the logger module name by default
  62. return __name__
  63. def create_logger(name=None):
  64. """create a Logger object with the proper path, which is returned by
  65. find_parent_module() by default, or is provided via the commandline
  66. this is really a shortcut for:
  67. logger = logging.getLogger(__name__)
  68. we use it to avoid errors and provide a more standard API.
  69. """
  70. return logging.getLogger(name or find_parent_module())