Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

log.py 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. from __future__ import absolute_import
  2. import logging
  3. import numbers
  4. import os
  5. import sys
  6. from logging.handlers import WatchedFileHandler
  7. from .five import string_t
  8. from .utils import cached_property
  9. from .utils.encoding import safe_repr, safe_str
  10. from .utils.functional import maybe_evaluate
  11. __all__ = ['LogMixin', 'LOG_LEVELS', 'get_loglevel', 'setup_logging']
  12. try:
  13. LOG_LEVELS = dict(logging._nameToLevel)
  14. LOG_LEVELS.update(logging._levelToName)
  15. except AttributeError:
  16. LOG_LEVELS = dict(logging._levelNames)
  17. LOG_LEVELS.setdefault('FATAL', logging.FATAL)
  18. LOG_LEVELS.setdefault(logging.FATAL, 'FATAL')
  19. DISABLE_TRACEBACKS = os.environ.get('DISABLE_TRACEBACKS')
  20. class NullHandler(logging.Handler):
  21. def emit(self, record):
  22. pass
  23. def get_logger(logger):
  24. if isinstance(logger, string_t):
  25. logger = logging.getLogger(logger)
  26. if not logger.handlers:
  27. logger.addHandler(NullHandler())
  28. return logger
  29. def get_loglevel(level):
  30. if isinstance(level, string_t):
  31. return LOG_LEVELS[level]
  32. return level
  33. def naive_format_parts(fmt):
  34. parts = fmt.split('%')
  35. for i, e in enumerate(parts[1:]):
  36. yield None if not e or not parts[i - 1] else e[0]
  37. def safeify_format(fmt, args,
  38. filters={'s': safe_str,
  39. 'r': safe_repr}):
  40. for index, type in enumerate(naive_format_parts(fmt)):
  41. filt = filters.get(type)
  42. yield filt(args[index]) if filt else args[index]
  43. class LogMixin(object):
  44. def debug(self, *args, **kwargs):
  45. return self.log(logging.DEBUG, *args, **kwargs)
  46. def info(self, *args, **kwargs):
  47. return self.log(logging.INFO, *args, **kwargs)
  48. def warn(self, *args, **kwargs):
  49. return self.log(logging.WARN, *args, **kwargs)
  50. def error(self, *args, **kwargs):
  51. return self._error(logging.ERROR, *args, **kwargs)
  52. def critical(self, *args, **kwargs):
  53. return self._error(logging.CRITICAL, *args, **kwargs)
  54. def _error(self, severity, *args, **kwargs):
  55. kwargs.setdefault('exc_info', True)
  56. if DISABLE_TRACEBACKS:
  57. kwargs.pop('exc_info', None)
  58. return self.log(severity, *args, **kwargs)
  59. def annotate(self, text):
  60. return '%s - %s' % (self.logger_name, text)
  61. def log(self, severity, *args, **kwargs):
  62. if self.logger.isEnabledFor(severity):
  63. log = self.logger.log
  64. if len(args) > 1 and isinstance(args[0], string_t):
  65. expand = [maybe_evaluate(arg) for arg in args[1:]]
  66. return log(severity,
  67. self.annotate(args[0].replace('%r', '%s')),
  68. *list(safeify_format(args[0], expand)), **kwargs)
  69. else:
  70. return self.logger.log(
  71. severity, self.annotate(' '.join(map(safe_str, args))),
  72. **kwargs)
  73. def get_logger(self):
  74. return get_logger(self.logger_name)
  75. def is_enabled_for(self, level):
  76. return self.logger.isEnabledFor(self.get_loglevel(level))
  77. def get_loglevel(self, level):
  78. if not isinstance(level, numbers.Integral):
  79. return LOG_LEVELS[level]
  80. return level
  81. @cached_property
  82. def logger(self):
  83. return self.get_logger()
  84. @property
  85. def logger_name(self):
  86. return self.__class__.__name__
  87. class Log(LogMixin):
  88. def __init__(self, name, logger=None):
  89. self._logger_name = name
  90. self._logger = logger
  91. def get_logger(self):
  92. if self._logger:
  93. return self._logger
  94. return LogMixin.get_logger(self)
  95. @property
  96. def logger_name(self):
  97. return self._logger_name
  98. def setup_logging(loglevel=None, logfile=None):
  99. logger = logging.getLogger()
  100. loglevel = get_loglevel(loglevel or 'ERROR')
  101. logfile = logfile if logfile else sys.__stderr__
  102. if not logger.handlers:
  103. if hasattr(logfile, 'write'):
  104. handler = logging.StreamHandler(logfile)
  105. else:
  106. handler = WatchedFileHandler(logfile)
  107. logger.addHandler(handler)
  108. logger.setLevel(loglevel)
  109. return logger