2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
* Statistics Class definition
10
* @author Jeff Stys <jeff.stys@nasa.gov>
11
* @author Keith Hughitt <keith.hughitt@nasa.gov>
12
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
13
* @link http://launchpad.net/helioviewer.org
16
* A simple module for recording query statistics
19
* @package Helioviewer
20
* @author Jeff Stys <jeff.stys@nasa.gov>
21
* @author Keith Hughitt <keith.hughitt@nasa.gov>
22
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
23
* @link http://launchpad.net/helioviewer.org
25
class Database_Statistics {
27
private $_dbConnection;
34
public function __construct() {
35
include_once HV_ROOT_DIR.'/src/php/Database/DbConnection.php';
36
$this->_dbConnection = new Database_DbConnection();
40
* Add a new entry to the `statistics` table
42
* param $action string The API action to log
46
public function log($action) {
48
"INSERT INTO statistics "
51
. "timestamp " . " = NULL, "
52
. "action " . " = '%s';",
53
$this->_dbConnection->link->real_escape_string($action)
56
$result = $this->_dbConnection->query($sql);
58
catch (Exception $e) {
66
* Get latest usage statistics as JSON
68
* @param string Time resolution
72
public function getUsageStatistics($resolution) {
73
require_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
75
// Determine time intervals to query
76
$interval = $this->_getQueryIntervals($resolution);
78
// Array to keep track of counts for each action
80
"buildMovie" => array(),
81
"getClosestData" => array(),
82
"getClosestImage" => array(),
84
"takeScreenshot" => array(),
85
"uploadMovieToYouTube" => array(),
92
"getClosestData" => 0,
93
"getClosestImage" => 0,
95
"takeScreenshot" => 0,
96
"uploadMovieToYouTube" => 0,
100
// Format to use for displaying dates
101
$dateFormat = $this->_getDateFormat($resolution);
104
$date = $interval['startDate'];
106
// Query each time interval
107
for ($i = 0; $i < $interval["numSteps"]; $i++) {
109
// Format date for array index
110
$dateIndex = $date->format($dateFormat);
112
// MySQL-formatted date string
113
$dateStart = toMySQLDateString($date);
115
// Move to end date for the current interval
116
$date->add($interval['timestep']);
118
// Fill with zeros to begin with
119
foreach ($counts as $action => $arr) {
120
array_push($counts[$action], array($dateIndex => 0));
122
$dateEnd = toMySQLDateString($date);
125
"SELECT action, COUNT(id) AS count "
128
. "timestamp BETWEEN '%s' AND '%s' "
129
. "GROUP BY action;",
130
$this->_dbConnection->link->real_escape_string($dateStart),
131
$this->_dbConnection->link->real_escape_string($dateEnd)
134
$result = $this->_dbConnection->query($sql);
136
catch (Exception $e) {
140
// Append counts for each API action during that interval
141
// to the appropriate array
142
while ($count = $result->fetch_array(MYSQLI_ASSOC)) {
143
$num = (int)$count['count'];
145
$counts[$count['action']][$i][$dateIndex] = $num;
146
$summary[$count['action']] += $num;
150
// Include summary info
151
$counts['summary'] = $summary;
153
return json_encode($counts);
157
* Return date format string for the specified time resolution
159
* @param string $resolution Time resolution string
161
* @return string Date format string
163
public function getDataCoverageTimeline($resolution, $endDate, $interval,
166
require_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
168
$sql = 'SELECT id, name, description FROM datasources ORDER BY description';
169
$result = $this->_dbConnection->query($sql);
173
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
174
$sourceId = $row['id'];
176
$output['sourceId'.$sourceId] = new stdClass;
177
$output['sourceId'.$sourceId]->sourceId = $sourceId;
178
$output['sourceId'.$sourceId]->label = $row['description'];
179
$output['sourceId'.$sourceId]->data = array();
182
// Format to use for displaying dates
183
switch($resolution) {
187
$dateFormat = "Y-m-d H:i";
190
$dateFormat = "Y-m-d H:i";
193
$dateFormat = "Y-m-d";
197
$dateFormat = "Y-m-d";
209
$dateFormat = "Y-m-d H:i e";
214
$date = $endDate->sub($interval);
216
// Query each time interval
217
for ($i = 0; $i < $steps; $i++) {
218
$dateIndex = $date->format($dateFormat); // Format date for array index
219
$dateStart = toMySQLDateString($date); // MySQL-formatted date string
221
// Move to end date for the current interval
222
$date->add($stepSize);
224
// Fill with zeros to begin with
225
foreach ($output as $sourceId => $arr) {
226
array_push($output[$sourceId]->data, array($dateIndex => 0));
228
$dateEnd = toMySQLDateString($date);
230
$sql = "SELECT sourceId, SUM(count) as count FROM data_coverage_30_min " .
231
"WHERE date BETWEEN '$dateStart' AND '$dateEnd' GROUP BY sourceId;";
234
$result = $this->_dbConnection->query($sql);
236
// And append counts for each sourceId during that interval to the relevant array
237
while ($count = $result->fetch_array(MYSQLI_ASSOC)) {
238
$num = (int) $count['count'];
239
$output['sourceId'.$count['sourceId']]->data[$i][$dateIndex] = $num;
243
return json_encode($output);
247
* Gets latest datasource coverage and return as JSON
249
public function getDataCoverage($resolution, $endDate, $interval,
252
require_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
254
$sql = 'SELECT id, name, description FROM datasources ORDER BY description';
255
$result = $this->_dbConnection->query($sql);
259
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
260
$sourceId = $row['id'];
262
$output['sourceId'.$sourceId] = new stdClass;
263
$output['sourceId'.$sourceId]->sourceId = $sourceId;
264
$output['sourceId'.$sourceId]->label = $row['description'];
265
$output['sourceId'.$sourceId]->data = array();
268
// Format to use for displaying dates
269
switch($resolution) {
273
$dateFormat = "Y-m-d H:i";
276
$dateFormat = "Y-m-d H:i";
279
$dateFormat = "Y-m-d";
283
$dateFormat = "Y-m-d";
295
$dateFormat = "Y-m-d H:i e";
300
$date = $endDate->sub($interval);
302
// Query each time interval
303
for ($i = 0; $i < $steps; $i++) {
304
$dateIndex = $date->format($dateFormat); // Format date for array index
305
$dateStart = toMySQLDateString($date); // MySQL-formatted date string
307
// Move to end date for the current interval
308
$date->add($stepSize);
310
// Fill with zeros to begin with
311
foreach ($output as $sourceId => $arr) {
312
array_push($output[$sourceId]->data, array($dateIndex => 0));
314
$dateEnd = toMySQLDateString($date);
316
$sql = "SELECT sourceId, SUM(count) as count FROM data_coverage_30_min " .
317
"WHERE date BETWEEN '$dateStart' AND '$dateEnd' GROUP BY sourceId;";
320
$result = $this->_dbConnection->query($sql);
322
// And append counts for each sourceId during that interval to the relevant array
323
while ($count = $result->fetch_array(MYSQLI_ASSOC)) {
324
$num = (int) $count['count'];
325
$output['sourceId'.$count['sourceId']]->data[$i][$dateIndex] = $num;
329
return json_encode($output);
333
* Update data source coverage data for the last 7 Days
334
* (or specified time period).
336
public function updateDataCoverage($period=null) {
338
if ( gettype($period) == 'string' &&
339
preg_match('/^([0-9]+)([mhDMY])$/', $period, $matches) === 1 ) {
341
$magnitude = $matches[1];
342
$period_abbr = $matches[2];
349
switch ($period_abbr) {
351
$interval = 'INTERVAL '.$magnitude.' MINUTE';
354
$interval = 'INTERVAL '.$magnitude.' HOUR';
357
$interval = 'INTERVAL '.$magnitude.' DAY';
360
$interval = 'INTERVAL '.$magnitude.' MONTH';
363
$interval = 'INTERVAL '.$magnitude.' YEAR';
366
$interval = 'INTERVAL 7 DAY';
369
$sql = 'REPLACE INTO ' .
370
'data_coverage_30_min ' .
371
'(date, sourceId, count) ' .
373
'SQL_BIG_RESULT SQL_BUFFER_RESULT SQL_NO_CACHE ' .
375
'DATE_FORMAT(date, "%Y-%m-%d %H:"), ' .
376
'LPAD((MINUTE(date) DIV 30)*30, 2, "0"), ' .
377
'":00") AS "bin", ' .
383
'date >= DATE_SUB(NOW(),'.$interval.') ' .
387
$result = $this->_dbConnection->query($sql);
392
'interval' => $interval
395
return json_encode($output);
399
* Determines date format to use for the x-axis of the requested resolution
401
private function _getDateFormat($resolution) {
402
switch ($resolution) {
410
return "M j"; // Feb 3
413
return "M y"; // Feb 09
422
* Determine time inveral specification for statistics query
424
* @param string $resolution Time resolution string
426
* @return array Array specifying a time interval
428
private function _getQueryIntervals($resolution) {
430
date_default_timezone_set('UTC');
433
$date = new DateTime();
437
// For hourly resolution, keep the hours value, otherwise set to zero
438
$hour = ($resolution == "hourly") ? (int) $date->format("H") : 0;
440
// Round end time to nearest hour or day to begin with (may round other units later)
441
$date->setTime($hour, 0, 0);
444
if ($resolution == "hourly") {
445
$timestep = new DateInterval("PT1H");
448
$date->add($timestep);
451
$date->sub(new DateInterval("P1D"));
455
else if ($resolution == "daily") {
456
$timestep = new DateInterval("P1D");
459
$date->add($timestep);
462
$date->sub(new DateInterval("P4W"));
466
else if ($resolution == "weekly") {
467
$timestep = new DateInterval("P1W");
470
$date->add(new DateInterval("P1D"));
473
$date->sub(new DateInterval("P25W"));
477
else if ($resolution == "monthly") {
478
$timestep = new DateInterval("P1M");
481
$date->modify('first day of next month');
482
$date->sub(new DateInterval("P24M"));
486
else if ($resolution == "yearly") {
487
$timestep = new DateInterval("P1Y");
490
$year = (int) $date->format("Y");
491
$date->setDate($year - $numSteps + 1, 1, 1);
494
// Array to store time intervals
496
"startDate" => $date,
497
"timestep" => $timestep,
498
"numSteps" => $numSteps