aboutsummaryrefslogtreecommitdiffstats
path: root/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/process/metrics.py
diff options
context:
space:
mode:
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.py494
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")