PageRenderTime 41ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/webapp-php/application/models/daily.php

https://github.com/hfeeki/socorro
PHP | 1022 lines | 655 code | 115 blank | 252 comment | 123 complexity | 80170429f61b414ba9474884ee029bd1 MD5 | raw file
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. require_once(Kohana::find_file('libraries', 'timeutil', TRUE, 'php'));
  6. /**
  7. * Model class for ADU, a.k.a. Active Daily Users / Installs.
  8. *
  9. * @package SocorroUI
  10. * @subpackage Models
  11. * @author Ryan Snyder <rsnyder@mozilla.com>
  12. */
  13. class Daily_Model extends Model {
  14. /**
  15. * The timestamp for today's date.
  16. */
  17. public $today = 0;
  18. /**
  19. * Class Constructor
  20. */
  21. public function __construct()
  22. {
  23. parent::__construct();
  24. $config = array();
  25. $credentials = Kohana::config('webserviceclient.basic_auth');
  26. if ($credentials) {
  27. $config['basic_auth'] = $credentials;
  28. }
  29. $this->service = new Web_Service($config);
  30. $this->today = strtotime(date('Y-m-d'));
  31. }
  32. /**
  33. * Prepare the statistics for Crashes per ADU by Operating System.
  34. *
  35. * The idea of throttled users were implemented in Socorro 1.5 - https://bugzilla.mozilla.org/show_bug.cgi?id=539337
  36. *
  37. * Throttling is inputted into the UI. It is an effective throttling of client throttling * server throttling. Reported
  38. * Active Daily Users are updated according to throttling percentages.
  39. *
  40. * @access public
  41. * @param object The response object from the API call
  42. * @param array An array of effective throttle rates for each version
  43. * @return array An array of statistics
  44. */
  45. public function calculateStatisticsByOS ($results, $throttle)
  46. {
  47. if (!empty($results)) {
  48. if (!empty($throttle)) {
  49. $t = array_shift($throttle);
  50. $throttle_1 = ($t > 0) ? ($t / 100) : 1;
  51. $throttle_2 = 1 - $throttle_1;
  52. $throttle_ratio = $throttle_2 / $throttle_1;
  53. } else {
  54. $throttle_1 = 1;
  55. $throttle_2 = 0;
  56. $throttle_ratio = 0;
  57. }
  58. $statistics = array(
  59. 'ratio' => 0.00,
  60. 'crashes' => 0,
  61. 'os' => array(),
  62. 'throttle' => $throttle_1,
  63. 'users' => 0,
  64. );
  65. foreach ($results->versions as $version) {
  66. foreach ($version->statistics as $v) {
  67. $date = $v->date;
  68. if (strtotime($date) < $this->today) {
  69. $key = $v->os;
  70. if (!isset($statistics['os'][$key])) {
  71. $statistics['os'][$key] = array(
  72. 'crashes' => 0,
  73. 'users' => 0,
  74. 'ratio' => 0.00,
  75. );
  76. }
  77. if (!isset($statistics['os'][$key][$date])) {
  78. $statistics['os'][$key][$date] = array(
  79. 'crashes' => 0,
  80. 'users' => 0,
  81. 'ratio' => 0.00,
  82. );
  83. }
  84. $throttled_crashes = $v->crashes;
  85. if ($throttle_ratio > 0) {
  86. $throttled_crashes += ($v->crashes * $throttle_ratio);
  87. }
  88. $statistics['os'][$key][$date]['crashes'] += $throttled_crashes;
  89. $statistics['os'][$key][$date]['throttle'] = $throttle_1;
  90. $statistics['os'][$key][$date]['users'] += $v->users;
  91. if ($statistics['os'][$key][$date]['crashes'] > 0 && $statistics['os'][$key][$date]['users'] > 0) {
  92. $statistics['os'][$key][$date]['ratio'] = $statistics['os'][$key][$date]['crashes'] / $statistics['os'][$key][$date]['users'];
  93. } else {
  94. $statistics['os'][$key][$date]['ratio'] = 0.00;
  95. }
  96. $statistics['crashes'] += $throttled_crashes;
  97. $statistics['users'] += $v->users;
  98. $statistics['os'][$key]['crashes'] += $throttled_crashes;
  99. $statistics['os'][$key]['users'] += $v->users;
  100. if ($statistics['os'][$key]['crashes'] > 0 && $statistics['os'][$key]['users'] > 0) {
  101. $statistics['os'][$key]['ratio'] = $statistics['os'][$key]['crashes'] / $statistics['os'][$key]['users'];
  102. } else {
  103. $statistics['os'][$key]['ratio'] = 0.00;
  104. }
  105. }
  106. }
  107. }
  108. if ($statistics['crashes'] > 0 && $statistics['users'] > 0) {
  109. $statistics['ratio'] = round(($statistics['crashes'] / $statistics['users']), 2);
  110. } else {
  111. $statistics['ratio'] = 0.00;
  112. }
  113. return $statistics;
  114. }
  115. return false;
  116. }
  117. /**
  118. * Returns the correct UI string for the provided OS
  119. *
  120. * @param string operating system name
  121. * @return string correctly formatted OS string
  122. */
  123. private function getOSDisplayName($os)
  124. {
  125. $formattedOS = "";
  126. if(stripos($os, "win") !== false) {
  127. $formattedOS = Kohana::config('platforms.win_name');
  128. } else if(stripos($os, "mac") !== false) {
  129. $formattedOS = Kohana::config('platforms.mac_name');
  130. } else if(stripos($os, "lin") !== false) {
  131. $formattedOS = Kohana::config('platforms.lin_name');
  132. } else {
  133. $formattedOS = "Unsupported OS Name.";
  134. }
  135. return $formattedOS;
  136. }
  137. /**
  138. *
  139. */
  140. public function calculateOverallTotal($product_data, $report_type='by_version')
  141. {
  142. $product_info = array();
  143. $versions = array();
  144. $os = array();
  145. $total_users = 0;
  146. $total_crashes = 0;
  147. $ratio = 0.00;
  148. // Extract the version data
  149. foreach (get_object_vars($product_data) as $key => $data) {
  150. $current_key = explode(':', $key);
  151. if($report_type != 'by_os') {
  152. array_push($versions, $current_key[1]);
  153. } else {
  154. array_push($os, $this->getOSDisplayName($current_key[2]));
  155. }
  156. $product_info = $data;
  157. }
  158. // Loop through all items and total up the amounts
  159. foreach ($product_info as $key => $current_item) {
  160. $ratio += $current_item->crash_hadu;
  161. $total_crashes += $current_item->report_count;
  162. $total_users += $current_item->adu;
  163. }
  164. $statistics['ratio'] = $ratio;
  165. $statistics['crashes'] = $total_crashes;
  166. $statistics['users'] = $total_users;
  167. if($report_type != 'by_os') {
  168. $statistics['versions'] = $versions;
  169. } else {
  170. $statistics['os'] = $os;
  171. }
  172. if ($statistics['crashes'] > 0 && $statistics['users'] > 0) {
  173. $statistics['ratio'] = round(($statistics['crashes'] / $statistics['users']), 2);
  174. } else {
  175. $statistics['ratio'] = 0.00;
  176. }
  177. return $statistics;
  178. }
  179. /**
  180. *
  181. */
  182. public function calculateTotalByVersion($statistics, $version_data)
  183. {
  184. // Extract the version data
  185. foreach (get_object_vars($version_data) as $version => $data) {
  186. // We only want the version string not including the product name
  187. $prod_ver = explode(':', $version);
  188. $key = $prod_ver[1];
  189. $ratio = 0.00;
  190. $total_crashes = 0;
  191. $throttle = 0;
  192. $total_users = 0;
  193. $statistics['versions'][$key] = array();
  194. // Loop through the data for the current version and total up the amounts
  195. foreach ($data as $date => $current_version) {
  196. $ratio += $current_version->crash_hadu;
  197. $total_crashes += $current_version->report_count;
  198. $throttle = $current_version->throttle;
  199. $total_users += $current_version->adu;
  200. if (strtotime($date) < $this->today) {
  201. if (!isset($statistics['versions'][$key][$date])) {
  202. $statistics['versions'][$key][$date] = array(
  203. 'crashes' => $current_version->report_count,
  204. 'users' => $current_version->adu,
  205. 'ratio' => $current_version->crash_hadu,
  206. 'throttle' => $current_version->throttle,
  207. );
  208. }
  209. }
  210. }
  211. $statistics['versions'][$key]['ratio'] = $ratio;
  212. $statistics['versions'][$key]['crashes'] = $total_crashes;
  213. $statistics['versions'][$key]['throttle'] = $throttle;
  214. $statistics['versions'][$key]['users'] = $total_users;
  215. $statistics['versions'][$key]['version'] = $key;
  216. }
  217. return $statistics;
  218. }
  219. /**
  220. *
  221. */
  222. public function calculateTotalByOS($statistics, $os_data)
  223. {
  224. // Extract the OS data
  225. foreach (get_object_vars($os_data) as $os => $data) {
  226. $prod_ver_os = explode(':', $os);
  227. $key = $this->getOSDisplayName($prod_ver_os[2]);
  228. $ratio = 0.00;
  229. $total_crashes = 0;
  230. $throttle = 0;
  231. $total_users = 0;
  232. $statistics['os'][$key] = array();
  233. foreach ($data as $date => $current_os) {
  234. $ratio += $current_os->crash_hadu;
  235. $total_crashes += $current_os->report_count;
  236. $throttle = $current_os->throttle;
  237. $total_users += $current_os->adu;
  238. if (!isset($statistics['os'][$key][$date])) {
  239. $statistics['os'][$key][$date] = array(
  240. 'crashes' => $current_os->report_count,
  241. 'users' => $current_os->adu,
  242. 'ratio' => $current_os->crash_hadu,
  243. 'throttle' => $current_os->throttle,
  244. );
  245. if ($statistics['os'][$key][$date]['crashes'] > 0 && $statistics['os'][$key][$date]['users'] > 0) {
  246. $statistics['os'][$key][$date]['ratio'] = $statistics['os'][$key][$date]['crashes'] / $statistics['os'][$key][$date]['users'];
  247. } else {
  248. $statistics['os'][$key][$date]['ratio'] = 0.00;
  249. }
  250. }
  251. }
  252. $statistics['os'][$key]['ratio'] = $ratio;
  253. $statistics['os'][$key]['crashes'] = $total_crashes;
  254. $statistics['os'][$key]['throttle'] = $throttle;
  255. $statistics['os'][$key]['users'] = $total_users;
  256. $statistics['os'][$key]['os'] = $key;
  257. }
  258. return $statistics;
  259. }
  260. /**
  261. *
  262. */
  263. public function calculateStatistics($results, $report_type)
  264. {
  265. $statistics = $this->calculateOverallTotal($results, $report_type);
  266. if ($report_type == 'by_version') {
  267. $statistics = $this->calculateTotalByVersion($statistics, $results);
  268. } elseif ($report_type == 'by_os') {
  269. $statistics = $this->calculateTotalByOS($statistics, $results);
  270. }
  271. return $statistics;
  272. }
  273. /**
  274. * Prepare the statistics for Crashes per ADU by Version.
  275. *
  276. * The idea of throttled users were implemented in Socorro 1.5 - https://bugzilla.mozilla.org/show_bug.cgi?id=539337
  277. *
  278. * Throttling is inputted into the UI. It is an effective throttling of client throttling * server throttling. Reported
  279. * Active Daily Users are updated according to throttling percentages.
  280. *
  281. * @access public
  282. * @param object The response object from the API call
  283. * @param array An array of effective throttle rates for each version
  284. * @return array An array of statistics
  285. */
  286. public function calculateStatisticsByVersion ($results, $throttle)
  287. {
  288. if (!empty($results)) {
  289. $this->calculateTotalForProduct($results);
  290. $statistics = array(
  291. 'ratio' => 0.00,
  292. 'crashes' => 0,
  293. 'versions' => array(),
  294. 'users' => 0,
  295. );
  296. foreach ($results as $key => $version_data) {
  297. if (!empty($throttle)) {
  298. $t = array_shift($throttle);
  299. $throttle_1 = ($t > 0) ? ($t / 100) : 1;
  300. $throttle_2 = 1 - $throttle_1;
  301. $throttle_ratio = $throttle_2 / $throttle_1;
  302. } else {
  303. $throttle_1 = 1;
  304. $throttle_2 = 0;
  305. $throttle_ratio = 0;
  306. }
  307. $statistics['versions'][$key] = array(
  308. 'ratio' => 0.00,
  309. 'crashes' => 0,
  310. 'throttle' => $throttle_1,
  311. 'users' => 0,
  312. 'version' => $key,
  313. );
  314. foreach ($version->statistics as $v) {
  315. $date = $v->date;
  316. if (strtotime($date) < $this->today) {
  317. if (!isset($statistics['versions'][$key][$date])) {
  318. $statistics['versions'][$key][$date] = array(
  319. 'crashes' => 0,
  320. 'users' => 0,
  321. 'ratio' => 0.00,
  322. );
  323. }
  324. $throttled_crashes = $v->crashes;
  325. if ($throttle_ratio > 0) {
  326. $throttled_crashes += ($v->crashes * $throttle_ratio);
  327. }
  328. $statistics['versions'][$key][$date]['crashes'] += $throttled_crashes;
  329. $statistics['versions'][$key][$date]['throttle'] = $throttle_1;
  330. $statistics['versions'][$key][$date]['users'] += $v->users;
  331. if ($statistics['versions'][$key][$date]['crashes'] > 0 && $statistics['versions'][$key][$date]['users'] > 0) {
  332. $statistics['versions'][$key][$date]['ratio'] = $statistics['versions'][$key][$date]['crashes'] / $statistics['versions'][$key][$date]['users'];
  333. } else {
  334. $statistics['versions'][$key][$date]['ratio'] = 0.00;
  335. }
  336. $statistics['crashes'] += $throttled_crashes;
  337. $statistics['users'] += $v->users;
  338. $statistics['versions'][$key]['crashes'] += $throttled_crashes;
  339. $statistics['versions'][$key]['users'] += $v->users;
  340. }
  341. }
  342. if ($statistics['versions'][$key]['crashes'] > 0 && $statistics['versions'][$key]['users'] > 0) {
  343. $statistics['versions'][$key]['ratio'] = $statistics['versions'][$key]['crashes'] / $statistics['versions'][$key]['users'];
  344. } else {
  345. $statistics['versions'][$key]['ratio'] = 0.00;
  346. }
  347. }
  348. if ($statistics['crashes'] > 0 && $statistics['users'] > 0) {
  349. $statistics['ratio'] = $statistics['crashes'] / $statistics['users'];
  350. } else {
  351. $statistics['ratio'] = 0.00;
  352. }
  353. return $statistics;
  354. }
  355. return false;
  356. }
  357. /**
  358. * Prepare an array of parameters for the url.
  359. *
  360. * @access private
  361. * @param array The array that needs to be parameterized.
  362. * @return string The url-encoded string.
  363. */
  364. private function encodeArray (array $parameters) {
  365. $uri = '';
  366. $parameters = array_unique($parameters);
  367. $num_parameters = count($parameters);
  368. for ($i = 0; $i <= $num_parameters; $i++) {
  369. $parameter = array_shift($parameters);
  370. if (!empty($parameter)) {
  371. if ($i > 0) {
  372. $uri .= ";";
  373. }
  374. $uri .= rawurlencode($parameter);
  375. }
  376. }
  377. return $uri;
  378. }
  379. /**
  380. * Format the URL for the ADU web service call.
  381. *
  382. * @access private
  383. * @param string The product name (e.g. 'Camino', 'Firefox', 'Seamonkey, 'Thunderbird')
  384. * @param string The version number (e.g. '3.5', '3.5.1', '3.5.1pre', '3.5.2', '3.5.2pre')
  385. * @param string The Report Type [any|crash|hang]
  386. * @param string The start date for this product YYYY-MM-DD
  387. * @param string The end date for this product YYYY-MM-DD (usually +90 days)
  388. * @return string The URL.
  389. */
  390. private function formatURL ($api, $product, $versions, $hang_type, $operating_systems, $start_date, $end_date) {
  391. $host = Kohana::config('webserviceclient.socorro_hostname');
  392. $p = rawurlencode($product);
  393. $v = $this->encodeArray($versions);
  394. $os = $this->encodeArray($operating_systems);
  395. $start = rawurlencode($start_date);
  396. $end = rawurlencode($end_date);
  397. $url = $host . $api . $p . "/v/" . $v . "/rt/" . $hang_type . "/os/" . $os . "/start/" . $start . "/end/" . $end;
  398. return $url;
  399. }
  400. /**
  401. * Format the URL for the ADU web service call.
  402. *
  403. * @access private
  404. * @param string The product name (e.g. 'Camino', 'Firefox', 'Seamonkey, 'Thunderbird')
  405. * @param string The version number (e.g. '3.5', '3.5.1', '3.5.1pre', '3.5.2', '3.5.2pre')
  406. * @param string The Report Type [any|crash|hang]
  407. * @param string The start date for this product YYYY-MM-DD
  408. * @param string The end date for this product YYYY-MM-DD (usually +90 days)
  409. * @return string The URL.
  410. */
  411. private function formatADUOverviewURL ($product, $versions, $hang_type, $operating_systems, $start_date, $end_date) {
  412. return $this->formatURL("/adu/byday/p/", $product, $versions, $hang_type, $operating_systems, $start_date, $end_date);
  413. }
  414. /**
  415. * Format the URL for the aduByDayDetails web service call.
  416. *
  417. * @access private
  418. * @param string The product name (e.g. 'Camino', 'Firefox', 'Seamonkey, 'Thunderbird')
  419. * @param string The version number (e.g. '3.5', '3.5.1', '3.5.1pre', '3.5.2', '3.5.2pre')
  420. * @param array The Report Types
  421. * @param string The start date for this product YYYY-MM-DD
  422. * @param string The end date for this product YYYY-MM-DD (usually +90 days)
  423. * @return string The URL.
  424. */
  425. private function formatADUDetailsByReportTypeURL ($product, $versions, $report_types, $operating_systems, $start_date, $end_date) {
  426. $rt = $this->encodeArray($report_types);
  427. return $this->formatURL("/adu/byday/details/p/", $product, $versions, $rt, $operating_systems, $start_date, $end_date);
  428. }
  429. private function _sortVersions($versions)
  430. {
  431. $sorted_versions_array = array();
  432. foreach ($versions as $key => $value) {
  433. array_push($sorted_versions_array, $key);
  434. }
  435. usort($sorted_versions_array, function ($a, $b) {
  436. return ($a > $b) ? -1 : 1;
  437. });
  438. return $sorted_versions_array;
  439. }
  440. private function _sortVersionData($version_data)
  441. {
  442. $sorted_version_data_array = array();
  443. foreach ($version_data as $item) {
  444. array_push($sorted_version_data_array, $item);
  445. }
  446. usort($sorted_version_data_array, function ($a, $b) {
  447. return ($a->date < $b->date) ? -1 : 1;
  448. });
  449. return $sorted_version_data_array;
  450. }
  451. /**
  452. * Build data object for front page graph.
  453. *
  454. * @access public
  455. * @param string The start date for this product YYYY-MM-DD
  456. * @param string The end date for this product YYYY-MM-DD
  457. * @param object The individual items from which we extract the ratios for the graph
  458. * @return array The compiled data for the front page graph
  459. */
  460. public function buidDataObjectForGraph($date_start=null, $date_end=null, $response_items=null, $report_type='by_version')
  461. {
  462. $count = count(get_object_vars($response_items));
  463. $counter = 1;
  464. $cadu = array();
  465. $data = array(
  466. 'startDate' => $date_start,
  467. 'endDate' => $date_end,
  468. 'count' => $count,
  469. );
  470. foreach ($response_items as $version => $version_data) {
  471. if ($counter <= $count) {
  472. $key_ratio = 'ratio' . $counter;
  473. $cadu[$key_ratio] = array();
  474. array_push($cadu[$key_ratio], $version);
  475. $version_data_array = $this->_sortVersionData($version_data);
  476. foreach ($version_data_array as $details) {
  477. if(strtotime($details->date) < $this->today) {
  478. array_push($cadu[$key_ratio], array(strtotime($details->date) * 1000, $details->crash_hadu));
  479. }
  480. }
  481. }
  482. $counter++;
  483. }
  484. $data['cadu'] = $cadu;
  485. usort($data['cadu'], function ($a, $b) {
  486. return ($a[0] > $b[0]) ? -1 : 1;
  487. });
  488. return $data;
  489. }
  490. private function _buildDataObjectForCrashReports($response_items)
  491. {
  492. $crashReports = array();
  493. $prod_ver = array();
  494. $version_array = $this->_sortVersions($response_items);
  495. foreach ($version_array as $version) {
  496. if (strrpos($version, ":")) {
  497. $products_versions = explode(":", $version);
  498. }
  499. $prod_ver['product'] = $products_versions[0];
  500. $prod_ver['version'] = $products_versions[1];
  501. array_push($crashReports, $prod_ver);
  502. }
  503. return $crashReports;
  504. }
  505. /**
  506. * Build the service URI from the paramters passed and returns the URI with
  507. * all values rawurlencoded.
  508. *
  509. * @param array url parameters to append and encode
  510. * @param string the main api entry point ex. crashes
  511. * @return string service URI with all values encoded
  512. */
  513. public function buildURI($params, $apiEntry)
  514. {
  515. $separator = "/";
  516. $host = Kohana::config('webserviceclient.socorro_hostname');
  517. $apiData = array(
  518. $host,
  519. $apiEntry
  520. );
  521. foreach ($params as $key => $value) {
  522. $apiData[] = $key;
  523. $apiData[] = (is_array($value) ? $this->encodeArray($value) : rawurlencode($value));
  524. }
  525. $apiData[] = ''; // Trick to have the closing '/'
  526. return implode($separator, $apiData);
  527. }
  528. /**
  529. * Fetch records for active daily users.
  530. *
  531. * @access public
  532. * @param string The product name (e.g. 'Camino', 'Firefox', 'Seamonkey, 'Thunderbird')
  533. * @param string The versions for this product
  534. * @param string The start date for this product YYYY-MM-DD
  535. * @param string The end date for this product YYYY-MM-DD
  536. * @param string The date range for which to fetch record. Should be either 'build' or 'report'
  537. * @param string The string of operating systems selected for this report.
  538. * @param string The hang type selected for this report. Can be one of crash, oopp, hang browser, hang plugin
  539. * @param string The report type selectd, can be one of by_version, by_os, by_report_type
  540. * @return array The compiled data for the front page graph or Crashes per ADU
  541. */
  542. public function getCrashesPerADU($product=null, $versions=null, $start_date=null, $end_date=null,
  543. $date_range_type=null, $operating_systems=null, $report_types=null, $form_selection='by_version')
  544. {
  545. $graph_data = array();
  546. $isDataForGraph = TRUE;
  547. $params['product'] = $product;
  548. $params['versions'] = $versions;
  549. $params['from_date'] = $start_date;
  550. $params['to_date'] = $end_date;
  551. $params['date_range_type'] = $date_range_type;
  552. if ($operating_systems != null) {
  553. $isDataForGraph = FALSE;
  554. $params['os'] = $operating_systems;
  555. // Operating systems can be specified for by version as well but,
  556. // we only want to separate the results by OS if the selected,
  557. // report type was by_os.
  558. if($form_selection == 'by_os') {
  559. $params['separated_by'] = 'os';
  560. }
  561. }
  562. if ($report_types != null) {
  563. $params['report_type'] = $report_types;
  564. }
  565. $url = $this->buildURI($params, "crashes/daily");
  566. $lifetime = Kohana::config('webserviceclient.topcrash_vers_rank_cache_minutes', 60) * 60; // number of seconds
  567. $response = $this->service->get($url, 'json', $lifetime);
  568. if (isset($response) && !empty($response)) {
  569. // If true, data is for the frontpage
  570. if ($isDataForGraph) {
  571. $graph_data = $this->buidDataObjectForGraph($start_date, $end_date, $response->hits);
  572. $graph_data['productVersions'] = $this->_buildDataObjectForCrashReports($response->hits);
  573. return $graph_data;
  574. }
  575. return $response;
  576. }
  577. return false;
  578. }
  579. /**
  580. * Fetch records for active daily users / installs by crash report type
  581. *
  582. * @access public
  583. * @param string The product name (e.g. 'Camino', 'Firefox', 'Seamonkey, 'Thunderbird')
  584. * @param array An array of versions of this product
  585. * @param array An array of operating systems to query
  586. * @param array The Report Type [crash|oopp|hang_browser|hang_plugin]
  587. * @param string The start date for this product YYYY-MM-DD
  588. * @param string The end date for this product YYYY-MM-DD (usually +90 days)
  589. * @return object The database query object
  590. */
  591. public function getDetailsByReportType($product, $versions, $operating_systems, $report_types, $start_date, $end_date) {
  592. $url = $this->formatADUDetailsByReportTypeURL($product, $versions, $report_types, $operating_systems, $start_date, $end_date);
  593. $lifetime = Kohana::config('webserviceclient.topcrash_vers_rank_cache_minutes', 60) * 60; // number of seconds
  594. $response = $this->service->get($url, 'json', $lifetime);
  595. if (isset($response) && !empty($response)) {
  596. return $response;
  597. } else {
  598. Kohana::log('error', "No ADU data was avialable at \"$url\" via soc.web daily.getDetailsByReportType()");
  599. }
  600. return false;
  601. }
  602. /**
  603. * Fetch records for active daily users / installs.
  604. *
  605. * @access public
  606. * @param string The product name (e.g. 'Camino', 'Firefox', 'Seamonkey, 'Thunderbird')
  607. * @param array An array of versions of this product
  608. * @param array An array of operating systems to query
  609. * @param string The start date for this product YYYY-MM-DD
  610. * @param string The end date for this product YYYY-MM-DD (usually +90 days)
  611. * @return object The database query object
  612. * @param string The Report Type [any|crash|hang] - defaults to 'any'
  613. */
  614. public function get($product, $versions, $operating_systems, $start_date, $end_date, $hang_type='any') {
  615. $url = $this->formatADUOverviewURL($product, $versions, $hang_type, $operating_systems, $start_date, $end_date);
  616. $lifetime = Kohana::config('webserviceclient.topcrash_vers_rank_cache_minutes', 60) * 60; // number of seconds
  617. $response = $this->service->get($url, 'json', $lifetime);
  618. if (isset($response) && !empty($response)) {
  619. return $response;
  620. } else {
  621. Kohana::log('error', "No ADU data was avialable at \"$url\" via soc.web daily.get()");
  622. }
  623. return false;
  624. }
  625. /**
  626. * Get version information that includes throttle level from products_versions service
  627. *
  628. * @access public
  629. * @param string The product
  630. * @param string The version number
  631. * @return object The JSON result
  632. */
  633. public function getVersionInfo($product, $versions) {
  634. $host = Kohana::config('webserviceclient.socorro_hostname');
  635. $p = rawurlencode($product);
  636. $v = $this->encodeArray($versions);
  637. $url = $host . "/products/versions/" . $p . ":" . $v;
  638. $lifetime = Kohana::config('webserviceclient.topcrash_vers_rank_cache_minutes', 60) * 60;
  639. $response = $this->service->get($url, 'json', $lifetime);
  640. return $response;
  641. }
  642. /**
  643. * Prepare the data for the crash graph for ADU by Operating System.
  644. *
  645. * @access public
  646. * @param string The start date for this product YYYY-MM-DD
  647. * @param string The end date for this product YYYY-MM-DD (usually +90 days)
  648. * @param array An array of dates
  649. * @param array An array of operating_systems
  650. * @param array An array of statistics
  651. * @return array The array prepared for the crash data graph
  652. */
  653. public function prepareCrashGraphDataByOS($date_start, $date_end, $dates, $operating_systems, $statistics) {
  654. if (!empty($statistics)) {
  655. $data = array(
  656. 'startDate' => $date_start,
  657. 'endDate' => $date_end,
  658. 'count' => count($operating_systems),
  659. );
  660. for($i = 1; $i <= $data['count']; $i++) {
  661. $key_ratio = 'ratio' . $i;
  662. $key_item = 'item' . $i;
  663. $item = substr(array_shift($operating_systems), 0, 3);
  664. $data[$key_item] = $item;
  665. $data[$key_ratio] = array();
  666. foreach ($dates as $date) {
  667. if (strtotime($date) < $this->today) {
  668. if (isset($statistics['os'][$item][$date])) {
  669. array_push($data[$key_ratio], array(strtotime($date)*1000, $statistics['os'][$item][$date]['ratio'] * 100));
  670. } else {
  671. array_push($data[$key_ratio], array(strtotime($date)*1000, null));
  672. }
  673. }
  674. }
  675. }
  676. return $data;
  677. }
  678. return false;
  679. }
  680. /**
  681. * Prepare the data for the crash graph for ADU by Version.
  682. *
  683. * @access public
  684. * @param string The start date for this product YYYY-MM-DD
  685. * @param string The end date for this product YYYY-MM-DD (usually +90 days)
  686. * @param array An array of dates
  687. * @param array An array of version numbers
  688. * @param array An array of statistics
  689. * @return array The array prepared for the crash data graph
  690. */
  691. public function prepareCrashGraphDataByVersion($date_start, $date_end, $dates, $versions, $statistics) {
  692. if (!empty($statistics)) {
  693. $data = array(
  694. 'startDate' => $date_start,
  695. 'endDate' => $date_end,
  696. 'count' => count($versions),
  697. );
  698. for($i = 1; $i <= $data['count']; $i++) {
  699. $key_ratio = 'ratio' . $i;
  700. $key_item = 'item' . $i;
  701. $item = array_shift($versions);
  702. $data[$key_item] = $item;
  703. $data[$key_ratio] = array();
  704. foreach ($dates as $date) {
  705. if (strtotime($date) < $this->today) {
  706. if (isset($statistics['versions'][$item][$date])) {
  707. array_push($data[$key_ratio], array(strtotime($date)*1000, $statistics['versions'][$item][$date]['ratio'] * 100));
  708. } else {
  709. array_push($data[$key_ratio], array(strtotime($date)*1000, null));
  710. }
  711. }
  712. }
  713. }
  714. return $data;
  715. }
  716. return false;
  717. }
  718. /**
  719. * Prepare the data for the crash graph for ADU by Operating System.
  720. *
  721. * What we want to create is
  722. [
  723. { 'label': '3.6.4 Crash Ratio',
  724. 'data': [[123456777, 2.2], [1234545645, 2.3]...]},
  725. ...
  726. ]
  727. *
  728. * @access public
  729. * @param string The start date for this product YYYY-MM-DD
  730. * @param string The end date for this product YYYY-MM-DD (usually +90 days)
  731. * @param array An array of dates
  732. * @param array An array of operating_systems
  733. * @param array An array of statistics
  734. * @return array The array prepared for the crash data graph
  735. */
  736. public function prepareCrashGraphDataByReportType($date_start, $date_end, $dates, $versions, $statistics) {
  737. if (!empty($statistics)) {
  738. $data = array();
  739. $keys = $this->statistic_keys($statistics, $dates);
  740. foreach($versions as $version) {
  741. $label = "$version Crash %";
  742. $ratio_data = array();
  743. $oopp_ratio_data = array();
  744. $hang_browser_ratio_data = array();
  745. $hang_plugin_ratio_data = array();
  746. foreach ($dates as $date) {
  747. if (strtotime($date) < $this->today) {
  748. if (in_array('crash', $keys)) {
  749. if (isset($statistics['versions'][$version][$date])) {
  750. array_push($ratio_data, array(strtotime($date)*1000, $statistics['versions'][$version][$date]['crash_ratio'] * 100));
  751. } else {
  752. array_push($ratio_data, array(strtotime($date)*1000, null));
  753. }
  754. }
  755. if (in_array('oopp', $keys)) {
  756. if (isset($statistics['versions'][$version][$date])) {
  757. array_push($oopp_ratio_data, array(strtotime($date)*1000, $statistics['versions'][$version][$date]['oopp_ratio'] * 100));
  758. } else {
  759. array_push($oopp_ratio_data, array(strtotime($date)*1000, null));
  760. }
  761. }
  762. if (in_array('hang_browser', $keys)) {
  763. if (isset($statistics['versions'][$version][$date])) {
  764. array_push($hang_browser_ratio_data, array(strtotime($date)*1000, $statistics['versions'][$version][$date]['hang_browser_ratio'] * 100));
  765. } else {
  766. array_push($hang_browser_ratio_data, array(strtotime($date)*1000, null));
  767. }
  768. }
  769. if (in_array('hang_plugin', $keys)) {
  770. if (isset($statistics['versions'][$version][$date])) {
  771. array_push($hang_plugin_ratio_data, array(strtotime($date)*1000, $statistics['versions'][$version][$date]['hang_plugin_ratio'] * 100));
  772. } else {
  773. array_push($hang_plugin_ratio_data, array(strtotime($date)*1000, null));
  774. }
  775. }
  776. }
  777. }
  778. if (in_array('crash', $keys)) {
  779. array_push($data, array('label' => "$version Crash %",
  780. 'data' => $ratio_data));
  781. }
  782. if (in_array('oopp', $keys)) {
  783. array_push($data, array('label' => "$version OOPP %",
  784. 'data' => $oopp_ratio_data));
  785. }
  786. if (in_array('hang_browser', $keys)) {
  787. array_push($data, array('label' => "$version Hang B %",
  788. 'data' => $hang_browser_ratio_data));
  789. }
  790. if (in_array('hang_plugin', $keys)) {
  791. array_push($data, array('label' => "$version Hang P%",
  792. 'data' => $hang_plugin_ratio_data));
  793. }
  794. }
  795. return $data;
  796. }
  797. return false;
  798. }
  799. /**
  800. * Prepare the dates that will be used for statistic collection.
  801. *
  802. * @param string The end date
  803. * @param int The number of dates to query
  804. * @return array
  805. */
  806. public function prepareDates($date_end, $duration) {
  807. $dates = array();
  808. $date_diff = TimeUtil::determineDayDifferential($date_end, date('Y-m-d', mktime(0, 0, 0, date("m"), date("d"), date("Y"))));
  809. $timestamp = time();
  810. for($i = 0; $i <= $duration; $i++) {
  811. $date = date('Y-m-d', mktime(0, 0, 0, date("m"), date("d")-($i+$date_diff), date("Y")));
  812. if (strtotime($date) <= $timestamp) {
  813. $dates[] = $date;
  814. }
  815. }
  816. return $dates;
  817. }
  818. /**
  819. * Prepare the Crash Data for the Crash Graphs.
  820. *
  821. * @param array The array of crash data statistics
  822. * @param string The graph type, whether reporting by version or by O/S
  823. * @param string The start date
  824. * @param string The end date
  825. * @param array The array of O/S that will be reported
  826. * @param array The array of versions that will be reported
  827. * @return array
  828. */
  829. public function prepareGraphData($statistics, $form_selection='by_version', $date_start, $date_end, $dates, $operating_systems=null, $versions=null)
  830. {
  831. $graph_data = null;
  832. if ($form_selection == 'by_version') {
  833. $graph_data = $this->prepareCrashGraphDataByVersion($date_start, $date_end, $dates, $versions, $statistics);
  834. } elseif ($form_selection == 'by_os') {
  835. $graph_data = $this->prepareCrashGraphDataByOS($date_start, $date_end, $dates, $operating_systems, $statistics);
  836. } elseif ($form_selection == 'by_report_type') {
  837. $graph_data = $this->prepareCrashGraphDataByReportType($date_start, $date_end, $dates, $versions, $statistics);
  838. }
  839. return $graph_data;
  840. }
  841. /**
  842. * Prepare the Crash Data for the Crash Graphs.
  843. *
  844. * @param array The array of crash stats data results
  845. * @param string The graph type, whether reporting by version or by O/S
  846. * @param string The product name
  847. * @param array An array of versions
  848. * @param array An array of operating systems
  849. * @param string The start date
  850. * @param string The end date
  851. * @param array An array of effective throttling rates for each version
  852. * @return array The array of crash stats data statistics
  853. */
  854. public function prepareStatistics($results, $form_selection='by_version', $product, $versions, $operating_system, $date_start, $date_end, $throttle) {
  855. $statistics = null;
  856. if ($form_selection == 'by_version') {
  857. $statistics = (!empty($results)) ? $this->calculateStatisticsByVersion($results, $throttle) : null;
  858. } elseif ($form_selection == 'by_os') {
  859. $statistics = (!empty($results)) ? $this->calculateStatisticsByOS($results, $throttle) : null;
  860. } elseif ($form_selection == 'by_report_type') {
  861. $statistics = (!empty($results)) ? $this->calculateStatisticsByReportType($results, $throttle) : null;
  862. }
  863. return $statistics;
  864. }
  865. /**
  866. * Given a set of statistics and dates determine which report_types are present.
  867. *
  868. * @param $statistics array
  869. * @param $dates array
  870. *
  871. * @return array of report types
  872. */
  873. public function statistic_keys($statistics, $dates)
  874. {
  875. $keys = array();
  876. if (is_null($statistics)) {
  877. return $keys;
  878. }
  879. foreach ($dates as $date) {
  880. if (isset($statistics['versions']) && !empty($statistics['versions'])) {
  881. foreach ($statistics['versions'] as $version) {
  882. if (isset($version[$date]) &&
  883. ( isset($version[$date]['crash_ratio']) ||
  884. isset($version[$date]['oopp_ratio']) ||
  885. isset($version[$date]['hang_browser_ratio']) ||
  886. isset($version[$date]['hang_plugin_ratio']))) {
  887. $stats = $version[$date];
  888. if (array_key_exists('crash_ratio', $stats)) {
  889. array_push($keys, 'crash');
  890. }
  891. if (array_key_exists('oopp_ratio', $stats)) {
  892. array_push($keys, 'oopp');
  893. }
  894. if (array_key_exists('hang_browser_ratio', $stats)) {
  895. array_push($keys, 'hang_browser');
  896. }
  897. if (array_key_exists('hang_plugin_ratio', $stats)) {
  898. array_push($keys, 'hang_plugin');
  899. }
  900. return $keys;
  901. }
  902. }
  903. }
  904. }
  905. return $keys;
  906. }
  907. }