diff options
Diffstat (limited to 'lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/metrics.py')
-rw-r--r-- | lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/metrics.py | 494 |
1 files changed, 0 insertions, 494 deletions
diff --git a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/metrics.py b/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/metrics.py deleted file mode 100644 index d0f28bb3..00000000 --- a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/metrics.py +++ /dev/null @@ -1,494 +0,0 @@ -# This file is part of Buildbot. Buildbot is free software: you can -# redistribute it and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Copyright Buildbot Team Members - -from __future__ import with_statement -""" -Buildbot metrics module - -Keeps track of counts and timings of various internal buildbot -activities. - -Basic architecture: - - MetricEvent.log(...) - || - \/ - MetricLogObserver - || - \/ - MetricHandler - || - \/ - MetricWatcher -""" -from collections import deque - -from twisted.python import log -from twisted.internet.task import LoopingCall -from twisted.internet import reactor -from twisted.application import service -from buildbot import util, config -from collections import defaultdict - -import gc, os, sys -# Make use of the resource module if we can -try: - import resource - assert resource -except ImportError: - resource = None - -class MetricEvent(object): - @classmethod - def log(cls, *args, **kwargs): - log.msg(metric=cls(*args, **kwargs)) - -class MetricCountEvent(MetricEvent): - def __init__(self, counter, count=1, absolute=False): - self.counter = counter - self.count = count - self.absolute = absolute - -class MetricTimeEvent(MetricEvent): - def __init__(self, timer, elapsed): - self.timer = timer - self.elapsed = elapsed - -ALARM_OK, ALARM_WARN, ALARM_CRIT = range(3) -ALARM_TEXT = ["OK", "WARN", "CRIT"] - -class MetricAlarmEvent(MetricEvent): - def __init__(self, alarm, msg=None, level=ALARM_OK): - self.alarm = alarm - self.level = level - self.msg = msg - -def countMethod(counter): - def decorator(func): - def wrapper(*args, **kwargs): - MetricCountEvent.log(counter=counter) - return func(*args, **kwargs) - return wrapper - return decorator - -class Timer(object): - # For testing - _reactor = None - - def __init__(self, name): - self.name = name - self.started = None - - def startTimer(self, func): - def wrapper(*args, **kwargs): - self.start() - return func(*args, **kwargs) - return wrapper - - def stopTimer(self, func): - def wrapper(*args, **kwargs): - try: - return func(*args, **kwargs) - finally: - self.stop() - return wrapper - - def start(self): - self.started = util.now(self._reactor) - - def stop(self): - if self.started is not None: - elapsed = util.now(self._reactor) - self.started - MetricTimeEvent.log(timer=self.name, elapsed=elapsed) - self.started = None - -def timeMethod(name, _reactor=None): - def decorator(func): - t = Timer(name) - t._reactor=_reactor - def wrapper(*args, **kwargs): - t.start() - try: - return func(*args, **kwargs) - finally: - t.stop() - return wrapper - return decorator - -class FiniteList(deque): - def __init__(self, maxlen=10): - self._maxlen = maxlen - deque.__init__(self) - - def append(self, o): - deque.append(self, o) - if len(self) > self._maxlen: - self.popleft() - -class AveragingFiniteList(FiniteList): - def __init__(self, maxlen=10): - FiniteList.__init__(self, maxlen) - self.average = 0 - - def append(self, o): - FiniteList.append(self, o) - self._calc() - - def _calc(self): - if len(self) == 0: - self.average = 0 - else: - self.average = float(sum(self)) / len(self) - - return self.average - -class MetricHandler(object): - def __init__(self, metrics): - self.metrics = metrics - self.watchers = [] - - self.reset() - - def addWatcher(self, watcher): - self.watchers.append(watcher) - - def removeWatcher(self, watcher): - self.watchers.remove(watcher) - - # For subclasses to define - def reset(self): - raise NotImplementedError - - def handle(self, eventDict, metric): - raise NotImplementedError - - def get(self, metric): - raise NotImplementedError - - def keys(self): - raise NotImplementedError - - def report(self): - raise NotImplementedError - - def asDict(self): - raise NotImplementedError - -class MetricCountHandler(MetricHandler): - _counters = None - def reset(self): - self._counters = defaultdict(int) - - def handle(self, eventDict, metric): - if metric.absolute: - self._counters[metric.counter] = metric.count - else: - self._counters[metric.counter] += metric.count - - def keys(self): - return self._counters.keys() - - def get(self, counter): - return self._counters[counter] - - def report(self): - retval = [] - for counter in sorted(self.keys()): - retval.append("Counter %s: %i" % (counter, self.get(counter))) - return "\n".join(retval) - - def asDict(self): - retval = {} - for counter in sorted(self.keys()): - retval[counter] = self.get(counter) - return dict(counters=retval) - -class MetricTimeHandler(MetricHandler): - _timers = None - def reset(self): - self._timers = defaultdict(AveragingFiniteList) - - def handle(self, eventDict, metric): - self._timers[metric.timer].append(metric.elapsed) - - def keys(self): - return self._timers.keys() - - def get(self, timer): - return self._timers[timer].average - - def report(self): - retval = [] - for timer in sorted(self.keys()): - retval.append("Timer %s: %.3g" % (timer, self.get(timer))) - return "\n".join(retval) - - def asDict(self): - retval = {} - for timer in sorted(self.keys()): - retval[timer] = self.get(timer) - return dict(timers=retval) - -class MetricAlarmHandler(MetricHandler): - _alarms = None - def reset(self): - self._alarms = defaultdict(lambda x: ALARM_OK) - - def handle(self, eventDict, metric): - self._alarms[metric.alarm] = (metric.level, metric.msg) - - def report(self): - retval = [] - for alarm, (level, msg) in sorted(self._alarms.items()): - if msg: - retval.append("%s %s: %s" % (ALARM_TEXT[level], alarm, msg)) - else: - retval.append("%s %s" % (ALARM_TEXT[level], alarm)) - return "\n".join(retval) - - def asDict(self): - retval = {} - for alarm, (level, msg) in sorted(self._alarms.items()): - retval[alarm] = (ALARM_TEXT[level], msg) - return dict(alarms=retval) - -class PollerWatcher(object): - def __init__(self, metrics): - self.metrics = metrics - - def run(self): - # Check if 'BuildMaster.pollDatabaseChanges()' and - # 'BuildMaster.pollDatabaseBuildRequests()' are running fast enough - h = self.metrics.getHandler(MetricTimeEvent) - if not h: - log.msg("Couldn't get MetricTimeEvent handler") - MetricAlarmEvent.log('PollerWatcher', - msg="Coudln't get MetricTimeEvent handler", - level=ALARM_WARN) - return - - for method in ('BuildMaster.pollDatabaseChanges()', - 'BuildMaster.pollDatabaseBuildRequests()'): - t = h.get(method) - master = self.metrics.parent - db_poll_interval = master.config.db['db_poll_interval'] - - if db_poll_interval: - if t < 0.8 * db_poll_interval: - level = ALARM_OK - elif t < db_poll_interval: - level = ALARM_WARN - else: - level = ALARM_CRIT - MetricAlarmEvent.log(method, level=level) - -class AttachedSlavesWatcher(object): - def __init__(self, metrics): - self.metrics = metrics - - def run(self): - # Check if 'BotMaster.attached_slaves' equals - # 'AbstractBuildSlave.attached_slaves' - h = self.metrics.getHandler(MetricCountEvent) - if not h: - log.msg("Couldn't get MetricCountEvent handler") - MetricAlarmEvent.log('AttachedSlavesWatcher', - msg="Coudln't get MetricCountEvent handler", - level=ALARM_WARN) - return - botmaster_count = h.get('BotMaster.attached_slaves') - buildslave_count = h.get('AbstractBuildSlave.attached_slaves') - - # We let these be off by one since they're counted at slightly - # different times - if abs(botmaster_count - buildslave_count) > 1: - level = ALARM_WARN - else: - level = ALARM_OK - - MetricAlarmEvent.log('attached_slaves', - msg='%s %s' % (botmaster_count, buildslave_count), - level=level) - -def _get_rss(): - if sys.platform == 'linux2': - try: - with open("/proc/%i/statm" % os.getpid()) as f: - return int(f.read().split()[1]) - except: - return 0 - return 0 - -def periodicCheck(_reactor=reactor): - try: - # Measure how much garbage we have - garbage_count = len(gc.garbage) - MetricCountEvent.log('gc.garbage', garbage_count, absolute=True) - if garbage_count == 0: - level = ALARM_OK - else: - level = ALARM_WARN - MetricAlarmEvent.log('gc.garbage', level=level) - - if resource: - r = resource.getrusage(resource.RUSAGE_SELF) - attrs = ['ru_utime', 'ru_stime', 'ru_maxrss', 'ru_ixrss', 'ru_idrss', - 'ru_isrss', 'ru_minflt', 'ru_majflt', 'ru_nswap', - 'ru_inblock', 'ru_oublock', 'ru_msgsnd', 'ru_msgrcv', - 'ru_nsignals', 'ru_nvcsw', 'ru_nivcsw'] - for i,a in enumerate(attrs): - # Linux versions prior to 2.6.32 didn't report this value, but we - # can calculate it from /proc/<pid>/statm - v = r[i] - if a == 'ru_maxrss' and v == 0: - v = _get_rss() * resource.getpagesize() / 1024 - MetricCountEvent.log('resource.%s' % a, v, absolute=True) - MetricCountEvent.log('resource.pagesize', resource.getpagesize(), absolute=True) - # Measure the reactor delay - then = util.now(_reactor) - dt = 0.1 - def cb(): - now = util.now(_reactor) - delay = (now - then) - dt - MetricTimeEvent.log("reactorDelay", delay) - _reactor.callLater(dt, cb) - except Exception: - log.err(None, "while collecting VM metrics") - -class MetricLogObserver(config.ReconfigurableServiceMixin, - service.MultiService): - _reactor = reactor - def __init__(self): - service.MultiService.__init__(self) - self.setName('metrics') - - self.enabled = False - self.periodic_task = None - self.periodic_interval = None - self.log_task = None - self.log_interval = None - - # Mapping of metric type to handlers for that type - self.handlers = {} - - # Register our default handlers - self.registerHandler(MetricCountEvent, MetricCountHandler(self)) - self.registerHandler(MetricTimeEvent, MetricTimeHandler(self)) - self.registerHandler(MetricAlarmEvent, MetricAlarmHandler(self)) - - # Make sure our changes poller is behaving - self.getHandler(MetricTimeEvent).addWatcher(PollerWatcher(self)) - self.getHandler(MetricCountEvent).addWatcher( - AttachedSlavesWatcher(self)) - - def reconfigService(self, new_config): - # first, enable or disable - if new_config.metrics is None: - self.disable() - else: - self.enable() - - metrics_config = new_config.metrics - - # Start up periodic logging - log_interval = metrics_config.get('log_interval', 60) - if log_interval != self.log_interval: - if self.log_task: - self.log_task.stop() - self.log_task = None - if log_interval: - self.log_task = LoopingCall(self.report) - self.log_task.clock = self._reactor - self.log_task.start(log_interval) - - # same for the periodic task - periodic_interval = metrics_config.get('periodic_interval', 10) - if periodic_interval != self.periodic_interval: - if self.periodic_task: - self.periodic_task.stop() - self.periodic_task = None - if periodic_interval: - self.periodic_task = LoopingCall(periodicCheck, - self._reactor) - self.periodic_task.clock = self._reactor - self.periodic_task.start(periodic_interval) - - # upcall - return config.ReconfigurableServiceMixin.reconfigService(self, - new_config) - - def stopService(self): - self.disable() - service.MultiService.stopService(self) - - def enable(self): - if self.enabled: - return - log.addObserver(self.emit) - self.enabled = True - - def disable(self): - if not self.enabled: - return - - if self.periodic_task: - self.periodic_task.stop() - self.periodic_task = None - - if self.log_task: - self.log_task.stop() - self.log_task = None - - log.removeObserver(self.emit) - self.enabled = False - - def registerHandler(self, interface, handler): - old = self.getHandler(interface) - self.handlers[interface] = handler - return old - - def getHandler(self, interface): - return self.handlers.get(interface) - - def emit(self, eventDict): - # Ignore non-statistic events - metric = eventDict.get('metric') - if not metric or not isinstance(metric, MetricEvent): - return - - if metric.__class__ not in self.handlers: - return - - h = self.handlers[metric.__class__] - h.handle(eventDict, metric) - for w in h.watchers: - w.run() - - def asDict(self): - retval = {} - for interface, handler in self.handlers.iteritems(): - retval.update(handler.asDict()) - return retval - - def report(self): - try: - for interface, handler in self.handlers.iteritems(): - report = handler.report() - if not report: - continue - for line in report.split("\n"): - log.msg(line) - except: - log.err(None, "generating metric report") |