43 lines
2.6 KiB
Python
43 lines
2.6 KiB
Python
"""Read native counters and profiler output; return bounded public measurements."""
|
|
import json,subprocess,time,math
|
|
COUNTERS=('quests','abandoned','lootEvents','lootItems','partyKills','rewarded','lootedCopper')
|
|
def normalize_performance(raw):
|
|
def number(v):
|
|
try:
|
|
n=float(v);return n if math.isfinite(n) and n>=0 else 0
|
|
except (TypeError,ValueError):return 0
|
|
rows=[]
|
|
for metric in raw.get('metrics',[]):
|
|
for row in metric.get('rows',[]):
|
|
if number(row.get('count'))<=0:continue
|
|
rows.append({'category':str(metric.get('type',''))[:40],'name':str(row.get('name',''))[:160],'calls':number(row.get('count')),'totalMs':number(row.get('totalTime'))/1000,'averageMs':number(row.get('avgTime'))/1000,'maxMs':number(row.get('maxTime'))/1000,'perTickMs':number(row.get('timePerTick'))/1000})
|
|
# Nested timers overlap. Do not sum their percentages or call this CPU usage.
|
|
rows.sort(key=lambda r:r['totalMs'],reverse=True)
|
|
ticks=number(raw.get('fullTickCount'))
|
|
return {'at':number(raw.get('generatedAt')),'enabled':raw.get('enabled') is True,'ticks':ticks,'averageTickMs':number(raw.get('fullTickTotalTime'))/max(1,ticks)/1000,'rows':rows[:20]}
|
|
def collect(sql,state):
|
|
bots=[b for b in state.get('bots',[]) if b.get('autonomy',{}).get('managed') and type(b.get('autonomy',{}).get('characterGuid')) is int]
|
|
allowed={b['autonomy']['characterGuid']:b for b in bots}
|
|
rows={}
|
|
for line in sql('SELECT guid,quests,abandoned,loot_events,loot_items,party_kills FROM acore_auth.azerothai_outcomes').splitlines():
|
|
fields=list(map(int,line.split('\t')))
|
|
if fields[0] in allowed:rows[fields[0]]=dict(zip(COUNTERS,fields[1:]+[0]))
|
|
rewarded={}
|
|
if allowed:
|
|
guids=','.join(map(str,allowed))
|
|
for line in sql('SELECT guid,COUNT(*) FROM acore_characters.character_queststatus_rewarded WHERE guid IN ('+guids+') GROUP BY guid').splitlines():
|
|
guid,count=map(int,line.split('\t'));rewarded[guid]=count
|
|
money={int(g):int(c) for g,c in (line.split('\t') for line in sql('SELECT guid,looted_copper FROM acore_auth.azerothai_currency').splitlines())}
|
|
result=[]
|
|
for guid,b in allowed.items():
|
|
counters=rows.get(guid,dict.fromkeys(COUNTERS,0));counters['rewarded']=rewarded.get(guid,0);counters['lootedCopper']=money.get(guid,0)
|
|
result.append({'guid':guid,'name':b['name'],**counters})
|
|
return result
|
|
|
|
def performance():
|
|
# Both paths are fixed; no user-controlled shell input and no credentials.
|
|
for path in ['/azerothcore/env/dist/logs/pmon_tick.json','/azerothcore/pmon_tick.json']:
|
|
p=subprocess.run(['docker','exec','ac-worldserver','cat',path],capture_output=True,text=True,timeout=10)
|
|
if p.returncode==0:return normalize_performance(json.loads(p.stdout))
|
|
return None
|