diff --git a/light9/collector/collector.py b/light9/collector/collector.py --- a/light9/collector/collector.py +++ b/light9/collector/collector.py @@ -3,6 +3,7 @@ import time from typing import Dict, List, Set, Tuple, cast from light9.typedgraph import typedValue +from prometheus_client import Summary from rdfdb.syncedgraph.syncedgraph import SyncedGraph from rdflib import URIRef @@ -16,6 +17,7 @@ from light9.newtypes import (ClientSessi log = logging.getLogger('collector') +STAT_SETATTR = Summary('set_attr', 'setAttr calls') def makeDmxMessageIndex(base: DmxIndex, offset: DmxIndex) -> DmxMessageIndex: return DmxMessageIndex(base + offset - 1) @@ -99,6 +101,7 @@ class Collector: end = typedValue(float, self.graph, remap, L9['end']) self.remapOut[(dev, attr)] = OutputRange((start, end)) + @STAT_SETATTR.time() def setAttrs(self, client: ClientType, clientSession: ClientSessionType, settings: DeviceSettings, sendTime: UnixTime): """ Given DeviceSettings, we resolve conflicting values, diff --git a/light9/collector/collector_client_asyncio.py b/light9/collector/collector_client_asyncio.py --- a/light9/collector/collector_client_asyncio.py +++ b/light9/collector/collector_client_asyncio.py @@ -9,7 +9,7 @@ from prometheus_client import Summary log = logging.getLogger('coll_client') -SESS = Summary('coll_client_new_session', 'aiohttp.ClientSession') +ZMQ_SEND = Summary('zmq_send', 'calls') def toCollectorJson(client, session, settings: DeviceSettings) -> str: @@ -30,6 +30,7 @@ class _Sender: self.socket.connect('tcp://127.0.0.1:9203') #todo: tie to :collectorZmq in graph # old version used: 'tcp://%s:%s' % (service.host, service.port) + @ZMQ_SEND.time() async def send(self, client: str, session: str, settings: DeviceSettings): msg = toCollectorJson(client, session, settings).encode('utf8') # log.info(f'zmq send {len(msg)}') diff --git a/light9/collector/service.py b/light9/collector/service.py --- a/light9/collector/service.py +++ b/light9/collector/service.py @@ -20,7 +20,6 @@ from light9.collector.weblisteners impor from light9.namespaces import L9 from light9.run_local import log from light9.zmqtransport import parseJsonMessage -from prometheus_client import Summary from rdfdb.syncedgraph.syncedgraph import SyncedGraph from starlette.applications import Starlette from starlette.endpoints import WebSocketEndpoint @@ -34,7 +33,6 @@ from starlette_exporter import Prometheu import zmq import zmq.asyncio -STAT_SETATTR = Summary('set_attr', 'setAttr calls') # this is the rate sent to usb RATE = 20 @@ -65,15 +63,14 @@ class Updates(WebSocketEndpoint, UiListe async def PutAttrs(collector: Collector, request): - with STAT_SETATTR.time(): - try: - body = await request.body() - except ClientDisconnect: - log.warning("PUT /attrs request disconnected- ignoring") - return Response('', status_code=400) - client, clientSession, settings, sendTime = parseJsonMessage(collector.graph, body) - collector.setAttrs(client, clientSession, settings, sendTime) - return Response('', status_code=202) + try: + body = await request.body() + except ClientDisconnect: + log.warning("PUT /attrs request disconnected- ignoring") + return Response('', status_code=400) + client, clientSession, settings, sendTime = parseJsonMessage(collector.graph, body) + collector.setAttrs(client, clientSession, settings, sendTime) + return Response('', status_code=202) async def zmqListener(collector): diff --git a/light9/effect/sequencer/eval_faders.py b/light9/effect/sequencer/eval_faders.py --- a/light9/effect/sequencer/eval_faders.py +++ b/light9/effect/sequencer/eval_faders.py @@ -18,8 +18,8 @@ from light9.typedgraph import typedValue log = logging.getLogger('seq.fader') -COMPILE = Summary('compile_graph_fader', '') -COMPUTE_ALL_FADERS = Summary('compute_all_faders', '') +COMPILE = Summary('compile_graph_fader', 'compile') +COMPUTE_ALL_FADERS = Summary('compute_all_faders', 'compile') @dataclass class Fader: diff --git a/light9/effect/sequencer/sequencer.py b/light9/effect/sequencer/sequencer.py --- a/light9/effect/sequencer/sequencer.py +++ b/light9/effect/sequencer/sequencer.py @@ -83,7 +83,6 @@ class Sequencer: self.graph.addHandler(self.compileGraph) #self.updateLoop() - @metrics('compile_graph').time() def compileGraph(self) -> None: """rebuild our data from the graph""" for song in self.graph.subjects(RDF.type, L9['Song']): @@ -93,7 +92,6 @@ class Sequencer: self.graph.addHandler(compileSong) - @metrics('compile_song').time() def compileSong(self, song: Song) -> None: anyErrors = False self.notes[song] = [] @@ -131,7 +129,6 @@ class Sequencer: await asyncio.sleep(delay) continue - @metrics('update_call').time() async def update(self): with metrics('update_s0_getMusic').time(): musicState = {'t':123.0,'song':'http://light9.bigasterisk.com/show/dance2019/song5'}#self.music.getLatest() diff --git a/light9/homepage/ServiceButtonRow.ts b/light9/homepage/ServiceButtonRow.ts --- a/light9/homepage/ServiceButtonRow.ts +++ b/light9/homepage/ServiceButtonRow.ts @@ -24,6 +24,7 @@ export class ServiceButtonRow extends Li display: inline-block; margin-right: 3px; flex-grow: 1; + min-width: 9em; } .window { } diff --git a/light9/homepage/StatsLine.ts b/light9/homepage/StatsLine.ts --- a/light9/homepage/StatsLine.ts +++ b/light9/homepage/StatsLine.ts @@ -58,6 +58,7 @@ export class StatsLine extends LitElemen setTimeout(reload, 1000); }) .catch((err) => { + log(`${this.name} failing`, err) setTimeout(reload, 1000); }); } else { @@ -73,13 +74,13 @@ export class StatsLine extends LitElemen }); } extractProcessStats(stats: Metrics) { - stats.forEach((row) => { + stats.forEach((row: Metric) => { if (row.name == "process_resident_memory_bytes") { - this.mem = parseFloat(row.metrics[0].value) / 1024 / 1024; + this.mem = parseFloat(row.metrics[0].value!) / 1024 / 1024; } if (row.name == "process_cpu_seconds_total") { const now = Date.now() / 1000; - const cpuSecondsTotal = parseFloat(row.metrics[0].value); + const cpuSecondsTotal = parseFloat(row.metrics[0].value!); this.cpu = (cpuSecondsTotal - this.prevCpuTotal) / (now - this.prevCpuNow); this.prevCpuTotal = cpuSecondsTotal; this.prevCpuNow = now; @@ -106,6 +107,7 @@ export class StatsLine extends LitElemen th { padding: 2px 4px; background: #2f2f2f; + text-align: left; } td { padding: 0; @@ -204,11 +206,10 @@ export class StatsLine extends LitElemen } else if (m.type == "UNTYPED") { return html`${v.value}`; } else if (m.type == "SUMMARY") { - log(v); if (!v.count) { return html`err: summary without count`; } - return html`c=${v.count} percall=${((v.count && v.sum ? v.sum / v.count : 0) * 1000).toPrecision(3)}ms`; + return html`n=${v.count} percall=${((v.count && v.sum ? v.sum / v.count : 0) * 1000).toPrecision(3)}ms`; } else { throw m.type; } @@ -230,7 +231,7 @@ export class StatsLine extends LitElemen if (delta > maxDelta) maxDelta = delta; } prev = 0; - const maxBarH = 60; + const maxBarH = 30; for (let level in b) { let count = parseFloat(b[level]); let delta = count - prev; @@ -247,6 +248,24 @@ export class StatsLine extends LitElemen return html`${firstLevel} ${lines} ${lastLevel}`; } + tightLabel(labs: { [key: string]: string }): string { + const d: { [key: string]: string } = {} + for (let k in labs) { + if (k == 'app_name') continue; + if (k == 'output') continue; + if (k=='status_code'&&labs[k]=="200") continue; + d[k] = labs[k] + } + const ret = JSON.stringify(d) + return ret == "{}" ? "" : ret + } + tightMetric(name: string): string { + return name + .replace('starlette', '⭐') + .replace("_request" ,"_req") + .replace("_duration" ,"_dur") + .replace('_seconds', '_s') + } render() { const now = Date.now() / 1000; @@ -255,31 +274,31 @@ export class StatsLine extends LitElemen
${displayedStats.map( - (row, rowNum) => html` + (row, rowNum) => html` - + ${rowNum == 0 - ? html` + ? html` ` - : ""} + : ""} ` - )} + )}
${row.type.slice(0, 1)} ${row.name}${this.tightMetric(row.name)} ${row.metrics.map( - (v) => html` + (v) => html` - + ` - )} + )}
${JSON.stringify(v.labels)}${this.tightLabel(v.labels)} ${this.valueDisplay(row, v)}
`;