/** * Set the package ID * @param int $packageId * @param string $fromTime */ public function setPackageId($packageId, $fromTime = null) { $this->from('crash_archive', 'a')->field('a.package_version_id')->field('COUNT(*)', 'total')->innerJoin('package_version pv', 'pv.id', '=', 'a.package_version_id')->field('pv.value', 'name')->where('a.package_id', $packageId)->groupBy('a.package_version_id'); $query = new Select(); $query->from('crash_archive', 'a', 'package_version_id')->where('a.package_id', $packageId)->innerJoin('package_version pv', 'pv.id', '=', 'a.package_version_id')->groupBy(1); if ($fromTime !== null) { $this->fromTime = $from = $this->getPeriodFrom($fromTime); $this->where('a.created_at', '>=', $from); $query->where('a.created_at', '>=', $from); } $this->setCountQuery($query); }
/** * Set the package ID * @param int $packageId */ public function setPackageId($packageId, $fromTime = null) { $this->from('crash_archive', 'a')->field('a.stack_trace_id')->field('COUNT(*)', 'total')->innerJoin('stack_trace st', 'st.id', '=', 'a.stack_trace_id')->field('st.summary')->where('a.package_id', $packageId)->groupBy('a.stack_trace_id'); $query = new Select(); $query->from('crash_archive', 'a', 'stack_trace_id')->where('a.package_id', $packageId)->innerJoin('stack_trace st', 'st.id', '=', 'a.stack_trace_id')->groupBy(1); if ($fromTime !== null) { $from = $this->getPeriodFrom($fromTime); $this->where('a.created_at', '>=', $from); $query->where('a.created_at', '>=', $from); } $this->setCountQuery($query); }
/** * (non-PHPdoc) * @see \Koldy\Cache\Driver\AbstractCacheDriver::get() */ public function get($key) { $this->checkKey($key); $select = new Select($this->config['table']); $select->setConnection($this->config['connection']); $select->where('id', $key)->where('expires_at', '>=', time()); $record = $select->fetchFirst(\PDO::FETCH_ASSOC); if ($record === false) { return null; } else { return unserialize($record['data']); } }
public function searchAjax() { $validator = Validator::create(array('package_id' => 'required|integer', 'package_version_id' => 'required|integer', 'brand_id' => 'required|integer', 'os_version_id' => 'required|integer', 'product_id' => 'required|integer', 'model_id' => 'required|integer', 'country_id' => 'required|integer', 'provider_id' => 'required|integer', 'date_from' => null, 'date_to' => null, 'stack_trace_id' => 'required|integer')); if ($validator->failed()) { Application::throwError(400, 'Bad request'); } else { $params = $validator->getParamsObj(); $prms = array(); $query = new ResultSet(); $count = new Select(); $count->from('crash_archive', 'a')->field('COUNT(*)', 'total'); $query->from('crash_archive', 'a')->field('a.id')->field('a.created_at')->leftJoin('package p', 'p.id', '=', 'a.package_id')->field('p.name', 'package_name')->leftJoin('package_version pv', 'pv.id', '=', 'a.package_version_id')->field('pv.value', 'package_version')->leftJoin('brand b', 'b.id', '=', 'a.brand_id')->field('b.name', 'brand_name')->leftJoin('stack_trace st', 'st.id', '=', 'a.stack_trace_id')->field('st.summary', 'stack_trace')->leftJoin('version v', 'v.id', '=', 'a.os_version_id')->field('v.os', 'os_name')->field('v.name', 'os_version_name')->leftJoin('country c', 'c.id', '=', 'a.country_id')->field('c.country', 'country_name')->field('c.tld', 'tld'); if ($params->date_from !== null) { $dateFrom = new DateTime($params->date_from); $query->where('a.created_at', '>=', Misc::utcFromUser('Y-m-d H:i:s', $dateFrom)); $count->where('a.created_at', '>=', Misc::utcFromUser('Y-m-d H:i:s', $dateFrom)); $prms['date_from'] = $params->date_from; } if ($params->date_to !== null) { $dateTo = new DateTime($params->date_to); $query->where('a.created_at', '<', Misc::utcFromUser('Y-m-d H:i:s', $dateTo)); $count->where('a.created_at', '<', Misc::utcFromUser('Y-m-d H:i:s', $dateTo)); $prms['date_to'] = $params->date_to; } if ($params->package_id > 0) { $query->where('a.package_id', $params->package_id); $count->where('a.package_id', $params->package_id); $prms['package_id'] = $params->package_id; } if ($params->package_version_id > 0) { $query->where('a.package_version_id', $params->package_version_id); $count->where('a.package_version_id', $params->package_version_id); $prms['package_version_id'] = $params->package_version_id; } if ($params->brand_id > 0) { $query->where('a.brand_id', $params->brand_id); $count->where('a.brand_id', $params->brand_id); $prms['brand_id'] = $params->brand_id; } if ($params->os_version_id > 0) { $query->where('a.os_version_id', $params->os_version_id); $count->where('a.os_version_id', $params->os_version_id); $prms['os_version_id'] = $params->os_version_id; } if ($params->product_id > 0) { $query->where('a.product_id', $params->product_id); $count->where('a.product_id', $params->product_id); $prms['product_id'] = $params->product_id; } if ($params->model_id > 0) { $query->where('a.model_id', $params->model_id); $count->where('a.model_id', $params->model_id); $prms['model_id'] = $params->model_id; } if ($params->country_id > 0) { $query->where('a.country_id', $params->country_id); $count->where('a.country_id', $params->country_id); $prms['country_id'] = $params->country_id; } if ($params->provider_id > 0) { $query->where('a.provider_id', $params->provider_id); $count->where('a.provider_id', $params->provider_id); $prms['provider_id'] = $params->provider_id; } if ($params->stack_trace_id > 0) { $query->where('a.stack_trace_id', $params->stack_trace_id); $count->where('a.stack_trace_id', $params->stack_trace_id); $prms['stack_trace_id'] = $params->stack_trace_id; } if (sizeof($prms) == 1) { // speed up count(*) ... because we have that precalculated if (isset($prms['stack_trace_id'])) { $count = new Select(); $count->from('stack_trace')->field('total')->where('id', $prms['stack_trace_id']); } else { if (isset($prms['brand_id'])) { $count = new Select(); $count->from('brand')->field('total')->where('id', $prms['brand_id']); } else { if (isset($prms['package_id'])) { $count = new Select(); $count->from('package')->field('total')->where('id', $prms['package_id']); } else { if (isset($prms['package_version_id'])) { $count = new Select(); $count->from('package_version')->field('total')->where('id', $prms['package_version_id']); } else { if (isset($prms['os_version_id'])) { $count = new Select(); $count->from('version')->field('total')->where('id', $prms['os_version_id']); } else { if (isset($prms['country_id'])) { $count = new Select(); $count->from('country')->field('total')->where('id', $prms['country_id']); } else { if (isset($prms['provider_id'])) { $count = new Select(); $count->from('provider')->field('total')->where('id', $prms['provider_id']); } else { if (isset($prms['model_id'])) { $count = new Select(); $count->from('phone_model')->field('total')->where('id', $prms['model_id']); } } } } } } } } } $query->setCountQuery($count); return BootstrapUI::tableRemoteResponse()->column('country_name', function ($value, $row) { if ($row['tld'] !== null) { $country = \Koldy\Html::quotes($row['country_name']); return '<img src="' . \Koldy\Url::link("img/flag/{$row['tld']}.png") . '" title="' . $country . '" />'; } else { return ''; } })->column('created_at', function ($value, $row) { $user = \Koldy\Session::get('user'); return \Koldy\Timezone::date($user['timezone'], 'd.m.Y', strtotime($value)) . '<br/>' . \Koldy\Timezone::date($user['timezone'], 'H:i:s', strtotime($value)); })->column('package_name', function ($value, $row) { $html = $value; $html .= "<details><summary>View stack trace summary</summary><pre class=\"text-danger\">{$row['stack_trace']}</pre></details>"; return $html; })->column('package_version')->column('brand_name')->column('os_version_name', function ($value, $row) { return "{$row['os_name']} {$row['os_version_name']}"; })->column('country')->column('action', function ($value, $row) { return \Bootstrap::anchor(\Bootstrap::icon('eye-open'), \Koldy\Url::href('report', $row['id']))->title('View report')->size('xs'); })->resultSet($query)->handle(); } }
/** * Calculate for reports * @return boolean */ public function calculate() { if (Status::isCalculationInProgress()) { Log::info('Trying to start calculation, but calculation is already in progress. Last was started on ' . Status::getLastCalculationProcessStart() . ' UTC'); return false; } ini_set('memory_limit', '512M'); set_time_limit(0); Status::calculationStarted(); Status::setCalculationStatus('Initializing'); Log::info('Calculation started'); /** * metas: 'file_path', 'build', 'environment', 'settings_global', 'settings_system', 'settings_secure', * 'device_features', 'shared_preferences', 'initial_configuration', 'crash_configuration', * 'dumpsys_meminfo', 'display', 'stack_trace', 'logcat', 'tktal_mem_size', '@evice_features', 'installation_id' */ $query = new Select(); $query->from('crash_submit')->field('id')->limit(0, 200000); $maxQuery = CrashArchive::query()->field('MAX(created_at)', 'time'); $max = $maxQuery->fetchFirstObj(); unset($maxQuery); $lastDatetime = new DateTime(gmdate('Y-m-d H:00:00')); $lastDatetime->modify('-1 hour'); $query->where('created_at', '<', $lastDatetime->format('Y-m-d H:i:s')); $ids = $query->fetchAllObj(); $sizeofIds = sizeof($ids); Log::info('Loaded ids: ' . $sizeofIds); $brandTotals = $countryTotals = $packageTotals = $packageVersionTotals = $phoneModelTotals = $productTotals = $providerTotals = $stackTraceTotals = $osVersionTotals = array(); foreach ($ids as $index => $r) { // on every 25 records, we should ask ourself: is that it? if ($index % 25 == 0) { $shouldTerminate = Status::shouldCalcuationTerminate(); if ($shouldTerminate !== false) { Log::info("Noticed request for calculation termination on {$shouldTerminate}. Aborted!"); Status::setCalculationStatus('Terminated after ' . ($index + 1) . ' records'); Status::terminateCalculation(false); return false; } } $id = $r->id; // record by record Log::info("Will now fetch id={$id}"); if ($index % 15 == 0) { $percent = round($index / $sizeofIds * 100, 2); Status::setCalculationStatus("Working; {$index}/{$sizeofIds} {$percent}%"); } $submit = CrashSubmit::fetchOne($id); if ($submit !== false && $submit->package_name !== null && trim($submit->package_name !== null) != '') { $appStartTime = strtotime($submit->user_app_start_date); $appCrashTime = strtotime($submit->user_crash_date); $appLifetime = $appCrashTime - $appStartTime; $metas = $submit->getMetas(); if ($submit->report_id !== null && trim($submit->report_id) !== '') { $metas['report_id'] = $submit->report_id; } if ($submit->file_path !== null && trim($submit->file_path) !== '') { $metas['file_path'] = $submit->file_path; } if ($submit->installation_id !== null && trim($submit->installation_id) !== '') { $metas['installation_id'] = $submit->installation_id; } $stackTrace = $submit->stack_trace; if ($stackTrace === null) { $stackTraceSummary = null; } else { $metas['stack_trace'] = $stackTrace; $stackTraceSummary = StackTrace::getSummary($stackTrace); } $packageId = $this->getPackageId($submit->package_name); $packageVersionId = $this->getPackageVersionId($this->getPackageId($submit->package_name), $submit->app_version_name); $brandId = $this->getBrandId($submit->brand); $phoneModelId = $this->getModelId($this->getBrandId($submit->brand), $submit->phone_model); $productId = $this->getProductId($this->getBrandId($submit->brand), $submit->product); $osVersionId = $this->getOsVersion($submit->os, $submit->android_version); $stackTraceId = $this->getStackTraceId($stackTraceSummary, $submit->created_at); $countryId = $this->getCountryId($submit->country); $providerId = $this->getProviderId($submit->provider); $archive = CrashArchive::create(array('created_at' => $submit->created_at, 'package_id' => $packageId, 'package_version_id' => $packageVersionId, 'brand_id' => $brandId, 'model_id' => $phoneModelId, 'product_id' => $productId, 'os' => $submit->os, 'os_version_id' => $osVersionId, 'total_mem_size' => $submit->total_mem_size, 'available_mem_size' => $submit->available_mem_size, 'user_comment' => trim($submit->user_comment) == '' ? null : trim($submit->user_comment), 'user_email' => trim($submit->user_email) == 'N/A' ? null : trim($submit->user_email), 'user_app_start_date' => $submit->user_app_start_date, 'user_crash_date' => $submit->user_crash_date, 'user_app_lifetime' => $appLifetime, 'stack_trace_id' => $stackTraceId, 'country_id' => $countryId, 'provider_id' => $providerId)); $archive->insertMeta($metas); // prepare increments for totals if ($packageId !== null) { if (!isset($packageTotals[$packageId])) { $packageTotals[$packageId] = 0; } $packageTotals[$packageId]++; } if ($packageVersionTotals !== null) { if (!isset($packageVersionTotals[$packageVersionId])) { $packageVersionTotals[$packageVersionId] = 0; } $packageVersionTotals[$packageVersionId]++; } if ($brandId !== null) { if (!isset($brandTotals[$brandId])) { $brandTotals[$brandId] = 0; } $brandTotals[$brandId]++; } if ($phoneModelId !== null) { if (!isset($phoneModelTotals[$phoneModelId])) { $phoneModelTotals[$phoneModelId] = 0; } $phoneModelTotals[$phoneModelId]++; } if ($productId !== null) { if (!isset($productTotals[$productId])) { $productTotals[$productId] = 0; } $productTotals[$productId]++; } if ($osVersionTotals !== null) { if (!isset($osVersionTotals[$osVersionId])) { $osVersionTotals[$osVersionId] = 0; } $osVersionTotals[$osVersionId]++; } if ($stackTraceId !== null) { if (!isset($stackTraceTotals[$stackTraceId])) { $stackTraceTotals[$stackTraceId] = 0; } $stackTraceTotals[$stackTraceId]++; } if ($countryId !== null) { if (!isset($countryTotals[$countryId])) { $countryTotals[$countryId] = 0; } $countryTotals[$countryId]++; } if ($providerId !== null) { if (!isset($providerTotals[$providerId])) { $providerTotals[$providerId] = 0; } $providerTotals[$providerId]++; } } } if ($sizeofIds > 0) { Log::info('Calculation done'); Status::setCalculationStatus('Starting to delete submit records'); $deleteIds = array(); foreach ($ids as $index => $r) { $deleteIds[] = $r->id; if (sizeof($deleteIds) == 100) { $percent = round($index / $sizeofIds * 100, 2); Status::setCalculationStatus("Deleting submit records {$index}/{$sizeofIds} {$percent}%"); Db::delete('crash_submit_meta')->whereIn('submit_id', $deleteIds)->exec(); Db::delete('crash_submit')->whereIn('id', $deleteIds)->exec(); $deleteIds = array(); } } if (sizeof($deleteIds) > 0) { Status::setCalculationStatus("Deleting submit records {$index}/{$sizeofIds} 100%"); Db::delete('crash_submit_meta')->whereIn('submit_id', $deleteIds)->exec(); Db::delete('crash_submit')->whereIn('id', $deleteIds)->exec(); } Status::setCalculationStatus('Started totals calculations update!'); // update calculated increments foreach ($brandTotals as $id => $total) { Status::setCalculationStatus('Brands: Updating calculated totals'); Db::update('brand')->increment('total', $total)->where('id', $id)->exec(); } foreach ($countryTotals as $id => $total) { Status::setCalculationStatus('Countries: Updating calculated totals'); Db::update('country')->increment('total', $total)->where('id', $id)->exec(); } foreach ($packageTotals as $id => $total) { Status::setCalculationStatus('Packages: Updating calculated totals'); Db::update('package')->increment('total', $total)->where('id', $id)->exec(); } foreach ($packageVersionTotals as $id => $total) { Status::setCalculationStatus('Package version: Updating calculated totals'); Db::update('package_version')->increment('total', $total)->where('id', $id)->exec(); } foreach ($phoneModelTotals as $id => $total) { Status::setCalculationStatus('Phone models: Updating calculated totals'); Db::update('phone_model')->increment('total', $total)->where('id', $id)->exec(); } foreach ($productTotals as $id => $total) { Status::setCalculationStatus('Products: Updating calculated totals'); Db::update('product')->increment('total', $total)->where('id', $id)->exec(); } foreach ($providerTotals as $id => $total) { Status::setCalculationStatus('Providers: Updating calculated totals'); Db::update('provider')->increment('total', $total)->where('id', $id)->exec(); } foreach ($stackTraceTotals as $id => $total) { Status::setCalculationStatus('Stack traces: Updating calculated totals'); Db::update('stack_trace')->increment('total', $total)->where('id', $id)->exec(); } foreach ($osVersionTotals as $id => $total) { Status::setCalculationStatus('OS version: Updating calculated totals'); Db::update('version')->increment('total', $total)->where('id', $id)->exec(); } } else { // Log::info('Calculation done, no records processed'); } Status::calculationFinished($sizeofIds); return true; }