예제 #1
0
 public function __construct($stackTraceId, $days)
 {
     $this->title("Last {$days} days analysis")->titleOnYAxis('count per day');
     $offset = \Misc::getUserTimezoneOffsetInMinutes();
     $cacheKey = "stacks-{$stackTraceId}-per-last-{$days}-days-offset-{$offset}min";
     $from = new \DateTime(\Misc::userDate('Y-m-d 00:00:00'));
     $from->modify("-{$days} day");
     $records = Cache::getOrSet($cacheKey, function () use($from, $stackTraceId, $days, $offset) {
         $operator = $offset < 0 ? '-' : '+';
         $offsetAbs = abs($offset);
         $today = new \DateTime(\Misc::userDate('Y-m-d 00:00:00'));
         $query = \Crash\Archive::query()->field("DATE(created_at + INTERVAL {$offset} MINUTE)", 'time')->field('COUNT(*)', 'total')->where('stack_trace_id', $stackTraceId)->where('created_at', '>=', \Db::expr("'{$from->format('Y-m-d H:i:s')}' {$operator} INTERVAL {$offsetAbs} MINUTE"))->groupBy(1)->orderBy(1);
         return $query->fetchAllObj();
     }, 3720 - date('i') * 60 + date('s'));
     $data = array();
     foreach ($records as $r) {
         $data[$r->time] = $r->total;
     }
     $serieData = array();
     $startMinute = (int) $from->format('i');
     for ($day = $from, $today = \Misc::userDate('Y-m-d'); $day->format('Y-m-d') <= $today; $day->modify('+1 day')) {
         $date = $day->format('Y-m-d');
         $serieData[$date] = isset($data[$date]) ? (int) $data[$date] : 0;
         $this->addOnXAxis($day->format('jS'));
     }
     $this->addSerie('requests', array_values($serieData));
 }
 public function versionsAjax()
 {
     $packageId = (int) Input::post('package_id');
     if ($packageId <= 0) {
         Application::throwError(400, 'Bad request');
     }
     $resultSet = new Package\ResultSet\Version();
     $resultSet->setPackageId($packageId, Input::post('last'));
     $timeFrom = $resultSet->getFromTime();
     return BootstrapUI::tableRemoteResponse()->primaryKey('package_version_id')->column('total', function ($value, $row) {
         return \Bootstrap::label($value)->color('red');
     })->column('name')->column('action', function ($value, $row) use($packageId, $timeFrom) {
         return \Bootstrap::anchor(\Bootstrap::icon('search'), \Koldy\Url::href('reports', 'search', array('package_version_id' => $row['package_version_id'], 'date_from' => \Misc::userDate('Y-m-d H:i:s', strtotime($timeFrom)))))->title('Find reports with this package version')->asButton()->size('xs')->color('red');
     })->resultSet($resultSet)->handle();
 }
예제 #3
0
 /**
  * Show the page with user edit form
  */
 public function editUserAction()
 {
     $id = (int) Url::getVar(2);
     $user = User::fetchOne($id);
     if ($user === false) {
         Application::throwError(404, "Can not find user");
     }
     $title = "Edit user {$user->username}";
     $elements = array(\Bootstrap::h(1, $title), \Bootstrap::panel("User #{$id}", $this->getUserForm($user->getData()))->color('blue'));
     if ($user->last_login !== null) {
         $info = \Bootstrap::alert('User logged in last time at ' . Misc::userDate('Y-m-d H:i:s', $user->last_login) . " from {$user->last_login_ip}")->color('info');
         $elements[] = $info;
     }
     $content[] = Bootstrap::row()->add(8, $elements, 2);
     return View::create('base')->with('title', $title)->with('content', $content);
 }
예제 #4
0
 public function __construct($days)
 {
     $user = Session::get('user');
     $this->title("Crash reports per days (UTC time)")->titleOnYAxis('number of requests')->tooltipShared();
     // 		$offset = \Misc::getUserTimezoneOffsetInMinutes();
     $offset = 0;
     $cacheKey = "DashboardDays-last-{$days}-days-offset-{$offset}min";
     $data = Cache::getOrSet($cacheKey, function () use($days, $offset) {
         $datetime = new \DateTime(\Misc::userDate('Y-m-d 00:00:00'));
         $datetime->modify("-{$days} day");
         $query = new Select();
         $query->from('crash_archive', 'a')->field('DATE(a.created_at)', 'time')->field('COUNT(*)', 'total')->where('a.created_at', '>=', $datetime->format('Y-m-d H:i:s'))->orderBy(1, 'asc')->groupBy(1);
         $records = $query->fetchAllObj();
         $data = array();
         foreach ($records as $r) {
             $data[$r->time] = (int) $r->total;
         }
         return $data;
     }, 3720 - date('i') * 60 + date('s'));
     // get data in last 30 days per package per date
     /*
     $query = new Select();
     $query
     	->from('crash_archive', 'a')
     	->field('DATE(a.created_at)', 'date')
     	->field('a.package_id')
     	->field('COUNT(*)', 'total')
     	
     	->innerJoin('package p', 'p.id', '=', 'a.package_id')
     	->field('p.name', 'package_name')
     	
     	->where('a.created_at', '>=', $datetime->format('Y-m-d H:i:s'))
     	->groupBy(2)
     	->groupBy(1)
     	->orderBy(1)
     	->orderBy(2)
     	->orderBy(4, 'DESC');
     
     $records = $query->fetchAllObj();
     $apps = $appName = array();
     foreach ($records as $r) {
     	if (!isset($apps[$r->package_id])) {
     		$apps[$r->package_id] = array();
     		$appName[$r->package_id] = $r->package_name;
     	}
     	
     	$apps[$r->package_id][$r->date] = (int) $r->total;
     }
     */
     $start = new \DateTime(gmdate('Y-m-d'));
     $days--;
     $start->modify("-{$days} day");
     $serieData = $appsData = array();
     $today = \Misc::userDate('Y-m-d');
     do {
         $pointer = $start->format('Y-m-d');
         $serieData[$pointer] = isset($data[$pointer]) ? $data[$pointer] : 0;
         // 			foreach ($apps as $packageId => $dates) {
         // 				if (!isset($apps[$packageId][$pointer])) {
         // 					$apps[$packageId][$pointer] = 0;
         // 				}
         // 			}
         $start->modify('+1 day');
     } while ($pointer < $today);
     $this->addSerie('total requests', array_values($serieData));
     /*foreach ($apps as $packageId => $dates) {
     			if (sizeof($this->series) < 6) {
     				ksort($dates);
     				$this->addSerie($appName[$packageId], array_values($dates));
     			}
     		}*/
     foreach (array_keys($serieData) as $key) {
         $date = new \DateTime($key);
         $this->addOnXAxis($date->format('jS'));
     }
 }
 public function indexAjax()
 {
     $where = array();
     $bindings = array();
     $params = Input::requireParams('package', 'package_version', 'brand', 'phone_model', 'product', 'os_version', 'country');
     // package
     if ($params->package !== '') {
         $a = explode(',', $params->package);
         $vals = array();
         foreach ($a as $val) {
             $vals[] = "s.package_name = ?";
             $bindings[] = $val;
         }
         $vals = '(' . implode(' OR ', $vals) . ')';
         $where[] = $vals;
     }
     // package_version
     if ($params->package_version !== '') {
         $a = explode(',', $params->package_version);
         $vals = array();
         foreach ($a as $val) {
             $vals[] = "s.app_version_name = ?";
             $bindings[] = $val;
         }
         $vals = '(' . implode(' OR ', $vals) . ')';
         $where[] = $vals;
     }
     // brand
     if ($params->brand !== '') {
         $a = explode(',', $params->brand);
         $vals = array();
         foreach ($a as $val) {
             $vals[] = "s.brand = ?";
             $bindings[] = $val;
         }
         $vals = '(' . implode(' OR ', $vals) . ')';
         $where[] = $vals;
     }
     // phone_model
     if ($params->phone_model !== '') {
         $a = explode(',', $params->phone_model);
         $vals = array();
         foreach ($a as $val) {
             $vals[] = "s.phone_model = ?";
             $bindings[] = $val;
         }
         $vals = '(' . implode(' OR ', $vals) . ')';
         $where[] = $vals;
     }
     // product
     if ($params->product !== '') {
         $a = explode(',', $params->product);
         $vals = array();
         foreach ($a as $val) {
             $vals[] = "s.product = ?";
             $bindings[] = $val;
         }
         $vals = '(' . implode(' OR ', $vals) . ')';
         $where[] = $vals;
     }
     // os_version
     if ($params->os_version !== '') {
         $a = explode(',', $params->os_version);
         $vals = array();
         foreach ($a as $val) {
             $vals[] = "s.android_version = ?";
             $bindings[] = $val;
         }
         $vals = '(' . implode(' OR ', $vals) . ')';
         $where[] = $vals;
     }
     // country
     if ($params->country !== '') {
         $a = explode(',', $params->country);
         $vals = array();
         foreach ($a as $val) {
             $vals[] = "s.country = ?";
             $bindings[] = $val;
         }
         $vals = '(' . implode(' OR ', $vals) . ')';
         $where[] = $vals;
     }
     if (sizeof($where) == 0) {
         $where = '1';
     } else {
         $where = implode(' AND ', $where);
     }
     $query = "\n\t\t\tSELECT\n\t\t\t\ts.id,\n\t\t\t\ts.created_at,\n\t\t\t\ts.package_name,\n\t\t\t\ts.app_version_name as package_version,\n\t\t\t\ts.brand,\n\t\t\t\ts.phone_model,\n\t\t\t\ts.product,\n\t\t\t\ts.android_version,\n\t\t\t\ts.country,\n\t\t\t\ts.stack_trace\n\t\t\tFROM\n\t\t\t\tcrash_submit s\n\t\t\tWHERE\n\t\t\t\t{$where}\n\t\t\tORDER BY s.created_at DESC\n\t\t\tLIMIT 0, 50\n\t\t";
     $records = Db::getAdapter()->query($query, $bindings);
     $data = array();
     foreach ($records as $r) {
         if ($r->stack_trace !== null) {
             $lines = explode("\n", $r->stack_trace);
             $stackTraceSummary = array();
             $more = 0;
             foreach ($lines as $line) {
                 $ord = ord(substr($line, 0, 1));
                 if ($ord >= 65 && $ord <= 90 || $ord >= 97 && $ord <= 122) {
                     if (sizeof($stackTraceSummary) < 2) {
                         $stackTraceSummary[] = trim($line);
                     } else {
                         $more++;
                     }
                 }
             }
             if ($more > 0) {
                 $stackTraceSummary[] = "... and {$more} more line(s)";
             }
             $stackTraceSummary = implode("\n", $stackTraceSummary);
         } else {
             $stackTraceSummary = null;
         }
         $data[] = array('id' => (int) $r->id, 'created_at' => Misc::userDate('H:i:s', $r->created_at), 'package' => "{$r->package_name} {$r->package_version}", 'device' => "{$r->brand}<br/>{$r->phone_model}", 'product' => $r->phone_model != $r->product ? $r->product : null, 'os' => "Android {$r->android_version}", 'country' => $r->country, 'stack_trace' => $stackTraceSummary);
     }
     return Json::create(array('success' => true, 'time' => Misc::userDate('Y-m-d H:i:s'), 'data' => $data));
 }
예제 #6
0
 public function viewAction()
 {
     $id = Url::getVar(1);
     // todo: ubaciti ovo u cache i odatle cupat van
     $cacheKey = "report-{$id}";
     $crash = CrashArchive::fetchOne($id);
     if ($crash === false) {
         Application::throwError(404, 'Can not find crash report ' . $id);
     }
     $title = "Crash Report #{$id}";
     $content = array();
     $panel = Bootstrap::panel($title)->color('blue')->addHeaderElement(Bootstrap::button('Back')->setAttribute('onclick', 'window.history.back()')->color('red')->size('xs'));
     $table = Bootstrap::table();
     $table->column('id', '')->column('value', '');
     // time
     $table->row(array('id' => 'time', 'value' => Misc::userDate('Y-m-d H:i:s', $crash->created_at) . ' (' . $this->user['timezone'] . ')'));
     // package
     $e = $crash->getPackage();
     $v = $crash->getPackageVersion();
     $table->row(array('id' => 'package and version', 'value' => implode(' ', array($e !== null ? "{$this->getSearchLink('package_id', $e->id, $e->name)} {$this->getLabel($e->total)}" : 'unknown', $v !== null ? "{$this->getSearchLink('package_version_id', $v->id, $v->value)} {$this->getLabel($v->total)}" : 'unknown'))));
     // device
     $value = '';
     $e = $crash->getBrand();
     if ($e === null) {
         $value .= 'unknown brand<br/>';
     } else {
         $value .= "{$this->getSearchLink('brand_id', $e->id, $e->name)} {$this->getLabel($e->total)}<br/>";
     }
     $e = $crash->getPhoneModel();
     if ($e === null) {
         $value .= 'unknown phone model<br/>';
     } else {
         $value .= "{$this->getSearchLink('model_id', $e->id, $e->name)} {$this->getLabel($e->total)}<br/>";
     }
     $table->row(array('id' => 'device', 'value' => substr($value, 0, -5)));
     // product
     $e = $crash->getProduct();
     if ($e !== null) {
         $table->row(array('id' => 'product name', 'value' => "{$this->getSearchLink('product_id', $e->id, $e->name)} {$this->getLabel($e->total)}"));
     }
     // os
     $e = $crash->getOsVersion();
     $table->row(array('id' => 'OS', 'value' => $e === null ? 'unknown' : "{$this->getSearchLink('os_version_id', $e->id, "{$e->os} {$e->name}")} {$this->getLabel($e->total)}"));
     // user comment
     if ($crash->user_comment !== null && trim($crash->user_comment) != '') {
         $table->row(array('id' => 'user comment', 'value' => $crash->user_comment));
     }
     // user email
     if ($crash->user_email !== null && trim($crash->user_email) != '') {
         $table->row(array('id' => 'user email', 'value' => $crash->user_email));
     }
     // app lifetime
     if ($crash->user_app_start_date !== null && $crash->user_crash_date !== null) {
         $table->row(array('id' => 'app lifetime', 'value' => "{$crash->user_app_start_date}<br/>{$crash->user_crash_date} (duration: {$this->duration($crash->user_app_start_date, $crash->user_crash_date)})"));
     }
     // memory usage
     $table->row(array('id' => 'available / total memory size', 'value' => Convert::bytesToString($crash->available_mem_size) . ' / ' . Convert::bytesToString($crash->total_mem_size)));
     // country
     if ($crash->country_id !== null) {
         $country = Country::fetchOne($crash->country_id);
         $table->row(array('id' => 'country', 'value' => "<img src=\"" . Url::link("img/flag/{$country->tld}.png") . "\" /> <a href=\"" . Url::href('reports', 'search', array('country_id' => $crash->country_id)) . "\">{$country->country} (" . strtoupper($country->tld) . ")</a> " . Bootstrap::label($country->total)->color('red')));
     }
     // provider
     if ($crash->provider_id !== null) {
         $e = Provider::fetchOne($crash->provider_id);
         $table->row(array('id' => 'internet provider', 'value' => "{$this->getSearchLink('provider_id', $e->id, $e->name)} {$this->getLabel($e->total)}"));
     }
     $metas = $crash->getMetas();
     $toTabs = array();
     foreach ($metas as $key => $value) {
         if ($key != 'stack_trace') {
             if (strpos(trim($value), "\n") === false) {
                 $table->row(array('id' => str_replace('_', ' ', $key), 'value' => trim($value) == '' ? '<em>empty</em>' : $value));
             } else {
                 $toTabs[] = $key;
             }
         }
     }
     $toTabsUnknown = array();
     $unknownMetas = $crash->getUnknownMetas();
     foreach ($unknownMetas as $key => $value) {
         if (strpos(trim($value), "\n") === false) {
             $table->row(array('id' => str_replace('_', ' ', $key), 'value' => (trim($value) == '' ? '<em>empty</em>' : $value) . ' ' . Bootstrap::label('unknown meta')->color('lightblue')));
         } else {
             $toTabsUnknown[] = $key;
         }
     }
     if ($crash->stack_trace_id !== null) {
         $table->row(array('id' => 'find reports with this stack trace', 'value' => Bootstrap::anchor(\Bootstrap::icon('search'), Url::href('reports', 'search', array('stack_trace_id' => $crash->stack_trace_id)))->asButton()->color('red')->size('xs')));
     }
     $panel->content($table);
     $content[] = Bootstrap::row()->add(12, $panel);
     $tabs = Bootstrap::nav();
     if (isset($metas['stack_trace'])) {
         $tabs->addLink('stack trace', "<pre class=\"text-danger\">{$metas['stack_trace']}</pre>");
     } else {
         if ($crash->stack_trace_id !== null) {
             $stackTrace = Stack\Trace::fetchOne($crash->stack_trace_id);
             $tabs->addLink('stack trace summary', "<pre class=\"text-danger\">{$stackTrace->summary}</pre>");
         }
     }
     if (sizeof($toTabs) > 0) {
         foreach ($toTabs as $key) {
             $tabs->addLink(str_replace('_', ' ', $key), "<pre>{$metas[$key]}</pre>");
         }
     }
     if (sizeof($toTabsUnknown) > 0) {
         foreach ($toTabsUnknown as $key) {
             $tabs->addLink(str_replace('_', ' ', $key) . ' ' . Bootstrap::label('?')->color('lightblue'), "<pre>{$unknownMetas[$key]}</pre>");
         }
     }
     if ($tabs->count() > 0) {
         $content[] = Bootstrap::row()->add(12, $tabs);
     }
     if ($crash->stack_trace_id !== null) {
         $content[] = Bootstrap::row()->add(12, Bootstrap::panel('This error count per day', new Chart\StackTracesPerDay($crash->stack_trace_id, 30))->color('red'));
     }
     return View::create('base')->with('title', $title)->with('content', $content);
 }