Create new "Debug" page for testing internal functions in debug mode.
This commit is contained in:
parent
4b74264441
commit
0939599532
|
@ -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' => [
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -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(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue