@cryptotaxi247 / netdata-1 / commits / d2f800058

loggers classes added

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