Create new "Debug" page for testing internal functions in debug mode.

This commit is contained in:
Buster "Silver Eagle" Neece 2020-03-01 10:26:49 -06:00
parent 4b74264441
commit 0939599532
No known key found for this signature in database
GPG Key ID: 6D9E12FF03411F4E
7 changed files with 265 additions and 111 deletions

View File

@ -33,16 +33,16 @@ return function (\App\Event\BuildAdminMenu $e) {
'url' => $router->named('admin:logs:index'),
'permission' => Acl::GLOBAL_LOGS,
],
'auditlog' => [
'label' => __('Audit Log'),
'url' => $router->named('admin:auditlog:index'),
'permission' => Acl::GLOBAL_LOGS,
],
'backups' => [
'label' => __('Backups'),
'url' => $router->named('admin:backups:index'),
'permission' => Acl::GLOBAL_BACKUPS,
],
'debug' => [
'label' => __('System Debugger'),
'url' => $router->named('admin:debug:index'),
'permission' => Acl::GLOBAL_ALL,
],
],
],
'users' => [
@ -59,6 +59,11 @@ return function (\App\Event\BuildAdminMenu $e) {
'url' => $router->named('admin:permissions:index'),
'permission' => Acl::GLOBAL_PERMISSIONS,
],
'auditlog' => [
'label' => __('Audit Log'),
'url' => $router->named('admin:auditlog:index'),
'permission' => Acl::GLOBAL_LOGS,
],
],
],
'stations' => [

View File

@ -11,12 +11,25 @@ use Slim\Routing\RouteCollectorProxy;
return function (App $app) {
$app->group('/admin', function (RouteCollectorProxy $group) {
$group->get('', Controller\Admin\IndexController::class . ':indexAction')
$group->get('', Controller\Admin\IndexController::class)
->setName('admin:index:index');
$group->get('/sync/{type}', Controller\Admin\IndexController::class . ':syncAction')
->setName('admin:index:sync')
->add(new Middleware\Permissions(Acl::GLOBAL_ALL));
$group->group('/debug', function (RouteCollectorProxy $group) {
$group->get('', Controller\Admin\DebugController::class)
->setName('admin:debug:index');
$group->get('/sync/{type}', Controller\Admin\DebugController::class . ':syncAction')
->setName('admin:debug:sync');
$group->group('/station/{station_id}', function (RouteCollectorProxy $group) {
$group->map(['GET', 'POST'], '/nextsong', Controller\Admin\DebugController::class . ':nextsongAction')
->setName('admin:debug:nextsong');
})->add(Middleware\GetStation::class);
})->add(new Middleware\Permissions(Acl::GLOBAL_ALL));
$group->group('/install', function (RouteCollectorProxy $group) {

View File

@ -0,0 +1,109 @@
<?php
namespace App\Controller\Admin;
use App\Entity;
use App\Event\Radio\GetNextSong;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\AutoDJ;
use App\Sync\Runner;
use Cake\Chronos\Chronos;
use Monolog\Handler\TestHandler;
use Monolog\Logger;
use Psr\Http\Message\ResponseInterface;
class DebugController
{
protected Logger $logger;
protected TestHandler $testHandler;
public function __construct(Logger $logger)
{
$this->logger = $logger;
$this->testHandler = new TestHandler(Logger::DEBUG, false);
}
public function __invoke(
ServerRequest $request,
Response $response,
Entity\Repository\StationRepository $stationRepo,
Runner $sync
): ResponseInterface {
return $request->getView()->renderToResponse($response, 'admin/debug/index', [
'sync_times' => $sync->getSyncTimes(),
'stations' => $stationRepo->fetchSelect(),
]);
}
public function syncAction(
ServerRequest $request,
Response $response,
Runner $sync,
$type
): ResponseInterface {
$this->logger->pushHandler($this->testHandler);
switch ($type) {
case 'long':
$sync->syncLong(true);
break;
case 'medium':
$sync->syncMedium(true);
break;
case 'short':
$sync->syncShort(true);
break;
case 'nowplaying':
default:
$sync->syncNowplaying(true);
break;
}
$this->logger->popHandler();
return $request->getView()->renderToResponse($response, 'system/log_view', [
'sidebar' => null,
'title' => __('Sync Task Output'),
'log_records' => $this->testHandler->getRecords(),
]);
}
public function nextsongAction(
ServerRequest $request,
Response $response,
AutoDJ $autoDJ
): ResponseInterface {
$this->logger->pushHandler($this->testHandler);
$station = $request->getStation();
$nowString = $request->getParam('now');
if (!empty($nowString)) {
$stationTz = $station->getTimezone();
$now = Chronos::parse($nowString, $stationTz);
$this->logger->debug('Modified time for calculation.', [
'new_time' => (string)$now,
]);
Chronos::setTestNow($now);
}
$event = new GetNextSong($station);
$autoDJ->calculateNextSong($event);
Chronos::setTestNow(null);
$this->logger->popHandler();
return $request->getView()->renderToResponse($response, 'system/log_view', [
'sidebar' => null,
'title' => __('Debug Output'),
'log_records' => $this->testHandler->getRecords(),
]);
}
}

View File

@ -8,32 +8,15 @@ use App\Radio\Quota;
use App\Settings;
use App\Sync\Runner;
use Brick\Math\BigInteger;
use Monolog\Handler\TestHandler;
use Monolog\Logger;
use Psr\Http\Message\ResponseInterface;
class IndexController
{
protected Logger $logger;
protected Runner $sync;
public function __construct(Logger $logger, Runner $sync)
{
$this->logger = $logger;
$this->sync = $sync;
}
/**
* Main display.
*
* @param ServerRequest $request
* @param Response $response
*
* @return ResponseInterface
*/
public function indexAction(ServerRequest $request, Response $response): ResponseInterface
{
public function __invoke(
ServerRequest $request,
Response $response,
Runner $sync
): ResponseInterface {
$view = $request->getView();
$user = $request->getUser();
@ -45,7 +28,7 @@ class IndexController
if ($acl->userAllowed($user, Acl::GLOBAL_ALL)) {
$view->addData([
'sync_times' => $this->sync->getSyncTimes(),
'sync_times' => $sync->getSyncTimes(),
]);
}
@ -62,39 +45,4 @@ class IndexController
'space_total' => Quota::getReadableSize($space_total),
]);
}
public function syncAction(ServerRequest $request, Response $response, $type): ResponseInterface
{
$view = $request->getView();
$handler = new TestHandler(Logger::DEBUG, false);
$this->logger->pushHandler($handler);
switch ($type) {
case 'long':
$this->sync->syncLong(true);
break;
case 'medium':
$this->sync->syncMedium(true);
break;
case 'short':
$this->sync->syncShort(true);
break;
case 'nowplaying':
default:
$this->sync->syncNowplaying(true);
break;
}
$this->logger->popHandler();
return $view->renderToResponse($response, 'system/log_view', [
'sidebar' => null,
'title' => __('Sync Task Output'),
'log_records' => $handler->getRecords(),
]);
}
}

View File

@ -284,11 +284,17 @@ class AutoDJ implements EventSubscriberInterface
continue;
}
$log_playlists = [];
$eligible_playlists = [];
foreach ($playlists_by_type[$type] as $playlist_id => $playlist) {
/** @var Entity\StationPlaylist $playlist */
if ($playlist->shouldPlayNow($now, $cued_song_history)) {
$eligible_playlists[$playlist_id] = $playlist->getWeight();
$log_playlists[] = [
'id' => $playlist->getId(),
'name' => $playlist->getName(),
'weight' => $playlist->getWeight(),
];
}
}
@ -296,8 +302,11 @@ class AutoDJ implements EventSubscriberInterface
continue;
}
$this->logger->info(sprintf('%d playable playlists of type "%s" found.', count($eligible_playlists), $type),
$eligible_playlists);
$this->logger->info(sprintf(
'%d playable playlist(s) of type "%s" found.',
count($eligible_playlists),
$type
), ['playlists' => $log_playlists]);
// Shuffle playlists by weight.
uasort($eligible_playlists, function ($a, $b) {

View File

@ -0,0 +1,68 @@
<?php
$this->layout('main', [
'title' => __('System Debugger'),
'manual' => true,
]);
?>
<h2 class="outside-card-header mb-1"><?=__('System Debugger')?></h2>
<div class="card mb-3">
<div class="card-header bg-primary-dark">
<h2 class="card-title"><?=__('Synchronization Tasks')?></h2>
</div>
<div class="card-body">
<div class="row">
<?php foreach ($sync_times as $sync_key => $sync_info): ?>
<div class="col">
<h5 class="mb-0"><?=$sync_info['name']?></h5>
<p><?=implode(', ', $sync_info['contents'])?></p>
<div class="buttons">
<a class="btn btn-sm btn-primary" role="button" href="<?=$router->named('admin:debug:sync',
['type' => $sync_key])?>">
<?=__('Run Task')?>
</a>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="card">
<div class="card-header bg-primary-dark">
<h2 class="card-title"><?=__('Station-Specific Debugging')?></h2>
</div>
<div class="card-body pb-0">
<ul class="nav nav-pills nav-pills-scrollable card-header-pills">
<?php foreach ($stations as $station_id => $station_name): ?>
<li class="nav-item">
<a class="nav-link" role="tab" data-toggle="tab" aria-expanded="true" aria-controls="debug_station_<?=$station_id?>" href="#debug_station_<?=$station_id?>"><?=$this->e($station_name)?></a>
</li>
<?php endforeach; ?>
</ul>
</div>
<div class="tab-content">
<?php foreach ($stations as $station_id => $station_name): ?>
<div class="card-body card-padding-sm tab-pane" id="debug_station_<?=$station_id?>">
<h3><?=$station_name?></h3>
<div class="row">
<div class="col">
<h5><?=__('Test AutoDJ Next Song')?></h5>
<form class="form" method="get" action="<?=$router->named('admin:debug:nextsong',
['station_id' => $station_id])?>">
<div class="form-group">
<label for="<?=$station_id?>_now"><?=__('Test time (Leave blank for current time)')?>:</label>
<input id="<?=$station_id?>_now" name="now" class="form-control" type="datetime-local">
</div>
<button type="submit" class="btn btn-primary"><?=__('Run Test')?></button>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>

View File

@ -7,7 +7,7 @@
$this->layout('main', [
'title' => 'Administration',
'manual' => true,
'page_class' => 'page-admin'
'page_class' => 'page-admin',
]);
$assets
@ -15,74 +15,76 @@ $assets
->addInlineJs($this->fetch('admin/index/index.js'), 99);
?>
<h2 class="outside-card-header mb-1"><?=__('Administration') ?></h2>
<h2 class="outside-card-header mb-1"><?=__('Administration')?></h2>
<div class="card-columns">
<?php foreach($admin_panels as $category_id => $category): ?>
<section class="card" role="region">
<div class="card-header bg-primary-dark">
<h2 class="card-title"><?=$category['label'] ?></h2>
</div>
<div class="list-group list-group-flush">
<?php foreach($category['items'] as $item): ?>
<a class="list-group-item list-group-item-action" href="<?=$item['url'] ?>" title="<?=$item['title'] ?>">
<?=$item['label'] ?>
</a>
<?php endforeach; ?>
</div>
</section>
<?php endforeach; ?>
<?php foreach ($admin_panels as $category_id => $category): ?>
<section class="card" role="region">
<div class="card-header bg-primary-dark">
<h2 class="card-title"><?=$category['label']?></h2>
</div>
<div class="list-group list-group-flush">
<?php foreach ($category['items'] as $item): ?>
<a class="list-group-item list-group-item-action" href="<?=$item['url']?>" title="<?=$item['title']?>">
<?=$item['label']?>
</a>
<?php endforeach; ?>
</div>
</section>
<?php endforeach; ?>
</div>
<h2 class="outside-card-header mb-1"><?=__('Server Status') ?></h2>
<h2 class="outside-card-header mb-1"><?=__('Server Status')?></h2>
<div class="card-deck system-statistics">
<div class="card cpu-usage-card" role="region">
<div class="card-body bg-primary-dark">
<h3 class="text-white">
<?=round($load[0], 2) ?><br>
<small><?=__('Current CPU Load') ?></small>
<?=round($load[0], 2)?><br>
<small><?=__('Current CPU Load')?></small>
</h3>
</div>
</div>
<div class="card cpu-usage-card" role="region">
<div class="card-body bg-primary-dark text-white">
<h3 class="text-white">
<?=round($load[2], 2) ?><br>
<small><?=__('15-Minute CPU Load Average') ?></small>
<?=round($load[2], 2)?><br>
<small><?=__('15-Minute CPU Load Average')?></small>
</h3>
</div>
</div>
<div class="card storage-card" role="region">
<div class="card-body bg-primary-dark text-white">
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="<?=$space_percent ?>" aria-valuemin="0" aria-valuemax="100" style="width: <?=$space_percent ?>%;">
<span class="sr-only"><?=$space_percent ?>%</span>
<div class="progress-bar" role="progressbar" aria-valuenow="<?=$space_percent?>" aria-valuemin="0" aria-valuemax="100" style="width: <?=$space_percent?>%;">
<span class="sr-only"><?=$space_percent?>%</span>
</div>
</div>
<h3 class="text-white"><small><?=__('%s of %s Used', $space_used, $space_total) ?></small></h3>
<h3 class="text-white"><small><?=__('%s of %s Used', $space_used, $space_total)?></small></h3>
</div>
</div>
</div>
<h2 class="outside-card-header mb-1"><?=__('Synchronization Tasks') ?></h2>
<h2 class="outside-card-header mb-1"><?=__('Synchronization Tasks')?></h2>
<div class="card-deck">
<?php foreach($sync_times as $sync_key => $sync_info): ?>
<section class="card" role="region">
<div class="card-header bg-primary-dark">
<h2 class="card-title"><?=$sync_info['name'] ?></h2>
<h3 class="card-subtitle"><?=implode(', ', $sync_info['contents']) ?></h3>
</div>
<div class="card-body">
<p class="card-text"><?=__('Last run: %s', '<time data-duration="'.$sync_info['diff'].'"></time>') ?></p>
</div>
<div class="card-actions">
<a class="btn btn-outline-primary" role="button" href="<?=$router->named('admin:index:sync', ['type' => $sync_key]) ?>">
<i class="material-icons" aria-hidden="true">send</i>
<?=__('Run Task') ?>
</a>
</div>
</section>
<?php endforeach; ?>
<?php foreach ($sync_times as $sync_key => $sync_info): ?>
<section class="card" role="region">
<div class="card-header bg-primary-dark">
<h2 class="card-title"><?=$sync_info['name']?></h2>
<h3 class="card-subtitle"><?=implode(', ', $sync_info['contents'])?></h3>
</div>
<div class="card-body">
<p class="card-text"><?=__('Last run: %s',
'<time data-duration="' . $sync_info['diff'] . '"></time>')?></p>
</div>
<div class="card-actions">
<a class="btn btn-outline-primary" role="button" href="<?=$router->named('admin:debug:sync',
['type' => $sync_key])?>">
<i class="material-icons" aria-hidden="true">send</i>
<?=__('Run Task')?>
</a>
</div>
</section>
<?php endforeach; ?>
</div>