Merge pull request #2040 from CachetHQ/metric-repository-perf

Metric repository perf
This commit is contained in:
James Brooks
2016-10-30 17:36:01 +00:00
committed by GitHub
9 changed files with 220 additions and 318 deletions

View File

@@ -13,9 +13,9 @@ namespace CachetHQ\Cachet\Foundation\Providers;
use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Dates\DateFactory;
use CachetHQ\Cachet\Repositories\Metric\MetricRepository; use CachetHQ\Cachet\Repositories\Metric\MetricRepository;
use CachetHQ\Cachet\Repositories\Metric\MySqlRepository as MetricMySqlRepository; use CachetHQ\Cachet\Repositories\Metric\MySqlRepository;
use CachetHQ\Cachet\Repositories\Metric\PgSqlRepository as MetricPgSqlRepository; use CachetHQ\Cachet\Repositories\Metric\PgSqlRepository;
use CachetHQ\Cachet\Repositories\Metric\SqliteRepository as MetricSqliteRepository; use CachetHQ\Cachet\Repositories\Metric\SqliteRepository;
use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Container\Container;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
@@ -46,14 +46,11 @@ class RepositoryServiceProvider extends ServiceProvider
{ {
$this->app->singleton(MetricRepository::class, function (Container $app) { $this->app->singleton(MetricRepository::class, function (Container $app) {
$config = $app->make(ConfigRepository::class); $config = $app->make(ConfigRepository::class);
$driver = $config->get('database.default');
if ($driver == 'mysql') { switch ($config->get('database.default')) {
$repository = new MetricMySqlRepository($config); case 'mysql': $repository = new MySqlRepository($config); break;
} elseif ($driver == 'pgsql') { case 'pgsql': $repository = new PgSqlRepository($config); break;
$repository = new MetricPgSqlRepository($config); case 'sqlite': $repository = new SqliteRepository($config); break;
} elseif ($driver == 'sqlite') {
$repository = new MetricSqliteRepository($config);
} }
$dates = $app->make(DateFactory::class); $dates = $app->make(DateFactory::class);

View File

@@ -31,20 +31,22 @@ use McCool\LaravelAutoPresenter\Facades\AutoPresenter;
class StatusPageController extends AbstractApiController class StatusPageController extends AbstractApiController
{ {
/** /**
* The metric repository instance.
*
* @var \CachetHQ\Cachet\Repositories\Metric\MetricRepository * @var \CachetHQ\Cachet\Repositories\Metric\MetricRepository
*/ */
protected $metricRepository; protected $metrics;
/** /**
* Construct a new status page controller instance. * Construct a new status page controller instance.
* *
* @param \CachetHQ\Cachet\Repositories\Metric\MetricRepository $metricRepository * @param \CachetHQ\Cachet\Repositories\Metric\MetricRepository $metrics
* *
* @return void * @return void
*/ */
public function __construct(MetricRepository $metricRepository) public function __construct(MetricRepository $metrics)
{ {
$this->metricRepository = $metricRepository; $this->metrics = $metrics;
} }
/** /**
@@ -141,16 +143,16 @@ class StatusPageController extends AbstractApiController
switch ($type) { switch ($type) {
case 'last_hour': case 'last_hour':
$metricData = $this->metricRepository->listPointsLastHour($metric); $metricData = $this->metrics->listPointsLastHour($metric);
break; break;
case 'today': case 'today':
$metricData = $this->metricRepository->listPointsToday($metric); $metricData = $this->metrics->listPointsToday($metric);
break; break;
case 'week': case 'week':
$metricData = $this->metricRepository->listPointsForWeek($metric); $metricData = $this->metrics->listPointsForWeek($metric);
break; break;
case 'month': case 'month':
$metricData = $this->metricRepository->listPointsForMonth($metric); $metricData = $this->metrics->listPointsForMonth($metric);
break; break;
} }

View File

@@ -27,14 +27,10 @@ class MetricPresenter extends BasePresenter implements Arrayable
public function view_name() public function view_name()
{ {
switch ($this->wrappedObject->default_view) { switch ($this->wrappedObject->default_view) {
case 0: case 0: return 'last_hour';
return 'last_hour'; case 1: return 'today';
case 1: case 2: return 'week';
return 'today'; case 3: return 'month';
case 2:
return 'week';
case 3:
return 'month';
} }
} }
@@ -56,14 +52,10 @@ class MetricPresenter extends BasePresenter implements Arrayable
public function trans_string_name() public function trans_string_name()
{ {
switch ($this->wrappedObject->default_view) { switch ($this->wrappedObject->default_view) {
case 0: case 0: return 'last_hour';
return 'last_hour'; case 1: return 'hourly';
case 1: case 2: return 'weekly';
return 'hourly'; case 3: return 'monthly';
case 2:
return 'weekly';
case 3:
return 'monthly';
} }
} }

View File

@@ -13,6 +13,7 @@ namespace CachetHQ\Cachet\Repositories\Metric;
use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\Metric;
use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Config\Repository;
use Illuminate\Support\Collection;
/** /**
* This is the abstract metric repository class. * This is the abstract metric repository class.
@@ -52,7 +53,7 @@ abstract class AbstractMetricRepository
* *
* @return string * @return string
*/ */
protected function getTableName() protected function getMetricsTable()
{ {
$driver = $this->config->get('database.default'); $driver = $this->config->get('database.default');
$connection = $this->config->get('database.connections.'.$driver); $connection = $this->config->get('database.connections.'.$driver);
@@ -60,4 +61,63 @@ abstract class AbstractMetricRepository
return $prefix.'metrics'; return $prefix.'metrics';
} }
/**
* Get the metric points table name.
*
* @return string
*/
protected function getMetricPointsTable()
{
$driver = $this->config->get('database.default');
$connection = $this->config->get('database.connections.'.$driver);
$prefix = $connection['prefix'];
return $prefix.'metric_points';
}
/**
* Return the query type.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
*
* @return string
*/
protected function getQueryType(Metric $metric)
{
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
return "sum({$this->getMetricPointsTable()}.value * {$this->getMetricPointsTable()}.counter) AS value";
} elseif ($metric->calc_type == Metric::CALC_AVG) {
return "avg({$this->getMetricPointsTable()}.value * {$this->getMetricPointsTable()}.counter) AS value";
} else {
return "sum({$this->getMetricPointsTable()}.value * {$this->getMetricPointsTable()}.counter) AS value";
}
}
/**
* Map the result set.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
* @param array $results
*
* @return \Illuminate\Support\Collection
*/
protected function mapResults(Metric $metric, array $results)
{
$results = Collection::make($results);
return $results->map(function ($point) use ($metric) {
if (!$point->value) {
$point->value = $metric->default_value;
}
if ($point->value === 0 && $metric->default_value != $value) {
$point->value = $metric->default_value;
}
$point->value = round($point->value, $metric->places);
return $point;
});
}
} }

View File

@@ -13,36 +13,40 @@ namespace CachetHQ\Cachet\Repositories\Metric;
use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\Metric;
/**
* This is the metric interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface MetricInterface interface MetricInterface
{ {
/** /**
* Returns metrics for the last hour. * Returns metrics since given minutes.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $hour * @param int $minutes
* @param int $minute
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsLastHour(Metric $metric, $hour, $minute); public function getPointsSinceMinutes(Metric $metric, $minutes);
/** /**
* Returns metrics for a given hour. * Returns metrics since given hour.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $hour * @param int $hour
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsByHour(Metric $metric, $hour); public function getPointsSinceHour(Metric $metric, $hour);
/** /**
* Returns metrics for the week. * Returns metrics since given day.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $day * @param int $day
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsForDayInWeek(Metric $metric, $day); public function getPointsSinceDay(Metric $metric, $day);
} }

View File

@@ -15,6 +15,11 @@ use CachetHQ\Cachet\Dates\DateFactory;
use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\Metric;
use DateInterval; use DateInterval;
/**
* This is the metric repository class.
*
* @author James Brooks <james@alt-three.com>
*/
class MetricRepository class MetricRepository
{ {
/** /**
@@ -50,22 +55,25 @@ class MetricRepository
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* *
* @return array * @return \Illuminate\Support\Collection
*/ */
public function listPointsLastHour(Metric $metric) public function listPointsLastHour(Metric $metric)
{ {
$dateTime = $this->dates->make(); $dateTime = $this->dates->make();
$points = [];
$pointKey = $dateTime->format('H:i'); $pointKey = $dateTime->format('H:i');
$points = $this->repository->getPointsSinceMinutes($metric, 60)->pluck('value', 'key');
for ($i = 0; $i <= 60; $i++) { for ($i = 0; $i <= 60; $i++) {
$points[$pointKey] = $this->repository->getPointsLastHour($metric, 0, $i); if (!$points->has($pointKey)) {
$points->put($pointKey, $metric->default_value);
}
$pointKey = $dateTime->sub(new DateInterval('PT1M'))->format('H:i'); $pointKey = $dateTime->sub(new DateInterval('PT1M'))->format('H:i');
} }
return array_reverse($points); return $points->sortBy(function ($point, $key) use ($points) {
return $key;
});
} }
/** /**
@@ -79,17 +87,20 @@ class MetricRepository
public function listPointsToday(Metric $metric, $hours = 12) public function listPointsToday(Metric $metric, $hours = 12)
{ {
$dateTime = $this->dates->make(); $dateTime = $this->dates->make();
$points = [];
$pointKey = $dateTime->format('H:00'); $pointKey = $dateTime->format('H:00');
$points = $this->repository->getPointsSinceHour($metric, $hours)->pluck('value', 'key');
for ($i = 0; $i <= $hours; $i++) { for ($i = 0; $i <= $hours; $i++) {
$points[$pointKey] = $this->repository->getPointsByHour($metric, $i); if (!$points->has($pointKey)) {
$points->put($pointKey, $metric->default_value);
}
$pointKey = $dateTime->sub(new DateInterval('PT1H'))->format('H:00'); $pointKey = $dateTime->sub(new DateInterval('PT1H'))->format('H:00');
} }
return array_reverse($points); return $points->sortBy(function ($point, $key) use ($points) {
return $key;
});
} }
/** /**
@@ -102,17 +113,20 @@ class MetricRepository
public function listPointsForWeek(Metric $metric) public function listPointsForWeek(Metric $metric)
{ {
$dateTime = $this->dates->make(); $dateTime = $this->dates->make();
$pointKey = $dateTime->format('Y-m-d');
$points = []; $points = $this->repository->getPointsSinceDay($metric, 7)->pluck('value', 'key');
$pointKey = $dateTime->format('D jS M');
for ($i = 0; $i <= 7; $i++) { for ($i = 0; $i <= 7; $i++) {
$points[$pointKey] = $this->repository->getPointsForDayInWeek($metric, $i); if (!$points->has($pointKey)) {
$pointKey = $dateTime->sub(new DateInterval('P1D'))->format('D jS M'); $points->put($pointKey, $metric->default_value);
} }
return array_reverse($points); $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('Y-m-d');
}
return $points->sortBy(function ($point, $key) use ($points) {
return $key;
});
} }
/** /**
@@ -125,18 +139,20 @@ class MetricRepository
public function listPointsForMonth(Metric $metric) public function listPointsForMonth(Metric $metric)
{ {
$dateTime = $this->dates->make(); $dateTime = $this->dates->make();
$pointKey = $dateTime->format('Y-m-d');
$daysInMonth = $dateTime->format('t'); $daysInMonth = $dateTime->format('t');
$points = $this->repository->getPointsSinceDay($metric, $daysInMonth)->pluck('value', 'key');
$points = [];
$pointKey = $dateTime->format('jS M');
for ($i = 0; $i <= $daysInMonth; $i++) { for ($i = 0; $i <= $daysInMonth; $i++) {
$points[$pointKey] = $this->repository->getPointsForDayInWeek($metric, $i); if (!$points->has($pointKey)) {
$pointKey = $dateTime->sub(new DateInterval('P1D'))->format('jS M'); $points->put($pointKey, $metric->default_value);
} }
return array_reverse($points); $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('Y-m-d');
}
return $points->sortBy(function ($point, $key) use ($points) {
return $key;
});
} }
} }

View File

@@ -12,9 +12,7 @@
namespace CachetHQ\Cachet\Repositories\Metric; namespace CachetHQ\Cachet\Repositories\Metric;
use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\Metric;
use DateInterval;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Jenssegers\Date\Date;
/** /**
* This is the mysql repository class. * This is the mysql repository class.
@@ -24,112 +22,59 @@ use Jenssegers\Date\Date;
class MySqlRepository extends AbstractMetricRepository implements MetricInterface class MySqlRepository extends AbstractMetricRepository implements MetricInterface
{ {
/** /**
* Returns metrics for the last hour. * Returns metrics since given minutes.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $hour * @param int $minutes
* @param int $minute
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsLastHour(Metric $metric, $hour, $minute) public function getPointsSinceMinutes(Metric $metric, $minutes)
{ {
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); $queryType = $this->getQueryType($metric);
$timeInterval = $dateTime->format('YmdHi'); $points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%H:%i') AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :minutes MINUTE) GROUP BY HOUR({$this->getMetricPointsTable()}.`created_at`), MINUTE({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`';
}
$value = 0;
$points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND DATE_FORMAT(mp.`created_at`, '%Y%m%d%H%i') = :timeInterval GROUP BY HOUR(mp.`created_at`), MINUTE(mp.`created_at`)", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'timeInterval' => $timeInterval, 'minutes' => $minutes,
]); ]);
if (isset($points[0]) && !($value = $points[0]->value)) { return $this->mapResults($metric, $points);
$value = 0;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
/** /**
* Returns metrics for a given hour. * Returns metrics since given hour.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $hour * @param int $hour
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsByHour(Metric $metric, $hour) public function getPointsSinceHour(Metric $metric, $hour)
{ {
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); $queryType = $this->getQueryType($metric);
$hourInterval = $dateTime->format('YmdH'); $points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%H:00') AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :hour HOUR) GROUP BY HOUR({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`';
}
$value = 0;
$points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND DATE_FORMAT(mp.`created_at`, '%Y%m%d%H') = :hourInterval GROUP BY HOUR(mp.`created_at`)", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'hourInterval' => $hourInterval, 'hour' => $hour,
]); ]);
if (isset($points[0]) && !($value = $points[0]->value)) { return $this->mapResults($metric, $points);
$value = 0;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
/** /**
* Returns metrics for the week. * Returns metrics since given day.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $day
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsForDayInWeek(Metric $metric, $day) public function getPointsSinceDay(Metric $metric, $day)
{ {
$dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); $queryType = $this->getQueryType($metric);
$points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%Y-%m-%d') AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :day DAY) GROUP BY DATE({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`';
}
$value = 0;
$points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND mp.`created_at` BETWEEN DATE_SUB(mp.`created_at`, INTERVAL 1 WEEK) AND DATE_ADD(NOW(), INTERVAL 1 DAY) AND DATE_FORMAT(mp.`created_at`, '%Y%m%d') = :timeInterval GROUP BY DATE_FORMAT(mp.`created_at`, '%Y%m%d')", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'timeInterval' => $dateTime->format('Ymd'), 'day' => $day,
]); ]);
if (isset($points[0]) && !($value = $points[0]->value)) { return $this->mapResults($metric, $points);
$value = 0;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
} }

View File

@@ -12,7 +12,6 @@
namespace CachetHQ\Cachet\Repositories\Metric; namespace CachetHQ\Cachet\Repositories\Metric;
use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\Metric;
use DateInterval;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Jenssegers\Date\Date; use Jenssegers\Date\Date;
@@ -24,113 +23,56 @@ use Jenssegers\Date\Date;
class PgSqlRepository extends AbstractMetricRepository implements MetricInterface class PgSqlRepository extends AbstractMetricRepository implements MetricInterface
{ {
/** /**
* Returns metrics for the last hour. * Returns metrics since given minutes.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $hour * @param int $minutes
* @param int $minute
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsLastHour(Metric $metric, $hour, $minute) public function getPointsSinceMinutes(Metric $metric, $minutes)
{ {
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); $queryType = $this->getQueryType($metric);
$points = DB::select("SELECT to_char({$this->getMetricPointsTable()}.created_at, 'HH24:MI') AS key, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.created_at >= (NOW() - INTERVAL '{$minutes}' MINUTE) GROUP BY to_char({$this->getMetricPointsTable()}.created_at, 'HH24:MI') ORDER BY to_char({$this->getMetricPointsTable()}.created_at, 'HH24:MI')", [
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'sum(metric_points.value * metric_points.counter)';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'avg(metric_points.value * metric_points.counter)';
} else {
$queryType = 'sum(metric_points.value * metric_points.counter)';
}
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND to_char(metric_points.created_at, 'YYYYMMDDHH24MI') = :timeInterval GROUP BY to_char(metric_points.created_at, 'HHMI')", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'timeInterval' => $dateTime->format('YmdHi'),
]); ]);
if (isset($query[0])) { return $this->mapResults($metric, $points);
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
/** /**
* Returns metrics for a given hour. * Returns metrics since given hour.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $hour * @param int $hour
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsByHour(Metric $metric, $hour) public function getPointsSinceHour(Metric $metric, $hour)
{ {
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); $queryType = $this->getQueryType($metric);
$points = DB::select("SELECT to_char({$this->getMetricPointsTable()}.created_at, 'HH24:00') AS key, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.created_at >= (NOW() - INTERVAL '{$hour}' HOUR) GROUP BY to_char({$this->getMetricPointsTable()}.created_at, 'HH24:00') ORDER BY to_char({$this->getMetricPointsTable()}.created_at, 'HH24:00')", [
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'sum(metric_points.value * metric_points.counter)';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'avg(metric_points.value * metric_points.counter)';
} else {
$queryType = 'sum(metric_points.value * metric_points.counter)';
}
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE metric_points.metric_id = :metricId AND to_char(metric_points.created_at, 'YYYYMMDDHH24') = :timeInterval GROUP BY to_char(metric_points.created_at, 'H')", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'timeInterval' => $dateTime->format('YmdH'),
]); ]);
if (isset($query[0])) { return $this->mapResults($metric, $points);
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
/** /**
* Returns metrics for the week. * Returns metrics since given day.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $day
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsForDayInWeek(Metric $metric, $day) public function getPointsSinceDay(Metric $metric, $day)
{ {
$dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); $queryType = $this->getQueryType($metric);
$points = DB::select("SELECT DATE({$this->getMetricPointsTable()}.created_at) AS key, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.created_at >= (DATE(NOW()) - INTERVAL '{$day}' DAY) GROUP BY DATE({$this->getMetricPointsTable()}.created_at) ORDER BY DATE({$this->getMetricPointsTable()}.created_at)", [
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'sum(mp.value * mp.counter) AS value';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'avg(mp.value * mp.counter) AS value';
}
$value = 0;
$points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND mp.created_at BETWEEN (mp.created_at - interval '1 week') AND (now() + interval '1 day') AND to_char(mp.created_at, 'YYYYMMDD') = :timeInterval GROUP BY to_char(mp.created_at, 'YYYYMMDD')", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'timeInterval' => $dateTime->format('Ymd'),
]); ]);
if (isset($points[0]) && !($value = $points[0]->value)) { return $this->mapResults($metric, $points);
$value = 0;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
} }

View File

@@ -12,123 +12,67 @@
namespace CachetHQ\Cachet\Repositories\Metric; namespace CachetHQ\Cachet\Repositories\Metric;
use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\Metric;
use DateInterval;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Jenssegers\Date\Date; use Jenssegers\Date\Date;
/**
* This is the sqlite repository class.
*
* @author James Brooks <james@alt-three.com>
*/
class SqliteRepository extends AbstractMetricRepository implements MetricInterface class SqliteRepository extends AbstractMetricRepository implements MetricInterface
{ {
/** /**
* Returns metrics for the last hour. * Returns metrics since given minutes.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $hour * @param int $minutes
* @param int $minute
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsLastHour(Metric $metric, $hour, $minute) public function getPointsSinceMinutes(Metric $metric, $minutes)
{ {
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); $queryType = $this->getQueryType($metric);
$points = DB::select("SELECT strftime('%H:%M', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', '-{$minutes} minutes') GROUP BY strftime('%H', {$this->getMetricPointsTable()}.`created_at`), strftime('%M', {$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'sum(metric_points.value * metric_points.counter)';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'avg(metric_points.value * metric_points.counter)';
} else {
$queryType = 'sum(metric_points.value * metric_points.counter)';
}
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND strftime('%Y%m%d%H%M', metric_points.created_at) = :timeInterval GROUP BY strftime('%H%M', metric_points.created_at)", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'timeInterval' => $dateTime->format('YmdHi'),
]); ]);
if (isset($query[0])) { return $this->mapResults($metric, $points);
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
/** /**
* Returns metrics for a given hour. * Returns metrics since given hour.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $hour * @param int $hour
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsByHour(Metric $metric, $hour) public function getPointsSinceHour(Metric $metric, $hour)
{ {
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); $queryType = $this->getQueryType($metric);
$points = DB::select("SELECT strftime('%H:00', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', '-{$hour} hours') GROUP BY strftime('%H', {$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'sum(metric_points.value * metric_points.counter)';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'avg(metric_points.value * metric_points.counter)';
} else {
$queryType = 'sum(metric_points.value * metric_points.counter)';
}
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND strftime('%Y%m%d%H', metric_points.created_at) = :timeInterval GROUP BY strftime('%H', metric_points.created_at)", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'timeInterval' => $dateTime->format('YmdH'),
]); ]);
if (isset($query[0])) { return $this->mapResults($metric, $points);
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
/** /**
* Returns metrics for the week. * Returns metrics since given day.
* *
* @param \CachetHQ\Cachet\Models\Metric $metric * @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $day
* *
* @return int * @return \Illuminate\Support\Collection
*/ */
public function getPointsForDayInWeek(Metric $metric, $day) public function getPointsSinceDay(Metric $metric, $day)
{ {
$dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); $queryType = $this->getQueryType($metric);
$points = DB::select("SELECT strftime('%Y-%m-%d', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', '-{$day} days') GROUP BY DATE({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'sum(metric_points.value * metric_points.counter)';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'avg(metric_points.value * metric_points.counter)';
} else {
$queryType = 'sum(metric_points.value * metric_points.counter)';
}
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND metric_points.created_at > date('now', '-7 day') AND strftime('%Y%m%d', metric_points.created_at) = :timeInterval GROUP BY strftime('%Y%m%d', metric_points.created_at)", [
'metricId' => $metric->id, 'metricId' => $metric->id,
'timeInterval' => $dateTime->format('Ymd'),
]); ]);
if (isset($query[0])) { return $this->mapResults($metric, $points);
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
return $metric->default_value;
}
return round($value, $metric->places);
} }
} }