| 287 | c.peak_total_rss = peak_rss_by_container[c.id] |
| 288 | |
| 289 | def create(self, output): |
| 290 | # Read logfiles |
| 291 | timelines = [] |
| 292 | for c in self.containers: |
| 293 | if not os.path.exists(c.logfile): |
| 294 | logging.warning("Missing log file: %s", c.logfile) |
| 295 | continue |
| 296 | timelines.append(self.logfile_timeline(c)) |
| 297 | |
| 298 | # Convert timelines to JSON |
| 299 | min_ts = None |
| 300 | timeline_json = [] |
| 301 | for timeline in timelines: |
| 302 | for current_line, next_line in zip(timeline, timeline[1:]): |
| 303 | name, ts_current, msg = current_line |
| 304 | _, ts_next, _ = next_line |
| 305 | timeline_json.append( |
| 306 | [name, msg, ts_current, ts_next] |
| 307 | ) |
| 308 | if not timeline_json: |
| 309 | logging.warning("No timeline data; skipping timeline") |
| 310 | return |
| 311 | |
| 312 | min_ts = min(x[2] for x in timeline_json) |
| 313 | |
| 314 | for row in timeline_json: |
| 315 | row[2] = row[2] - min_ts |
| 316 | row[3] = row[3] - min_ts |
| 317 | |
| 318 | # metrics_by_container: container -> [ ts, user, system ] |
| 319 | metrics_by_container = dict() |
| 320 | max_metric_ts = 0 |
| 321 | container_by_id = dict() |
| 322 | for c in self.containers: |
| 323 | container_by_id[c.id] = c |
| 324 | |
| 325 | for ts, container_id, user, system in self.parse_metrics(open(self.monitor_file)): |
| 326 | container = container_by_id.get(container_id) |
| 327 | if not container: |
| 328 | continue |
| 329 | |
| 330 | if ts > max_metric_ts: |
| 331 | max_metric_ts = ts |
| 332 | if ts < min_ts: |
| 333 | # We ignore metrics that show up before the timeline's |
| 334 | # first messages. This largely avoids a bug in the |
| 335 | # Google Charts visualization code wherein one of the series seems |
| 336 | # to wrap around. |
| 337 | continue |
| 338 | metrics_by_container.setdefault( |
| 339 | container.name, []).append((ts - min_ts, user, system)) |
| 340 | |
| 341 | with open(output, "w") as o: |
| 342 | template_path = os.path.join(os.path.dirname(__file__), "timeline.html.template") |
| 343 | shutil.copyfileobj(open(template_path), o) |
| 344 | o.write("\n<script>\nvar data = \n") |
| 345 | json.dump(dict(buildname=self.buildname, timeline=timeline_json, |
| 346 | metrics=metrics_by_container, max_ts=(max_metric_ts - min_ts)), o, indent=2) |