gates / gates (push) Successful in 13m1s
Spike: per-app normal levels on three boxes (19-31 days), the off-site push as a line measure (a lower bound), qBittorrent/Transmission/Plex explainers measured on 9202, a tc ceiling measured (not built). Live on 9202 with 0.342.0-rc.1: limit set; real seed explained; CPU burner and the hidden flood alarmed once each and cleared once; the household's limit left alone. Teardown: apps removed, 9202 back on 0.341.0, receiver 9471 destroyed.
33 lines
1.5 KiB
Python
33 lines
1.5 KiB
Python
import sqlite3,sys,collections
|
|
def runs(r, pred):
|
|
best=cur=0; bt=None; prev=None
|
|
for t,v in r:
|
|
if pred(v) and prev is not None and t-prev<=180: cur+=1
|
|
elif pred(v): cur=1
|
|
else: cur=0
|
|
if cur>best: best=cur; bt=t
|
|
prev=t
|
|
return best,bt
|
|
import datetime
|
|
for box in sys.argv[1:]:
|
|
db=sqlite3.connect(f'file:{box}/metrics.db?mode=ro',uri=True)
|
|
nc=None
|
|
rows=collections.defaultdict(list)
|
|
for ts,name,cpu,tx in db.execute('select ts,container_name,cpu_percent,net_tx_bytes from container_metrics order by ts'):
|
|
rows[name].append((ts,cpu,tx))
|
|
print('==',box.rsplit('/',1)[1])
|
|
out=[]
|
|
for name,r in rows.items():
|
|
cpu=[(t,c) for t,c,_ in r]
|
|
tx=[]
|
|
for (t0,_,a),(t1,_,b) in zip(r,r[1:]):
|
|
if a is None or b is None or b<a or not 0<t1-t0<=180: continue
|
|
tx.append((t1,(b-a)*8/(t1-t0)/1e6))
|
|
c150,ct=runs(cpu,lambda v:v>=150); c80,_=runs(cpu,lambda v:v>=80)
|
|
u5,ut=runs(tx,lambda v:v>=5); u1,_=runs(tx,lambda v:v>=1)
|
|
if max(c80,u1)>=3: out.append((name,c80,c150,ct,u1,u5,ut))
|
|
print(f'{"container":28} cpu>=80% cpu>=150% (at) tx>=1Mbit tx>=5Mbit (at) [longest run, minutes]')
|
|
for name,c80,c150,ct,u1,u5,ut in sorted(out,key=lambda x:-max(x[1],x[4])):
|
|
f=lambda t: datetime.datetime.utcfromtimestamp(t).strftime('%m-%d %H:%M') if t else '-'
|
|
print(f'{name[:28]:28} {c80:8} {c150:9} ({f(ct)}) {u1:9} {u5:9} ({f(ut)})')
|