+
+crunchstat_re = re.compile(r"^\d{4}-\d\d-\d\d_\d\d:\d\d:\d\d [a-z0-9]{5}-8i9sb-[a-z0-9]{15} \d+ \d+ stderr crunchstat:")
+timestamp_re = re.compile(r"^(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d+Z) (.*)")
+
+def logtail(logcollection, logfunc, header, maxlen=25):
+ if len(logcollection) == 0:
+ logfunc("%s\n%s", header, " ** log is empty **")
+ return
+
+ containersapi = ("crunch-run.txt" in logcollection)
+ mergelogs = {}
+
+ for log in list(logcollection):
+ if not containersapi or log in ("crunch-run.txt", "stdout.txt", "stderr.txt"):
+ logname = log[:-4]
+ logt = deque([], maxlen)
+ mergelogs[logname] = logt
+ with logcollection.open(log) as f:
+ for l in f:
+ if containersapi:
+ g = timestamp_re.match(l)
+ logt.append((g.group(1), g.group(2)))
+ elif not crunchstat_re.match(l):
+ logt.append(l)
+
+ if containersapi:
+ keys = list(mergelogs)
+ loglines = []
+ while True:
+ earliest = None
+ for k in keys:
+ if mergelogs[k]:
+ if earliest is None or mergelogs[k][0][0] < mergelogs[earliest][0][0]:
+ earliest = k
+ if earliest is None:
+ break
+ ts, msg = mergelogs[earliest].popleft()
+ loglines.append("%s %s %s" % (ts, earliest, msg))
+ loglines = loglines[-maxlen:]
+ else:
+ loglines = mergelogs[list(mergelogs)[0]]
+
+ logtxt = "\n ".join(l.strip() for l in loglines)
+ logfunc("%s\n\n %s", header, logtxt)