Beispiel #1
0
 /**
  * Displays a particular model.
  * @param integer $id the ID of the model to be displayed
  */
 public function actionView($id)
 {
     // Load crash group
     $model = $this->loadModel($id);
     // Check that user is authorized to access this model
     $this->checkAuthorization($model);
     // Create new crash report model as search conditions container.
     $crashReport = new CrashReport();
     $crashReport->groupid = $model->id;
     // Fill search conditions
     if (isset($_GET['q'])) {
         $crashReport->filter = $_GET['q'];
     } else {
         if (isset($_POST['CrashReport'])) {
             // Advanced search
             $crashReport->isAdvancedSearch = true;
             // Fill form with data
             $crashReport->attributes = $_POST['CrashReport'];
         }
     }
     // Perform search
     $crashReportDataProvider = $crashReport->search();
     // Render view
     $this->render('view', array('model' => $model, 'crashReportModel' => $crashReport, 'crashReportDataProvider' => $crashReportDataProvider));
 }
 public function show($id)
 {
     $this->crash_report = CrashReport::findById($id);
     $symbolicator = new Symbolicator($this->crash_report->summary, 'tower1', $this->crash_report->appVersion);
     $this->symbolicated_report = null;
     $this->symbolicator_error_message = null;
     try {
         $this->symbolicated_report = $symbolicator->symbolicate();
     } catch (Exception $e) {
         $this->symbolicator_error_message = markdown_to_html($e->getMessage());
     }
 }
Beispiel #3
0
 /**
  * This validator method checks if srcid is a valid crash report ID or
  * debug info ID. 
  */
 public function checkSrcId()
 {
     if ($this->type == ProcessingError::TYPE_CRASH_REPORT_ERROR) {
         $crashReport = CrashReport::model()->find('id=' . $this->srcid);
         if ($crashReport === Null) {
             $this->addError('srcid', 'SrcID must be a valid crash report ID.');
             return false;
         }
     } else {
         if ($this->type == ProcessingError::TYPE_DEBUG_INFO_ERROR) {
             $debugInfo = DebugInfo::model()->find('id=' . $this->srcid);
             if ($debugInfo === Null) {
                 $this->addError('srcid', 'SrcID must be a valid debug info ID.');
                 return false;
             }
         }
     }
     return true;
 }
 /**
  * Returns the data model based on the primary key given in the GET variable.
  * If the data model is not found, an HTTP exception will be raised.
  * @param integer the ID of the model to be loaded
  */
 public function loadModel($id)
 {
     $model = CrashReport::model()->findByPk($id);
     if ($model === null) {
         throw new CHttpException(404, 'The requested page does not exist.');
     }
     return $model;
 }
Beispiel #5
0
 public function testGetCrashGroupTitle()
 {
     // Create new crash report
     $model = new CrashReport();
     $model->md5 = '123456789012345678';
     $model->project_id = 100;
     // invalid project id
     $model->status = CrashReport::STATUS_PROCESSED;
     $groupMD5 = '';
     $title = $model->getCrashGroupTitle($groupMD5);
     $this->assertTrue($title == 'Unknown Project');
     $this->assertTrue(strlen($groupMD5) != 0);
     $model->project_id = 1;
     // valid project id
     $groupMD5 = '';
     $title = $model->getCrashGroupTitle($groupMD5);
     $this->assertTrue($title == 'Reports without Exception Info');
     $this->assertTrue(strlen($groupMD5) != 0);
     // Find a pending crash report
     $model = CrashReport::model()->findByPk(1);
     $this->assertTrue($model != null);
     $groupMD5 = '';
     $title = $model->getCrashGroupTitle($groupMD5);
     $this->assertTrue($title == 'Unsorted Reports');
     $this->assertTrue(strlen($groupMD5) != 0);
     // Find an invalid crash report
     $model = CrashReport::model()->findByPk(5);
     $this->assertTrue($model != null);
     $groupMD5 = '';
     $title = $model->getCrashGroupTitle($groupMD5);
     $this->assertTrue($title == 'Invalid Reports');
     $this->assertTrue(strlen($groupMD5) != 0);
     // Find a processed crash report
     $model = CrashReport::model()->findByPk(4);
     $this->assertTrue($model != null);
     $groupMD5 = '';
     $title = $model->getCrashGroupTitle($groupMD5);
     $this->assertTrue($title == 'CrashRptd.dll! wmain() +0x2bd9 [crtex.c: 120]');
     $this->assertTrue(strlen($groupMD5) != 0);
     // Find another processed crash report
     $model = CrashReport::model()->findByPk(6);
     $this->assertTrue($model != null);
     $groupMD5 = '';
     $title = $model->getCrashGroupTitle($groupMD5);
     $this->assertTrue($title == 'CrashRpt.dll!+0xf');
     $this->assertTrue(strlen($groupMD5) != 0);
 }
Beispiel #6
0
$bugList = '';
foreach ($model->bugs as $bugCrashReport) {
    if ($bugCrashReport->bug->status < Bug::STATUS_OPEN_MAX) {
        $bugList .= CHtml::link('#' . $bugCrashReport->bug_id, array('bug/view', 'id' => $bugCrashReport->bug_id)) . ' ';
    }
    if ($bugList == '') {
        $bugList = 'None';
    }
}
$this->widget('zii.widgets.CDetailView', array('data' => $model, 'attributes' => array(array('name' => 'received', 'type' => 'text', 'value' => date("d/m/y H:i", $model->received)), array('name' => 'date_created', 'type' => 'text', 'value' => date("d/m/y H:i", $model->date_created)), array('name' => 'status', 'type' => 'text', 'value' => Lookup::item('CrashReportStatus', $model->status)), array('name' => 'filesize', 'type' => 'raw', 'value' => CHtml::encode(MiscHelpers::fileSizeToStr($model->filesize))), array('name' => 'project_id', 'type' => 'text', 'value' => $model->project->name), array('name' => 'appversion_id', 'type' => 'text', 'value' => $model->appVersion->version), 'crashguid', array('name' => 'crashrptver', 'type' => 'text', 'value' => 'CrashRpt ' . CrashReport::generatorVersionToStr($model->crashrptver)), array('name' => 'srcfilename', 'type' => 'raw', 'value' => CHtml::link($model->srcfilename, array('crashReport/download', 'id' => $model->id))), array('name' => 'groupid', 'type' => 'raw', 'value' => CHtml::link(CHtml::encode($model->collection->title), array('crashGroup/view', 'id' => $model->groupid))), array('label' => 'Open Bug(s)', 'type' => 'raw', 'value' => $bugList))));
?>

<div class="span-27 last detail-group-caption">Sender Info:</div>

<?php 
$this->widget('zii.widgets.CDetailView', array('data' => $model, 'attributes' => array(array('name' => 'geo_location', 'type' => 'text', 'value' => CrashReport::geoIdToCountryName($model->geo_location)), 'ipaddress', 'emailfrom', 'description')));
?>

<div class="span-27 last detail-group-caption">Exception Info:</div>

<?php 
$text = $model->exception_thread_id != 0 ? '0x' . dechex($model->exception_thread_id) : null;
$exceptionThread = $model->getExceptionThread();
if ($exceptionThread) {
    $link = CHtml::link(CHtml::encode('View Stack Trace'), array('crashReport/view', 'id' => $model->id, 'tab' => 'Threads', 'thread' => $exceptionThread->id));
    $text .= ' ' . $link;
}
$this->widget('zii.widgets.CDetailView', array('data' => $model, 'attributes' => array('exception_type', array('name' => 'exceptionaddress', 'type' => 'text', 'value' => $model->exceptionaddress != 0 ? '0x' . base_convert($model->exceptionaddress, 10, 16) : null), array('name' => 'exception_code', 'type' => 'text', 'value' => $model->exception_code != 0 ? '0x' . base_convert($model->exception_code, 10, 16) : null), 'exe_image', 'exceptionmodule', array('name' => 'exceptionmodulebase', 'type' => 'text', 'value' => $model->exceptionmodulebase != 0 ? '0x' . base_convert($model->exceptionmodulebase, 10, 16) : null), array('name' => 'exception_thread_id', 'type' => 'raw', 'value' => $text))));
?>

<div class="span-27 last detail-group-caption">Machine Info:</div>
Beispiel #7
0
 /**
  * Generates a crash report geographic location distribution graph for currently 
  * selected project and dumps it to stdout.
  * @param type $w Desired image width.
  * @param type $h Desired image height.
  * @throws CHttpException
  * @return void
  */
 public static function generateGeoLocationDistributionGraph($w, $h, $file = null)
 {
     if (!is_numeric($w) || $w <= 0 || $w > 1024) {
         throw new CHttpException(403, 'Invalid parameter');
     }
     if (!is_numeric($h) || $h <= 0 || $h > 960) {
         throw new CHttpException(403, 'Invalid parameter');
     }
     // Get current project info
     $curProjectId = Yii::app()->user->getCurProjectId();
     if ($curProjectId == false) {
         throw new CHttpException(403, 'Invalid parameter');
     }
     // Prepare data
     $criteria = new CDbCriteria();
     $criteria->select = 'geo_location, COUNT(*) as cnt';
     $criteria->group = 'geo_location';
     $criteria->compare('t.project_id', $curProjectId);
     $criteria->order = 'cnt DESC';
     $curVer = '(not set)';
     $versions = Yii::app()->user->getCurProjectVersions($curVer);
     if ($curVer != -1) {
         $criteria->compare('appversion_id', $curVer == 0 ? null : $curVer);
     }
     $data = array();
     $models = CrashReport::model()->findAll($criteria);
     $totalCount = 0;
     foreach ($models as $model) {
         $totalCount += $model->cnt;
         if ($model->geo_location === null) {
             if (isset($data[''])) {
                 $data[''] += $model->cnt;
             } else {
                 $data[''] = $model->cnt;
             }
         } else {
             $data[$model->geo_location] = $model->cnt;
         }
     }
     if ($file == null) {
         $fout = fopen('php://output', 'w');
     } else {
         $fout = fopen($file, 'wt');
     }
     fprintf($fout, '<div class="digest-pane-image" style="width:' . $w . 'px;min-height:' . $h . 'px;max-height:' . $h . 'px;overflow:hidden"><table id="geo-locations">');
     // Check the case when $data is empty.
     if (count($data) == 0) {
         fprintf($fout, '<tr><td><i>No data available</i></td></tr>');
     } else {
         foreach ($data as $name => $val) {
             $percent = 100 * $val / $totalCount;
             $percentStr = sprintf('%0.1f', $percent);
             $nameStr = '(not set)';
             if ($name != '') {
                 $nameStr = MiscHelpers::addEllipsis(CrashReport::geoIdToCountryName($name), 30);
             }
             fprintf($fout, '<tr><td>' . $nameStr . '</td><td>' . $percentStr . '%%</td></tr>');
         }
     }
     fprintf($fout, '</table></div>');
     if ($file != null) {
         fclose($fout);
     }
 }
Beispiel #8
0
 public function insertReport(CrashReport $report)
 {
     if ($stmt = $this->db->prepare(self::$INSERT_REPORT)) {
         $stmt->bind_param("ssississiii", $report->getCausingPlugin(), $report->getVersion()->get(true), $report->getVersion()->getBuild(), $report->getFile(), $report->getMessage(), $report->getLine(), $report->getType(), $report->getOS(), $report->getReportType(), time(), $report->getDate());
         $stmt->execute();
         return $this->db->insert_id;
     }
     return -1;
 }
Beispiel #9
0
 public function getCrashReports()
 {
     if ($this->crashReports === null) {
         $this->crashReports = CrashReport::findAllByErrorCase($this->id);
     }
     return $this->crashReports;
 }
Beispiel #10
0
 /**
  * Imports crash report files for certain project version.
  * @param string $dirName  Directory name.
  * @param string $projectId Project ID.
  * @param string $projVer  Project version.
  * @return integer count of crash report imported; or -1 on error.
  */
 private function importCrashReports($dirName, $projectId, $projVerId)
 {
     //echo 'Importing crash report files from dir: '.$dirName.'\n';
     // Get file list in the directory
     $fileList = scandir($dirName);
     if ($fileList == false) {
         Yii::log('Directory name is invalid: ' . $dirName, 'error');
         return -1;
         // Error
     }
     // Walk through files
     foreach ($fileList as $index => $file) {
         // Get abs path
         $path = $dirName . '/' . $file;
         // Strip file parts
         $path_parts = pathinfo($path);
         if ($file != '.' && $file != '..' && is_file($path) && strtolower($path_parts['extension']) == 'zip') {
             //echo 'Importing crash report file: '.$path.'\n';
             // Create new AR record
             $crashReport = new CrashReport();
             $crashReport->project_id = $projectId;
             $crashReport->appversion = $projVerId;
             $crashReport->fileAttachment = new CUploadedFile($file, $path, 'application/zip', filesize($path), '');
             // The following is to copy attachment file correctly.
             $crashReport->fileAttachmentIsUploaded = false;
             // Save changes to database
             if (!$crashReport->save()) {
                 Yii::log('Could not import crash report file:' . $path, 'error');
                 $errors = $crashReport->getErrors();
                 //var_dump($errors);
             } else {
                 // Increment counter
                 $this->_importedCrashReportsCount++;
             }
         }
     }
     // Done
     return $this->_importedCrashReportsCount;
 }
Beispiel #11
0
 /**
  * Returns count of crash reports in this project. 
  * @param integer $totalFileSize On output, receives the total size in bytes of files.
  * @param integer $percentOfDiskQuota On output, receives percent of disk quota.
  * @param integer $appver Optional. If specified, count of files is calculated for the given version.
  * @return integer count of crash report files.
  */
 public function getCrashReportCount(&$totalFileSize, &$percentOfDiskQuota, $appver = Project::PROJ_VER_ALL)
 {
     // Find all crash reports belonging to this project and having
     // $appver application version.
     $criteria = new CDbCriteria();
     $criteria->compare('project_id', $this->id, false, 'AND');
     if ($appver != Project::PROJ_VER_ALL) {
         $criteria->compare('appversion_id', $appver, false, 'AND');
     }
     $crashReports = CrashReport::model()->findAll($criteria);
     // Calculate count of crash reports
     $count = CrashReport::model()->count($criteria);
     // Calculate total file size
     $totalFileSize = 0;
     foreach ($crashReports as $crashReport) {
         $totalFileSize += $crashReport->filesize;
     }
     // Calc percent of disk quota
     if ($this->crash_report_files_disc_quota <= 0) {
         // unlimited
         $percentOfDiskQuota = -1;
     } else {
         $percentOfDiskQuota = 100 * $totalFileSize / ($this->crash_report_files_disc_quota * 1024 * 1024);
     }
     // Return file count
     return $count;
 }
Beispiel #12
0
 /**
  * This method is executed before AR is saved to database.
  * In this method, we set some model attributes.
  * @return boolean True on success.
  */
 protected function beforeSave()
 {
     if (!parent::beforeSave()) {
         return false;
     }
     // Check if this is a new record.
     if ($this->isNewRecord) {
         // Set project id
         $this->project_id = Yii::app()->user->getCurProjectId();
         // Set project version
         $curVer = false;
         $versions = Yii::app()->user->getCurProjectVersions($curVer);
         if ($curVer != Project::PROJ_VER_ALL) {
             $this->appversion_id = $curVer;
         } else {
             // Project version '<all>' currently selected.
             // We have to determine bug version from associated
             // crash reports/collections.
             $numbers = MiscHelpers::splitNumberList($this->crashgroups);
             foreach ($numbers as $number) {
                 $crashGroup = CrashGroup::model()->findByPk($number);
                 if ($crashGroup === Null) {
                     throw new HttpException('Invalid crash group ID');
                 }
                 $curVer = $crashGroup->appversion_id;
                 break;
             }
             if ($curVer == -1) {
                 $numbers = MiscHelpers::splitNumberList($this->crashreports);
                 foreach ($numbers as $number) {
                     $crashReport = CrashReport::model()->findByPk($number);
                     if ($crashReport === Null) {
                         throw new HttpException('Invalid crash report ID');
                     }
                     $curVer = $crashReport->appversion_id;
                     break;
                 }
             }
             if ($curVer == -1) {
                 throw new CHttpException(403, 'Invalid request');
             }
             $this->appversion_id = $curVer;
         }
         // Set date created
         $this->date_created = time();
         // Set date last modified
         $this->date_last_modified = $this->date_created;
         // Set reported by
         $this->reported_by = Yii::app()->user->id;
         if ($this->assigned_to < 0) {
             unset($this->assigned_to);
         }
     } else {
         // Set date last modified
         $this->date_last_modified = time();
         if ($this->status > Bug::STATUS_OPEN_MAX) {
             $this->date_closed = $this->date_last_modified;
         } else {
             unset($this->date_closed);
         }
     }
     // Success.
     return true;
 }
Beispiel #13
0
 /**
  * Determines if a bug can be opened for this group. A bug can not be opened
  * if the crash group is empty or does not contain processed crash reports.
  * @return boolean true if a bug can be opened.
  */
 public function canOpenNewBug()
 {
     // Calculate count of processed reports in this group
     $criteria = new CDbCriteria();
     $criteria->compare('groupid', $this->id);
     $criteria->compare('status', CrashReport::STATUS_PROCESSED);
     $count = CrashReport::model()->count($criteria);
     if ($count == 0) {
         return false;
     }
     // No such reports
     // OK
     return true;
 }
Beispiel #14
0
 /**
  * This method finalizes the given operation, updates appropriate db tables
  * and removes temporary files.	 
  */
 public function finalizeOperation($op, $opStatus)
 {
     // Update operation db record.
     $op->status = $opStatus;
     $op->save();
     if ($op->optype == Operation::OPTYPE_PROCESS_CRASH_REPORT) {
         // Delete temporary files and directories
         $crashReportFileName = $op->operand1;
         $xmlFileName = $op->operand2;
         if ($opStatus != Operation::STATUS_SUCCEEDED) {
             // Set crash report record status to Invalid
             Yii::log('Setting crash report #' . $op->srcid . ' status to invalid ', 'error');
             $crashReport = CrashReport::model()->find('id=' . $op->srcid);
             if ($crashReport != null) {
                 $crashReport->status = DebugInfo::STATUS_INVALID;
                 $crashReport->save();
             }
         }
         // Delete temp XML file
         Yii::log('Deleting file ' . $xmlFileName, 'info');
         if (!@unlink($xmlFileName)) {
             // Couldn't delete file
             Yii::log('Error deleting file ' . $xmlFileName, 'error');
         }
     } else {
         if ($op->optype == Operation::OPTYPE_IMPORTPDB) {
             // Delete temporary files and directories
             $pdbFileName = $op->operand1;
             $xmlFileName = $op->operand2;
             if ($opStatus != Operation::STATUS_SUCCEEDED) {
                 // Set debug info record status to Invalid
                 Yii::log('Setting debug info #' . $op->srcid . ' status to invalid ', 'error');
                 $debugInfo = DebugInfo::model()->find('id=' . $op->srcid);
                 if ($debugInfo != null) {
                     $debugInfo->status = DebugInfo::STATUS_INVALID;
                     $debugInfo->save();
                 }
             }
             // Delete file
             Yii::log('Deleting file ' . $xmlFileName, 'info');
             if (!@unlink($xmlFileName)) {
                 // Couldn't delete file
                 Yii::log('Error deleting file ' . $xmlFileName, 'error');
             }
             // If operation has succeeded, we can remove original PDB file and
             // its parent directories, because the file was copied by daemon
             // to its persistent location.
             if ($op->status == Operation::STATUS_SUCCEEDED) {
                 // Delete file
                 Yii::log('Deleting file ' . $pdbFileName, 'info');
                 if (!@unlink($pdbFileName)) {
                     // Couldn't delete file
                     Yii::log('Error deleting file ' . $pdbFileName, 'error');
                 }
                 // Delete parent directory.
                 $parentDirName = dirname($pdbFileName);
                 Yii::log('Deleting directory ' . $parentDirName, 'info');
                 if (!@rmdir($parentDirName)) {
                     // Couldn't delete directory.
                     Yii::log('Error deleting directory ' . $parentDirName, 'error');
                 }
                 // Delete first-level parent directory.
                 $parentDirName = dirname($parentDirName);
                 Yii::log('Deleting directory ' . $parentDirName, 'info');
                 if (!@rmdir($parentDirName)) {
                     // Couldn't delete dir
                     Yii::log('Error deleting directory ' . $parentDirName, 'error');
                 }
             }
         }
     }
 }