Mark Bergsma has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/371636 )
Change subject: Instrument the Twisted reactor with Prometheus metrics ...................................................................... Instrument the Twisted reactor with Prometheus metrics instrumented_reactor adds InstrumentedReactor which derives from either the EPollReactor or SelectReactor (depending on availability on the platform), and decorates the most important methods with Prometheus timing metrics. Change-Id: Ie7cccd14687808b1c4d4a224d82b8b4ed8d0cbce --- M pybal/__init__.py A pybal/instrumented_reactor.py M pybal/metrics.py 3 files changed, 94 insertions(+), 5 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/operations/debs/pybal refs/changes/36/371636/1 diff --git a/pybal/__init__.py b/pybal/__init__.py index ade8bc3..a6418e7 100644 --- a/pybal/__init__.py +++ b/pybal/__init__.py @@ -4,6 +4,11 @@ The pybal package contains all PyBal modules """ + +# Use our own instrumented epoll reactor +from pybal import instrumented_reactor +instrumented_reactor.install() + import test from .version import * diff --git a/pybal/instrumented_reactor.py b/pybal/instrumented_reactor.py new file mode 100644 index 0000000..7cc0ac2 --- /dev/null +++ b/pybal/instrumented_reactor.py @@ -0,0 +1,64 @@ +""" +reactor.py + +An instrumented reactor (epoll or select). +To install the reactor (and you should do this before any connections, +listeners or connectors are added):: + + from pybal import instrumented_reactor + instrumented_reactor.install() +""" + +from pybal.metrics import Summary + +try: + from twisted.internet.epollreactor import EPollReactor + ancestor = EPollReactor +except ImportError: + from twisted.internet.selectreactor import SelectReactor + ancestor = SelectReactor + +class InstrumentedReactor(ancestor): + metric_keywords = { + 'namespace': 'pybal', + 'subsystem': 'reactor' + } + metrics = { + 'iteration_duration': + Summary( + 'iteration_duration', + 'Reactor iteration latency', + **metric_keywords), + 'do_read_or_write_duration': + Summary( + 'do_read_or_write_duration', + 'doReadOrWrite latency', + labelnames=('selectable', 'method'), + **metric_keywords), + 'run_until_current_duration': + Summary( + 'run_until_current_duration', + 'runUntilCurrent latency', + **metric_keywords) + } + + if ancestor.__name__ == 'EPollReactor': + doPoll = metrics['iteration_duration'].time()(EPollReactor.doPoll.__func__) + doIteration = doPoll + elif ancestor.__name__ == 'SelectReactor': + doSelect = metrics['iteration_duration'].time()(SelectReactor.doSelect.__func__) + doIteration = doSelect + + runUntilCurrent = metrics['run_until_current_duration'].time()(ancestor.runUntilCurrent.__func__) + + def _doReadOrWrite(self, selectable, method): + with self.metrics['do_read_or_write_duration'].labels( + type(selectable).__name__, method).time(): + super(InstrumentedReactor, self)._doReadOrWrite(selectable, method) + +def install(): + """ + Install the instrumented epoll() reactor. + """ + from twisted.internet.main import installReactor + installReactor(InstrumentedReactor()) diff --git a/pybal/metrics.py b/pybal/metrics.py index 4ccb064..74de644 100644 --- a/pybal/metrics.py +++ b/pybal/metrics.py @@ -10,24 +10,44 @@ except ImportError: metrics_implementation = 'dummy' -class DummyMetric(object): - def __init__(self, **kwargs): +class DummyTimer(object): + def __call__(self, func): + def wrap(*args, **kwargs): + func(*args, **kwargs) + return wrap + + def __enter__(self, *args, **kwargs): + pass + def __exit__(self, *args, **kwargs): pass - def labels(self, **kwargs): +class DummyMetric(object): + def __init__(self, *args, **kwargs): + pass + + def labels(self, *args, **kwargs): return self class DummyCounter(DummyMetric): - def inc(self, **kwargs): + def inc(self, *args, **kwargs): pass class DummyGauge(DummyMetric): - def set(**kwargs): + def set(self, *args, **kwargs): pass + +class DummySummary(DummyMetric): + def observe(self, *args, **kwargs): + pass + + def time(self): + return DummyTimer() if metrics_implementation == 'prometheus': Counter = prometheus_client.Counter Gauge = prometheus_client.Gauge + Summary = prometheus_client.Summary else: Counter = DummyCounter Gauge = DummyGauge + Summary = DummySummary -- To view, visit https://gerrit.wikimedia.org/r/371636 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie7cccd14687808b1c4d4a224d82b8b4ed8d0cbce Gerrit-PatchSet: 1 Gerrit-Project: operations/debs/pybal Gerrit-Branch: master Gerrit-Owner: Mark Bergsma <m...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits