logger.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import logging
  2. import os
  3. import sys
  4. import colorama
  5. def to_bool(arg):
  6. '''
  7. Return a boolean value based on `arg`.
  8. '''
  9. if arg is None or isinstance(arg, bool):
  10. return arg
  11. if isinstance(arg, str):
  12. arg = arg.lower()
  13. if arg in ('yes', 'on', '1', 'true', 1):
  14. return True
  15. return False
  16. def interactive_console():
  17. '''
  18. Return whether the current console is "interactive". Meaning: Capable of
  19. user input and not just something like a cron job.
  20. '''
  21. return sys.stdout.isatty() and os.environ.get('TERM') != 'dumb'
  22. def should_do_markup(no_color, configs):
  23. '''
  24. Given the value of the command-line no-color argument, and a dict of configuration filename to
  25. corresponding parsed configuration, determine if we should enable colorama marking up.
  26. '''
  27. if no_color:
  28. return False
  29. if any(config.get('output', {}).get('color') is False for config in configs.values()):
  30. return False
  31. py_colors = os.environ.get('PY_COLORS', None)
  32. if py_colors is not None:
  33. return to_bool(py_colors)
  34. return interactive_console()
  35. LOG_LEVEL_TO_COLOR = {
  36. logging.CRITICAL: colorama.Fore.RED,
  37. logging.ERROR: colorama.Fore.RED,
  38. logging.WARN: colorama.Fore.YELLOW,
  39. logging.INFO: colorama.Fore.GREEN,
  40. logging.DEBUG: colorama.Fore.CYAN,
  41. }
  42. class Console_color_formatter(logging.Formatter):
  43. def format(self, record):
  44. color = LOG_LEVEL_TO_COLOR.get(record.levelno)
  45. return color_text(color, record.msg)
  46. def color_text(color, message):
  47. '''
  48. Give colored text.
  49. '''
  50. if not color:
  51. return message
  52. return '{}{}{}'.format(color, message, colorama.Style.RESET_ALL)
  53. def configure_logging(console_log_level, syslog_log_level=None):
  54. '''
  55. Configure logging to go to both the console and syslog. Use the given log levels, respectively.
  56. '''
  57. if syslog_log_level is None:
  58. syslog_log_level = console_log_level
  59. console_handler = logging.StreamHandler()
  60. console_handler.setFormatter(Console_color_formatter())
  61. console_handler.setLevel(console_log_level)
  62. syslog_path = None
  63. if os.path.exists('/dev/log'):
  64. syslog_path = '/dev/log'
  65. elif os.path.exists('/var/run/syslog'):
  66. syslog_path = '/var/run/syslog'
  67. if syslog_path and not interactive_console():
  68. syslog_handler = logging.handlers.SysLogHandler(address=syslog_path)
  69. syslog_handler.setFormatter(logging.Formatter('borgmatic: %(levelname)s %(message)s'))
  70. syslog_handler.setLevel(syslog_log_level)
  71. handlers = (console_handler, syslog_handler)
  72. else:
  73. handlers = (console_handler,)
  74. logging.basicConfig(level=min(console_log_level, syslog_log_level), handlers=handlers)