Files
@ 0dd05e9d4ae7
Branch filter:
Location: light9/light9/metrics.py
0dd05e9d4ae7
4.3 KiB
text/x-python
ran into this line- maybe it is not NotImplemented after all?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | """for easier porting, and less boilerplate, allow these styles using the
form of the call to set up the right type of metric automatically:
from metrics import metrics
metrics.setProcess('pretty_name')
@metrics('loop').time() # a common one to get the fps of each service. Gets us qty and time
def frame():
if err:
metrics('foo_errors').incr() # if you incr it, it's a counter
@metrics('foo_calls').time() # qty & time because it's a decorator
def foo():
metrics('goal_fps').set(f) # a gauge because we called set()
with metrics('recompute'): ... # ctxmgr also makes a timer
time_this_part()
I don't see a need for labels yet, but maybe some code will want like
metrics('foo', label1=one). Need histogram? Info?
"""
from typing import Dict, Tuple, Callable, Type, TypeVar, cast
import cyclone.web
from prometheus_client import Counter, Gauge, Metric, Summary
from prometheus_client.exposition import generate_latest
from prometheus_client.registry import REGISTRY
_created: Dict[str, Metric] = {}
# _process=sys.argv[0]
# def setProcess(name: str):
# global _process
# _process = name
MT = TypeVar("MT")
class _MetricsRequest:
def __init__(self, name: str, **labels):
self.name = name
self.labels = labels
def _ensure(self, cls: Type[MT]) -> MT:
if self.name not in _created:
_created[self.name] = cls(name=self.name, documentation=self.name, labelnames=self.labels.keys())
m = _created[self.name]
if self.labels:
m = m.labels(**self.labels)
return m
def __call__(self, fn) -> Callable:
return timed_fn
def set(self, v: float):
self._ensure(Gauge).set(v)
def inc(self):
self._ensure(Counter).inc()
def offset(self, amount: float):
self._ensure(Gauge).inc(amount)
def time(self):
return self._ensure(Summary).time()
def observe(self, x: float):
return self._ensure(Summary).observe(x)
def __enter__(self):
return self._ensure(Summary).__enter__()
def metrics(name: str, **labels):
return _MetricsRequest(name, **labels)
class _CycloneMetrics(cyclone.web.RequestHandler):
def get(self):
self.add_header('content-type', 'text/plain')
self.write(generate_latest(REGISTRY))
def metricsRoute() -> Tuple[str, Type[cyclone.web.RequestHandler]]:
return ('/metrics', _CycloneMetrics)
"""
stuff we used to have in greplin. Might be nice to get (client-side-computed) min/max/stddev back.
class PmfStat(Stat):
A stat that stores min, max, mean, standard deviation, and some
percentiles for arbitrary floating-point data. This is potentially a
bit expensive, so its child values are only updated once every
twenty seconds.
metrics consumer side can do this with the changing counts:
class RecentFps:
def __init__(self, window=20):
self.window = window
self.recentTimes = []
def mark(self):
now = time.time()
self.recentTimes.append(now)
self.recentTimes = self.recentTimes[-self.window:]
def rate(self):
def dec(innerFunc):
def f(*a, **kw):
self.mark()
return innerFunc(*a, **kw)
return f
return dec
def __call__(self):
if len(self.recentTimes) < 2:
return {}
recents = sorted(round(1 / (b - a), 3)
for a, b in zip(self.recentTimes[:-1],
self.recentTimes[1:]))
avg = (len(self.recentTimes) - 1) / (
self.recentTimes[-1] - self.recentTimes[0])
return {'average': round(avg, 5), 'recents': recents}
i think prometheus covers this one:
import psutil
def gatherProcessStats():
procStats = scales.collection('/process',
scales.DoubleStat('time'),
scales.DoubleStat('cpuPercent'),
scales.DoubleStat('memMb'),
)
proc = psutil.Process()
lastCpu = [0.]
def updateTimeStat():
now = time.time()
procStats.time = round(now, 3)
if now - lastCpu[0] > 3:
procStats.cpuPercent = round(proc.cpu_percent(), 6) # (since last call)
lastCpu[0] = now
procStats.memMb = round(proc.memory_info().rss / 1024 / 1024, 6)
task.LoopingCall(updateTimeStat).start(.1)
"""
class M:
def __call__(self, name):
return
|