Files @ 8784bdc90648
Branch filter:

Location: light9/light9/metrics.py

drewp@bigasterisk.com
rm external gtk themes
"""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
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)




"""
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.





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