Skip to content

Commit

Permalink
Add graphs to the dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenvdlinde committed Nov 24, 2024
1 parent f2e2d5c commit bbd2317
Show file tree
Hide file tree
Showing 6 changed files with 1,178 additions and 106 deletions.
4 changes: 4 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
],
'routes' => [
['name' => 'dashboard#page', 'url' => '/', 'verb' => 'GET'],
['name' => 'dashboard#index', 'url' => '/api/dashboard', 'verb' => 'GET'],
['name' => 'dashboard#getCallStats', 'url' => '/api/dashboard/callstats', 'verb' => 'GET'],
['name' => 'dashboard#getJobStats', 'url' => '/api/dashboard/jobstats', 'verb' => 'GET'],
['name' => 'dashboard#getSyncStats', 'url' => '/api/dashboard/syncstats', 'verb' => 'GET'],
['name' => 'sources#test', 'url' => '/api/source-test/{id}', 'verb' => 'POST'],
['name' => 'sources#logs', 'url' => '/api/sources-logs/{id}', 'verb' => 'GET'],
['name' => 'jobs#run', 'url' => '/api/jobs-test/{id}', 'verb' => 'POST'],
Expand Down
126 changes: 100 additions & 26 deletions lib/Controller/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,30 @@
use OCA\OpenConnector\Db\EndpointMapper;
use OCA\OpenConnector\Db\JobMapper;
use OCA\OpenConnector\Db\MappingMapper;
use OCA\OpenConnector\Db\CallLogMapper;
use OCA\OpenConnector\Db\JobLogMapper;
use OCA\OpenConnector\Db\SynchronizationContractLogMapper;

/**
* @package OCA\OpenConnector\Controller
*/
class DashboardController extends Controller
{
private $synchronizationMapper;
private $sourceMapper;
private $synchronizationContractMapper;
private $consumerMapper;
private $endpointMapper;
private $jobMapper;
private $mappingMapper;

public function __construct(
$appName,
IRequest $request,
SynchronizationMapper $synchronizationMapper,
SourceMapper $sourceMapper,
SynchronizationContractMapper $synchronizationContractMapper,
ConsumerMapper $consumerMapper,
EndpointMapper $endpointMapper,
JobMapper $jobMapper,
MappingMapper $mappingMapper
private readonly SynchronizationMapper $synchronizationMapper,
private readonly SourceMapper $sourceMapper,
private readonly SynchronizationContractMapper $synchronizationContractMapper,
private readonly ConsumerMapper $consumerMapper,
private readonly EndpointMapper $endpointMapper,
private readonly JobMapper $jobMapper,
private readonly MappingMapper $mappingMapper,
private readonly CallLogMapper $callLogMapper,
private readonly JobLogMapper $jobLogMapper,
private readonly SynchronizationContractLogMapper $synchronizationContractLogMapper
) {
parent::__construct($appName, $request);
$this->synchronizationMapper = $synchronizationMapper;
$this->sourceMapper = $sourceMapper;
$this->synchronizationContractMapper = $synchronizationContractMapper;
$this->consumerMapper = $consumerMapper;
$this->endpointMapper = $endpointMapper;
$this->jobMapper = $jobMapper;
$this->mappingMapper = $mappingMapper;
}

/**
Expand Down Expand Up @@ -82,17 +76,97 @@ public function index(): JSONResponse
{
try {
$results = [
"synchronizations" => $this->synchronizationMapper->getTotalCallCount(),
"sources" => $this->sourceMapper->getTotalCallCount(),
"mappings" => $this->mappingMapper->getTotalCallCount(),
"synchronizations" => $this->synchronizationMapper->getTotalCallCount(),
"synchronizationContracts" => $this->synchronizationContractMapper->getTotalCallCount(),
"consumers" => $this->consumerMapper->getTotalCallCount(),
"endpoints" => $this->endpointMapper->getTotalCallCount(),
"jobs" => $this->jobMapper->getTotalCallCount(),
"mappings" => $this->mappingMapper->getTotalCallCount()
"endpoints" => $this->endpointMapper->getTotalCallCount()
];
return new JSONResponse($results);
} catch (\Exception $e) {
return new JSONResponse(['error' => $e->getMessage()], 500);
}
}

/**
* Get call statistics for the dashboard
*
* @NoAdminRequired
* @NoCSRFRequired
* @param string|null $from Start date in ISO format
* @param string|null $to End date in ISO format
* @return JSONResponse
*/
public function getCallStats(?string $from = null, ?string $to = null): JSONResponse
{
try {
$fromDate = $from ? new \DateTime($from) : (new \DateTime())->modify('-7 days');
$toDate = $to ? new \DateTime($to) : new \DateTime();

$dailyStats = $this->callLogMapper->getCallStatsByDateRange($fromDate, $toDate);
$hourlyStats = $this->callLogMapper->getCallStatsByHourRange($fromDate, $toDate);

return new JSONResponse([
'daily' => $dailyStats,
'hourly' => $hourlyStats
]);
} catch (\Exception $e) {
return new JSONResponse(['error' => $e->getMessage()], 500);
}
}

/**
* Get job statistics for the dashboard
*
* @NoAdminRequired
* @NoCSRFRequired
* @param string|null $from Start date in ISO format
* @param string|null $to End date in ISO format
* @return JSONResponse
*/
public function getJobStats(?string $from = null, ?string $to = null): JSONResponse
{
try {
$fromDate = $from ? new \DateTime($from) : (new \DateTime())->modify('-7 days');
$toDate = $to ? new \DateTime($to) : new \DateTime();

$dailyStats = $this->jobLogMapper->getJobStatsByDateRange($fromDate, $toDate);
$hourlyStats = $this->jobLogMapper->getJobStatsByHourRange($fromDate, $toDate);

return new JSONResponse([
'daily' => $dailyStats,
'hourly' => $hourlyStats
]);
} catch (\Exception $e) {
return new JSONResponse(['error' => $e->getMessage()], 500);
}
}

/**
* Get synchronization statistics for the dashboard
*
* @NoAdminRequired
* @NoCSRFRequired
* @param string|null $from Start date in ISO format
* @param string|null $to End date in ISO format
* @return JSONResponse
*/
public function getSyncStats(?string $from = null, ?string $to = null): JSONResponse
{
try {
$fromDate = $from ? new \DateTime($from) : (new \DateTime())->modify('-7 days');
$toDate = $to ? new \DateTime($to) : new \DateTime();

$dailyStats = $this->synchronizationContractLogMapper->getSyncStatsByDateRange($fromDate, $toDate);
$hourlyStats = $this->synchronizationContractLogMapper->getSyncStatsByHourRange($fromDate, $toDate);

return new JSONResponse([
'daily' => $dailyStats,
'hourly' => $hourlyStats
]);
} catch (\Exception $e) {
return new JSONResponse(['error' => $e->getMessage()], 500);
}
}
}
70 changes: 70 additions & 0 deletions lib/Db/CallLogMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,74 @@ public function getLastCallLog(): ?CallLog
return null;
}
}

/**
* Get call statistics grouped by date for a specific date range
*
* @param \DateTime $from Start date
* @param \DateTime $to End date
* @return array Array of daily statistics with success and error counts
*/
public function getCallStatsByDateRange(\DateTime $from, \DateTime $to): array
{
$qb = $this->db->getQueryBuilder();

$qb->select(
$qb->createFunction('DATE(created) as date'),
$qb->createFunction('SUM(CASE WHEN status_code >= 200 AND status_code < 300 THEN 1 ELSE 0 END) as success'),
$qb->createFunction('SUM(CASE WHEN status_code < 200 OR status_code >= 300 THEN 1 ELSE 0 END) as error')
)
->from('openconnector_call_logs')
->where($qb->expr()->gte('created', $qb->createNamedParameter($from->format('Y-m-d H:i:s'))))
->andWhere($qb->expr()->lte('created', $qb->createNamedParameter($to->format('Y-m-d H:i:s'))))
->groupBy('date')
->orderBy('date', 'ASC');

$result = $qb->execute();
$stats = [];

while ($row = $result->fetch()) {
$stats[$row['date']] = [
'success' => (int)$row['success'],
'error' => (int)$row['error']
];
}

return $stats;
}

/**
* Get call statistics grouped by hour for a specific date range
*
* @param \DateTime $from Start date
* @param \DateTime $to End date
* @return array Array of hourly statistics with success and error counts
*/
public function getCallStatsByHourRange(\DateTime $from, \DateTime $to): array
{
$qb = $this->db->getQueryBuilder();

$qb->select(
$qb->createFunction('HOUR(created) as hour'),
$qb->createFunction('SUM(CASE WHEN status_code >= 200 AND status_code < 300 THEN 1 ELSE 0 END) as success'),
$qb->createFunction('SUM(CASE WHEN status_code < 200 OR status_code >= 300 THEN 1 ELSE 0 END) as error')
)
->from('openconnector_call_logs')
->where($qb->expr()->gte('created', $qb->createNamedParameter($from->format('Y-m-d H:i:s'))))
->andWhere($qb->expr()->lte('created', $qb->createNamedParameter($to->format('Y-m-d H:i:s'))))
->groupBy('hour')
->orderBy('hour', 'ASC');

$result = $qb->execute();
$stats = [];

while ($row = $result->fetch()) {
$stats[$row['hour']] = [
'success' => (int)$row['success'],
'error' => (int)$row['error']
];
}

return $stats;
}
}
78 changes: 78 additions & 0 deletions lib/Db/JobLogMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,82 @@ public function getLastCallLog(): ?JobLog
return null;
}
}

/**
* Get job statistics grouped by date for a specific date range
*
* @param \DateTime $from Start date
* @param \DateTime $to End date
* @return array Array of daily statistics with counts per log level
*/
public function getJobStatsByDateRange(\DateTime $from, \DateTime $to): array
{
$qb = $this->db->getQueryBuilder();

$qb->select(
$qb->createFunction('DATE(created) as date'),
$qb->createFunction('SUM(CASE WHEN level = \'INFO\' THEN 1 ELSE 0 END) as info'),
$qb->createFunction('SUM(CASE WHEN level = \'WARNING\' THEN 1 ELSE 0 END) as warning'),
$qb->createFunction('SUM(CASE WHEN level = \'ERROR\' THEN 1 ELSE 0 END) as error'),
$qb->createFunction('SUM(CASE WHEN level = \'DEBUG\' THEN 1 ELSE 0 END) as debug')
)
->from('openconnector_job_logs')
->where($qb->expr()->gte('created', $qb->createNamedParameter($from->format('Y-m-d H:i:s'))))
->andWhere($qb->expr()->lte('created', $qb->createNamedParameter($to->format('Y-m-d H:i:s'))))
->groupBy('date')
->orderBy('date', 'ASC');

$result = $qb->execute();
$stats = [];

while ($row = $result->fetch()) {
$stats[$row['date']] = [
'info' => (int)$row['info'],
'warning' => (int)$row['warning'],
'error' => (int)$row['error'],
'debug' => (int)$row['debug']
];
}

return $stats;
}

/**
* Get job statistics grouped by hour for a specific date range
*
* @param \DateTime $from Start date
* @param \DateTime $to End date
* @return array Array of hourly statistics with counts per log level
*/
public function getJobStatsByHourRange(\DateTime $from, \DateTime $to): array
{
$qb = $this->db->getQueryBuilder();

$qb->select(
$qb->createFunction('HOUR(created) as hour'),
$qb->createFunction('SUM(CASE WHEN level = \'INFO\' THEN 1 ELSE 0 END) as info'),
$qb->createFunction('SUM(CASE WHEN level = \'WARNING\' THEN 1 ELSE 0 END) as warning'),
$qb->createFunction('SUM(CASE WHEN level = \'ERROR\' THEN 1 ELSE 0 END) as error'),
$qb->createFunction('SUM(CASE WHEN level = \'DEBUG\' THEN 1 ELSE 0 END) as debug')
)
->from('openconnector_job_logs')
->where($qb->expr()->gte('created', $qb->createNamedParameter($from->format('Y-m-d H:i:s'))))
->andWhere($qb->expr()->lte('created', $qb->createNamedParameter($to->format('Y-m-d H:i:s'))))
->groupBy('hour')
->orderBy('hour', 'ASC');

$result = $qb->execute();
$stats = [];

while ($row = $result->fetch()) {
$stats[$row['hour']] = [
'info' => (int)$row['info'],
'warning' => (int)$row['warning'],
'error' => (int)$row['error'],
'debug' => (int)$row['debug']
];
}

return $stats;
}
}
62 changes: 62 additions & 0 deletions lib/Db/SynchronizationContractLogMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,66 @@ public function updateFromArray(int $id, array $object): SynchronizationContract

return $this->update($obj);
}

/**
* Get synchronization execution counts by date for a specific date range
*
* @param \DateTime $from Start date
* @param \DateTime $to End date
* @return array Array of daily execution counts
*/
public function getSyncStatsByDateRange(\DateTime $from, \DateTime $to): array
{
$qb = $this->db->getQueryBuilder();

$qb->select(
$qb->createFunction('DATE(created) as date'),
$qb->createFunction('COUNT(*) as executions')
)
->from('openconnector_synchronization_contract_logs')
->where($qb->expr()->gte('created', $qb->createNamedParameter($from->format('Y-m-d H:i:s'))))
->andWhere($qb->expr()->lte('created', $qb->createNamedParameter($to->format('Y-m-d H:i:s'))))
->groupBy('date')
->orderBy('date', 'ASC');

$result = $qb->execute();
$stats = [];

while ($row = $result->fetch()) {
$stats[$row['date']] = (int)$row['executions'];
}

return $stats;
}

/**
* Get synchronization execution counts by hour for a specific date range
*
* @param \DateTime $from Start date
* @param \DateTime $to End date
* @return array Array of hourly execution counts
*/
public function getSyncStatsByHourRange(\DateTime $from, \DateTime $to): array
{
$qb = $this->db->getQueryBuilder();

$qb->select(
$qb->createFunction('HOUR(created) as hour'),
$qb->createFunction('COUNT(*) as executions')
)
->from('openconnector_synchronization_contract_logs')
->where($qb->expr()->gte('created', $qb->createNamedParameter($from->format('Y-m-d H:i:s'))))
->andWhere($qb->expr()->lte('created', $qb->createNamedParameter($to->format('Y-m-d H:i:s'))))
->groupBy('hour')
->orderBy('hour', 'ASC');

$result = $qb->execute();
$stats = [];

while ($row = $result->fetch()) {
$stats[$row['hour']] = (int)$row['executions'];
}

return $stats;
}
}
Loading

0 comments on commit bbd2317

Please sign in to comment.