php/inc/LogParser.php
author Ed Morley <emorley@mozilla.com>
Wed, 01 Apr 2015 14:04:18 +0400
changeset 1519 134bdfcf7e2d4a46ef468d5d4f687b257504c19a
parent 1511 ec1850f9e430773b6036a65e41d95382ae12ba3b
permissions -rw-r--r--
Bug 1054977 - Revert EOL changes to make future local use easier TBPL has now been switched off in production, so the src repo is no longer being used. However in case anyone in the future wants to try using TBPL locally (eg for a side by side comparison when debugging a Treeherder issue), let's revert a bunch of the EOL changes we made, so it's not quite so limited in functionality.

<?php
/* -*- Mode: PHP; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et tw=80 : */

require_once 'inc/ParallelLogGenerating.php';
require_once 'inc/GzipUtils.php';
require_once 'inc/RawGzLogDownloader.php';
require_once 'inc/LineFilter.php';

class LogParser implements LogGenerator {
  private $lines = null;
  private $matchedLineNumbers = null;

  public function __construct($run, LineFilter $lineFilter) {
    $this->run = $run;
    $this->lineFilter = $lineFilter;
  }

  public function ensureExcerptExists() {
    $log = array("_id" => $this->run['_id'], "type" => $this->lineFilter->getType());
    ParallelLogGenerating::ensureLogExists($log, $this);
    return $log;
  }

  // Called during ensureExcerptExists, LogGenerator implementation
  public function generate($log) {
    GzipUtils::writeToDb($log, $this->getExcerpt());
  }

  protected function linkLine($target, $text) {
    if (substr($text, -1) == "\n")
      $text = substr($text, 0, -1);
    if (substr($text, -1) == "\r")
      $text = substr($text, 0, -1);
    return '<a href="'.$target.'">'.htmlspecialchars($text)."</a>\n";
  }

  public function getExcerpt($asHTML = false) {
    // Keep in sync with AnnotatedSummaryGenerator.php's $maxParsedFailures
    $maxParsedFailures = 100;
    $maxLineLength = 500;
    $type = $this->lineFilter->getType();
    // The TinderboxPrint and reftest analyser scrape lines must remain untouched.
    $canTruncate = ($type != "tinderbox_print" && $type != "reftest");
    $lines = $this->getLines();
    $matchedLineNumbers = $this->getMatchedLineNumbers();
    $excerptLines = array();
    foreach ($matchedLineNumbers as $i => $lineNumber) {
      // Only display the first N failures
      if ($i >= $maxParsedFailures) {
        $totalFailures = count($matchedLineNumbers);
        $excerptLines[] = "First $maxParsedFailures of $totalFailures failures shown.\n";
        break;
      }
      // Remove mozharness timestamp/log level prefixes to avoid annotated summary bloat
      // and to allow for bug suggestions when searching for the whole failure line.
      $mozharnessPrefixRE = "/^\d+:\d+:\d+[ ]+(?:DEBUG|INFO|WARNING|ERROR|CRITICAL|FATAL) - [ ]?/";
      $matchedline = preg_replace($mozharnessPrefixRE, '', $lines[$lineNumber]);
      if ($canTruncate && strlen($matchedline) > $maxLineLength) {
        // Cap the line length to avoid hanging the browser in extreme cases.
        $matchedline = rtrim(substr($matchedline, 0, $maxLineLength)) . "... [exceeded max length]\n";
      }
      $excerptLines[] = $asHTML ? $this->linkLine('#error'.$i, $matchedline) : $matchedline;
    }
    return implode('', $excerptLines);
  }

  public function getLines() {
    if ($this->lines === null) {
      $this->lines = RawGzLogDownloader::getLines($this->run);
    }
    return $this->lines;
  }

  public function getMatchedLineNumbers() {
    if ($this->matchedLineNumbers === null) {
      $this->matchedLineNumbers = $this->findMatchedLineNumbers();
    }
    return $this->matchedLineNumbers;
  }

  public function findMatchedLineNumbers() {
    $lines = $this->getLines();
    $matchedLineNumbers = array();
    foreach ($lines as $i => $line) {
      if ($this->lineFilter->matchLine($line)) {
        $matchedLineNumbers[] = $i;
      }
    }
    return $matchedLineNumbers;
  }
}