loggers.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. # -*- coding: utf-8 -*-
  2. # Description:
  3. # Author: Ilya Mashchenko (ilyam8)
  4. # SPDX-License-Identifier: GPL-3.0-or-later
  5. import logging
  6. import traceback
  7. from sys import exc_info
  8. try:
  9. from time import monotonic as time
  10. except ImportError:
  11. from time import time
  12. from bases.collection import on_try_except_finally, unicode_str
  13. LOGGING_LEVELS = {'CRITICAL': 50,
  14. 'ERROR': 40,
  15. 'WARNING': 30,
  16. 'INFO': 20,
  17. 'DEBUG': 10,
  18. 'NOTSET': 0}
  19. DEFAULT_LOG_LINE_FORMAT = '%(asctime)s: %(name)s %(levelname)s : %(message)s'
  20. DEFAULT_LOG_TIME_FORMAT = '%Y-%m-%d %H:%M:%S'
  21. PYTHON_D_LOG_LINE_FORMAT = '%(asctime)s: %(name)s %(levelname)s: %(module_name)s[%(job_name)s] : %(message)s'
  22. PYTHON_D_LOG_NAME = 'python.d'
  23. def limiter(log_max_count=30, allowed_in_seconds=60):
  24. def on_decorator(func):
  25. def on_call(*args):
  26. current_time = args[0]._runtime_counters.start_mono
  27. lc = args[0]._logger_counters
  28. if lc.logged and lc.logged % log_max_count == 0:
  29. if current_time - lc.time_to_compare <= allowed_in_seconds:
  30. lc.dropped += 1
  31. return
  32. lc.time_to_compare = current_time
  33. lc.logged += 1
  34. func(*args)
  35. return on_call
  36. return on_decorator
  37. def add_traceback(func):
  38. def on_call(*args):
  39. self = args[0]
  40. if not self.log_traceback:
  41. func(*args)
  42. else:
  43. if exc_info()[0]:
  44. func(*args)
  45. func(self, traceback.format_exc())
  46. else:
  47. func(*args)
  48. return on_call
  49. class LoggerCounters:
  50. def __init__(self):
  51. self.logged = 0
  52. self.dropped = 0
  53. self.time_to_compare = time()
  54. def __repr__(self):
  55. return 'LoggerCounter(logged: {logged}, dropped: {dropped})'.format(logged=self.logged,
  56. dropped=self.dropped)
  57. class BaseLogger(object):
  58. def __init__(self, logger_name, log_fmt=DEFAULT_LOG_LINE_FORMAT, date_fmt=DEFAULT_LOG_TIME_FORMAT,
  59. handler=logging.StreamHandler):
  60. """
  61. :param logger_name: <str>
  62. :param log_fmt: <str>
  63. :param date_fmt: <str>
  64. :param handler: <logging handler>
  65. """
  66. self.logger = logging.getLogger(logger_name)
  67. if not self.has_handlers():
  68. self.severity = 'INFO'
  69. self.logger.addHandler(handler())
  70. self.set_formatter(fmt=log_fmt, date_fmt=date_fmt)
  71. def __repr__(self):
  72. return '<Logger: {name})>'.format(name=self.logger.name)
  73. def set_formatter(self, fmt, date_fmt=DEFAULT_LOG_TIME_FORMAT):
  74. """
  75. :param fmt: <str>
  76. :param date_fmt: <str>
  77. :return:
  78. """
  79. if self.has_handlers():
  80. self.logger.handlers[0].setFormatter(logging.Formatter(fmt=fmt, datefmt=date_fmt))
  81. def has_handlers(self):
  82. return self.logger.handlers
  83. @property
  84. def severity(self):
  85. return self.logger.getEffectiveLevel()
  86. @severity.setter
  87. def severity(self, level):
  88. """
  89. :param level: <str> or <int>
  90. :return:
  91. """
  92. if level in LOGGING_LEVELS:
  93. self.logger.setLevel(LOGGING_LEVELS[level])
  94. def debug(self, *msg, **kwargs):
  95. self.logger.debug(' '.join(map(unicode_str, msg)), **kwargs)
  96. def info(self, *msg, **kwargs):
  97. self.logger.info(' '.join(map(unicode_str, msg)), **kwargs)
  98. def warning(self, *msg, **kwargs):
  99. self.logger.warning(' '.join(map(unicode_str, msg)), **kwargs)
  100. def error(self, *msg, **kwargs):
  101. self.logger.error(' '.join(map(unicode_str, msg)), **kwargs)
  102. def alert(self, *msg, **kwargs):
  103. self.logger.critical(' '.join(map(unicode_str, msg)), **kwargs)
  104. @on_try_except_finally(on_finally=(exit, 1))
  105. def fatal(self, *msg, **kwargs):
  106. self.logger.critical(' '.join(map(unicode_str, msg)), **kwargs)
  107. class PythonDLogger(object):
  108. def __init__(self, logger_name=PYTHON_D_LOG_NAME, log_fmt=PYTHON_D_LOG_LINE_FORMAT):
  109. """
  110. :param logger_name: <str>
  111. :param log_fmt: <str>
  112. """
  113. self.logger = BaseLogger(logger_name, log_fmt=log_fmt)
  114. self.module_name = 'plugin'
  115. self.job_name = 'main'
  116. self._logger_counters = LoggerCounters()
  117. _LOG_TRACEBACK = False
  118. @property
  119. def log_traceback(self):
  120. return PythonDLogger._LOG_TRACEBACK
  121. @log_traceback.setter
  122. def log_traceback(self, value):
  123. PythonDLogger._LOG_TRACEBACK = value
  124. def debug(self, *msg):
  125. self.logger.debug(*msg, extra={'module_name': self.module_name,
  126. 'job_name': self.job_name or self.module_name})
  127. def info(self, *msg):
  128. self.logger.info(*msg, extra={'module_name': self.module_name,
  129. 'job_name': self.job_name or self.module_name})
  130. def warning(self, *msg):
  131. self.logger.warning(*msg, extra={'module_name': self.module_name,
  132. 'job_name': self.job_name or self.module_name})
  133. @add_traceback
  134. def error(self, *msg):
  135. self.logger.error(*msg, extra={'module_name': self.module_name,
  136. 'job_name': self.job_name or self.module_name})
  137. @add_traceback
  138. def alert(self, *msg):
  139. self.logger.alert(*msg, extra={'module_name': self.module_name,
  140. 'job_name': self.job_name or self.module_name})
  141. def fatal(self, *msg):
  142. self.logger.fatal(*msg, extra={'module_name': self.module_name,
  143. 'job_name': self.job_name or self.module_name})
  144. class PythonDLimitedLogger(PythonDLogger):
  145. @limiter()
  146. def info(self, *msg):
  147. PythonDLogger.info(self, *msg)
  148. @limiter()
  149. def warning(self, *msg):
  150. PythonDLogger.warning(self, *msg)
  151. @limiter()
  152. def error(self, *msg):
  153. PythonDLogger.error(self, *msg)
  154. @limiter()
  155. def alert(self, *msg):
  156. PythonDLogger.alert(self, *msg)