import json,sys,collections,datetime,pathlib
p=pathlib.Path(sys.argv[1]);spans={};kids=collections.defaultdict(list)
for path in [*p.parent.glob(p.name+'.*'),p]:
 if not path.exists():continue
 for line in path.open():
  try:s=json.loads(line)
  except ValueError:continue
  if s.get('type')=='effect-span':spans[(s['traceId'],s['spanId'])]=s
for s in spans.values():kids[(s['traceId'],s.get('parentSpanId'))].append(s)
def desc(s):
 for k in kids[(s['traceId'],s['spanId'])]:yield k;yield from desc(k)
rows=[]
for s in sorted((s for s in spans.values() if s['name']=='ThreadPullRequestServiceV2.synchronize'),key=lambda s:int(s['startTimeUnixNano'])):
 ds=list(desc(s));calls=[k for k in ds if k['name']=='branchPullRequest'];git=[k for k in ds if (k['name']=='runGitCommand' or (k['name']=='processRunner.runProcessCore' and k['attributes'].get('process.command')=='git'))]
 row=dict(at=datetime.datetime.fromtimestamp(int(s['startTimeUnixNano'])/1e9,datetime.timezone.utc).isoformat(),spanId=s['spanId'],traceId=s['traceId'],request=s['attributes'].get('evidence.request'),lookups=len(calls),discovery=sum('freshGitState' not in k['attributes'].get('evidence.options','') for k in calls),revalidation=sum('freshGitState' in k['attributes'].get('evidence.options','') for k in calls),git=len(git),faultWrappers=sum(k['attributes'].get('evidence.exitCode')==87 for k in git),actualGit=len(git)-sum(k['attributes'].get('evidence.exitCode')==87 for k in git),runGitCommand=sum(k['name']=='runGitCommand' for k in ds),branches=[k['attributes'] for k in calls],gitProcesses=[dict(spanId=k['spanId'],attributes=k['attributes'],exit=k['exit']) for k in git],exit=s['exit'])
 def owningBranch(process):
  parent=(process['traceId'],process.get('parentSpanId'));seen=set()
  while parent in spans and parent not in seen:
   seen.add(parent);ancestor=spans[parent]
   if ancestor['name']=='branchPullRequest':return ancestor['attributes'].get('evidence.branch')
   if ancestor['spanId']==s['spanId']:return None
   parent=(ancestor['traceId'],ancestor.get('parentSpanId'))
  return None
 row['gitPerBranch']=dict(collections.Counter(owningBranch(k) or '(outside branchPullRequest)' for k in git))
 row['lookupSpans']=[dict(spanId=k['spanId'],attributes=k['attributes'],exit=k['exit']) for k in calls]
 rows.append(row)
print(json.dumps(rows,indent=2))
