/** * 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()); } }
/** * 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; }
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); }
$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>
/** * 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); } }
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; }
public function getCrashReports() { if ($this->crashReports === null) { $this->crashReports = CrashReport::findAllByErrorCase($this->id); } return $this->crashReports; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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'); } } } } }