mirror of
https://github.com/getgrav/grav.git
synced 2026-03-03 11:01:30 +01:00
Merge branch 'feature/clockwork' into feature/clockwork-twig
This commit is contained in:
@@ -57,7 +57,7 @@ class Debugger
|
||||
protected $clockwork;
|
||||
|
||||
/** @var bool */
|
||||
protected $enabled;
|
||||
protected $enabled = false;
|
||||
|
||||
protected $initialized = false;
|
||||
|
||||
@@ -88,9 +88,6 @@ class Debugger
|
||||
|
||||
$this->requestTime = $_SERVER['REQUEST_TIME_FLOAT'] ?? GRAV_REQUEST_TIME;
|
||||
|
||||
// Enable debugger until $this->init() gets called.
|
||||
$this->enabled = true;
|
||||
|
||||
// Set deprecation collector.
|
||||
$this->setErrorHandler();
|
||||
}
|
||||
@@ -173,6 +170,7 @@ class Debugger
|
||||
}
|
||||
|
||||
$this->addMessage('Grav v' . GRAV_VERSION);
|
||||
$this->config->debug();
|
||||
|
||||
if ($clockwork) {
|
||||
$clockwork->info('System Configuration', $this->config->get('system'));
|
||||
@@ -188,6 +186,8 @@ class Debugger
|
||||
public function finalize(): void
|
||||
{
|
||||
if ($this->clockwork && $this->enabled) {
|
||||
$this->addMeasures();
|
||||
|
||||
$deprecations = $this->getDeprecations();
|
||||
$count = count($deprecations);
|
||||
if (!$count) {
|
||||
@@ -195,7 +195,7 @@ class Debugger
|
||||
}
|
||||
|
||||
/** @var UserData $userData */
|
||||
$userData = $this->clockwork->userData("Deprecated ({$count})");
|
||||
$userData = $this->clockwork->userData('Deprecated');
|
||||
$userData->counters([
|
||||
'Deprecated' => count($deprecations)
|
||||
]);
|
||||
@@ -213,6 +213,34 @@ class Debugger
|
||||
}
|
||||
}
|
||||
|
||||
protected function addMeasures()
|
||||
{
|
||||
if (!$this->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$nowTime = microtime(true);
|
||||
$clkTimeLine = $this->clockwork ? $this->clockwork->getTimeline() : null;
|
||||
$debTimeLine = $this->debugbar ? $this->debugbar['time'] : null;
|
||||
foreach ($this->timers as $name => $data) {
|
||||
$description = $data[0];
|
||||
$startTime = $data[1];
|
||||
$endTime = $data[2] ?? $nowTime;
|
||||
if ($endTime - $startTime < 0.001) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($clkTimeLine) {
|
||||
$clkTimeLine->addEvent($name, $description, $startTime, $endTime);
|
||||
}
|
||||
|
||||
if ($debTimeLine) {
|
||||
$debTimeLine->addMeasure($description, $startTime, $endTime);
|
||||
}
|
||||
}
|
||||
$this->timers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/get the enabled state of the debugger
|
||||
*
|
||||
@@ -306,6 +334,8 @@ class Debugger
|
||||
if ($this->debugbar) {
|
||||
return $this->debugbar->getCollector($collector);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,6 +352,7 @@ class Debugger
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->addMeasures();
|
||||
$this->addDeprecations();
|
||||
|
||||
echo $this->renderer->render();
|
||||
@@ -338,6 +369,7 @@ class Debugger
|
||||
public function sendDataInHeaders()
|
||||
{
|
||||
if ($this->enabled && $this->debugbar) {
|
||||
$this->addMeasures();
|
||||
$this->addDeprecations();
|
||||
$this->debugbar->sendDataInHeaders();
|
||||
}
|
||||
@@ -356,6 +388,7 @@ class Debugger
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->addMeasures();
|
||||
$this->addDeprecations();
|
||||
$this->timers = [];
|
||||
|
||||
@@ -372,9 +405,7 @@ class Debugger
|
||||
*/
|
||||
public function startTimer($name, $description = null)
|
||||
{
|
||||
if ($this->enabled || strpos($name, '_') === 0) {
|
||||
$this->timers[$name] = [$description, microtime(true)];
|
||||
}
|
||||
$this->timers[$name] = [$description, microtime(true)];
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -388,23 +419,10 @@ class Debugger
|
||||
*/
|
||||
public function stopTimer($name)
|
||||
{
|
||||
if (isset($this->timers[$name]) && (strpos($name, '_') === 0 || $this->enabled)) {
|
||||
[$description, $startTime] = $this->timers[$name];
|
||||
if (isset($this->timers[$name])) {
|
||||
$endTime = microtime(true);
|
||||
if ($endTime - $startTime < 0.001) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($this->debugbar) {
|
||||
$this->debugbar['time']->addMeasure($description, $startTime, $endTime);
|
||||
}
|
||||
|
||||
if ($this->clockwork) {
|
||||
$timeLine = $this->clockwork->getTimeline();
|
||||
$timeLine->addEvent($name, $description, $startTime, $endTime);
|
||||
}
|
||||
$this->timers[$name][] = $endTime;
|
||||
}
|
||||
unset($this->timers[$name]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -16,12 +16,8 @@ use Grav\Common\Page\Medium\ImageMedium;
|
||||
use Grav\Common\Page\Medium\Medium;
|
||||
use Grav\Common\Processors\AssetsProcessor;
|
||||
use Grav\Common\Processors\BackupsProcessor;
|
||||
use Grav\Common\Processors\ConfigurationProcessor;
|
||||
use Grav\Common\Processors\DebuggerAssetsProcessor;
|
||||
use Grav\Common\Processors\DebuggerProcessor;
|
||||
use Grav\Common\Processors\ErrorsProcessor;
|
||||
use Grav\Common\Processors\InitializeProcessor;
|
||||
use Grav\Common\Processors\LoggerProcessor;
|
||||
use Grav\Common\Processors\PagesProcessor;
|
||||
use Grav\Common\Processors\PluginsProcessor;
|
||||
use Grav\Common\Processors\RenderProcessor;
|
||||
@@ -89,8 +85,6 @@ class Grav extends Container
|
||||
* @var array All middleware processors that are processed in $this->process()
|
||||
*/
|
||||
protected $middleware = [
|
||||
'configurationProcessor',
|
||||
'debuggerProcessor',
|
||||
'initializeProcessor',
|
||||
'pluginsProcessor',
|
||||
'themesProcessor',
|
||||
@@ -181,12 +175,6 @@ class Grav extends Container
|
||||
|
||||
$container = new Container(
|
||||
[
|
||||
'configurationProcessor' => function () {
|
||||
return new ConfigurationProcessor($this);
|
||||
},
|
||||
'debuggerProcessor' => function () {
|
||||
return new DebuggerProcessor($this);
|
||||
},
|
||||
'initializeProcessor' => function () {
|
||||
return new InitializeProcessor($this);
|
||||
},
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Processors
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Processors;
|
||||
|
||||
use Grav\Common\Config\Config;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use Monolog\Handler\SyslogHandler;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class ConfigurationProcessor extends ProcessorBase
|
||||
{
|
||||
public $id = '_config';
|
||||
public $title = 'Configuration';
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
{
|
||||
$grav = $this->container;
|
||||
|
||||
// Initialize Configuration
|
||||
$this->startTimer('_config', 'Configuration');
|
||||
/** @var Config $config */
|
||||
$config = $grav['config'];
|
||||
$config->init();
|
||||
$grav['plugins']->setup();
|
||||
$this->stopTimer('_config');
|
||||
|
||||
// Initialize Logging
|
||||
$this->startTimer('_logger', 'Logger');
|
||||
switch ($config->get('system.log.handler', 'file')) {
|
||||
case 'syslog':
|
||||
$log = $grav['log'];
|
||||
$log->popHandler();
|
||||
|
||||
$facility = $config->get('system.log.syslog.facility', 'local6');
|
||||
$logHandler = new SyslogHandler('grav', $facility);
|
||||
$formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%");
|
||||
$logHandler->setFormatter($formatter);
|
||||
|
||||
$log->pushHandler($logHandler);
|
||||
break;
|
||||
}
|
||||
$this->stopTimer('_logger');
|
||||
|
||||
// Initialize Error Handlers
|
||||
$this->startTimer('_errors', 'Error Handlers Reset');
|
||||
$this->container['errors']->resetHandlers();
|
||||
$this->stopTimer('_errors');
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Processors
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Processors;
|
||||
|
||||
use Clockwork\Clockwork;
|
||||
use Clockwork\DataSource\PsrMessageDataSource;
|
||||
use Clockwork\Helpers\ServerTiming;
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Framework\Psr7\Response;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class DebuggerProcessor extends ProcessorBase
|
||||
{
|
||||
public $id = '_debugger';
|
||||
public $title = 'Init Debugger';
|
||||
|
||||
protected $clockwork;
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
{
|
||||
$this->startTimer();
|
||||
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = $this->container['debugger']->init();
|
||||
|
||||
$clockwork = $debugger->getClockwork();
|
||||
if ($clockwork) {
|
||||
$server = $request->getServerParams();
|
||||
$baseUri = parse_url(dirname($server['PHP_SELF']), PHP_URL_PATH);
|
||||
if ($baseUri === '/') {
|
||||
$baseUri = '';
|
||||
}
|
||||
$requestTime = $_SERVER['REQUEST_TIME_FLOAT'] ?? GRAV_REQUEST_TIME;
|
||||
|
||||
$request = $request
|
||||
->withAttribute('base_uri', $baseUri)
|
||||
->withAttribute('request_time', $requestTime);
|
||||
|
||||
// Handle clockwork API calls.
|
||||
$uri = $request->getUri();
|
||||
if (mb_strpos($uri->getPath(), $baseUri . '/__clockwork/') === 0) {
|
||||
return $this->retrieveRequest($request, $clockwork);
|
||||
}
|
||||
|
||||
$this->container['clockwork'] = $clockwork;
|
||||
}
|
||||
|
||||
$this->stopTimer();
|
||||
|
||||
$response = $handler->handle($request);
|
||||
|
||||
if ($clockwork) {
|
||||
$debugger->finalize();
|
||||
|
||||
return $this->logRequest($request, $response, $clockwork);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function logRequest(ServerRequestInterface $request, ResponseInterface $response, Clockwork $clockwork)
|
||||
{
|
||||
$clockwork->getTimeline()->finalize($request->getAttribute('request_time'));
|
||||
$clockwork->addDataSource(new PsrMessageDataSource($request, $response));
|
||||
|
||||
$clockwork->resolveRequest();
|
||||
$clockwork->storeRequest();
|
||||
|
||||
$clockworkRequest = $clockwork->getRequest();
|
||||
|
||||
$response = $response
|
||||
->withHeader('X-Clockwork-Id', $clockworkRequest->id)
|
||||
->withHeader('X-Clockwork-Version', $clockwork::VERSION);
|
||||
|
||||
$basePath = $request->getAttribute('base_uri');
|
||||
if ($basePath) {
|
||||
$response = $response->withHeader('X-Clockwork-Path', $basePath . '/__clockwork/');
|
||||
}
|
||||
|
||||
return $response->withHeader('Server-Timing', ServerTiming::fromRequest($clockworkRequest)->value());
|
||||
}
|
||||
|
||||
protected function retrieveRequest(RequestInterface $request, Clockwork $clockwork): Response
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
'Grav-Internal-SkipShutdown' => 1
|
||||
];
|
||||
|
||||
$path = $request->getUri()->getPath();
|
||||
$clockworkDataUri = '#/__clockwork(?:/(?<id>[0-9-]+))?(?:/(?<direction>(?:previous|next)))?(?:/(?<count>\d+))?#';
|
||||
if (preg_match($clockworkDataUri, $path, $matches) === false) {
|
||||
$response = ['message' => 'Bad Input'];
|
||||
|
||||
return new Response(400, $headers, json_encode($response));
|
||||
}
|
||||
|
||||
$id = $matches['id'] ?? null;
|
||||
$direction = $matches['direction'] ?? null;
|
||||
$count = $matches['count'] ?? null;
|
||||
|
||||
$storage = $clockwork->getStorage();
|
||||
|
||||
if ($direction === 'previous') {
|
||||
$data = $storage->previous($id, $count);
|
||||
} elseif ($direction === 'next') {
|
||||
$data = $storage->next($id, $count);
|
||||
} elseif ($id === 'latest') {
|
||||
$data = $storage->latest();
|
||||
} else {
|
||||
$data = $storage->find($id);
|
||||
}
|
||||
|
||||
if (preg_match('#(?<id>[0-9-]+|latest)/extended#', $path)) {
|
||||
$clockwork->extendRequest($data);
|
||||
}
|
||||
|
||||
if (!$data) {
|
||||
$response = ['message' => 'Not Found'];
|
||||
|
||||
return new Response(404, $headers, json_encode($response));
|
||||
}
|
||||
|
||||
$data = is_array($data) ? array_map(function ($item) { return $item->toArray(); }, $data) : $data->toArray();
|
||||
|
||||
return new Response(200, $headers, json_encode($data));
|
||||
}
|
||||
}
|
||||
@@ -9,26 +9,192 @@
|
||||
|
||||
namespace Grav\Common\Processors;
|
||||
|
||||
use Clockwork\Clockwork;
|
||||
use Clockwork\DataSource\PsrMessageDataSource;
|
||||
use Clockwork\Helpers\ServerTiming;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Common\Uri;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Psr7\Response;
|
||||
use Grav\Framework\Session\Exceptions\SessionException;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use Monolog\Handler\SyslogHandler;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class InitializeProcessor extends ProcessorBase
|
||||
{
|
||||
public $id = 'init';
|
||||
public $id = '_init';
|
||||
public $title = 'Initialize';
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
{
|
||||
$this->startTimer();
|
||||
$this->startTimer('_config', 'Configuration');
|
||||
$this->initializeConfig();
|
||||
$this->stopTimer('_config');
|
||||
|
||||
$this->startTimer('_logger', 'Logger');
|
||||
$this->initializeLogger();
|
||||
$this->stopTimer('_logger');
|
||||
|
||||
$this->startTimer('_errors', 'Error Handlers Reset');
|
||||
$this->initializeErrors();
|
||||
$this->stopTimer('_errors');
|
||||
|
||||
$this->startTimer('_debugger', 'Init Debugger');
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = $this->container['debugger']->init();
|
||||
$clockwork = $debugger->getClockwork();
|
||||
if ($clockwork) {
|
||||
$server = $request->getServerParams();
|
||||
$baseUri = parse_url(dirname($server['PHP_SELF']), PHP_URL_PATH);
|
||||
if ($baseUri === '/') {
|
||||
$baseUri = '';
|
||||
}
|
||||
$requestTime = $_SERVER['REQUEST_TIME_FLOAT'] ?? GRAV_REQUEST_TIME;
|
||||
|
||||
$request = $request
|
||||
->withAttribute('base_uri', $baseUri)
|
||||
->withAttribute('request_time', $requestTime);
|
||||
|
||||
// Handle clockwork API calls.
|
||||
$uri = $request->getUri();
|
||||
if (mb_strpos($uri->getPath(), $baseUri . '/__clockwork/') === 0) {
|
||||
return $this->debuggerRequest($request, $clockwork);
|
||||
}
|
||||
|
||||
$this->container['clockwork'] = $clockwork;
|
||||
}
|
||||
$this->stopTimer('_debugger');
|
||||
|
||||
|
||||
$this->startTimer('_init', 'Initialize');
|
||||
$this->initialize();
|
||||
$this->stopTimer('_init');
|
||||
|
||||
$response = $handler->handle($request);
|
||||
|
||||
if ($clockwork) {
|
||||
$debugger->finalize();
|
||||
|
||||
return $this->logRequest($request, $response, $clockwork);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function logRequest(ServerRequestInterface $request, ResponseInterface $response, Clockwork $clockwork)
|
||||
{
|
||||
$clockwork->getTimeline()->finalize($request->getAttribute('request_time'));
|
||||
$clockwork->addDataSource(new PsrMessageDataSource($request, $response));
|
||||
|
||||
$clockwork->resolveRequest();
|
||||
$clockwork->storeRequest();
|
||||
|
||||
$clockworkRequest = $clockwork->getRequest();
|
||||
|
||||
$response = $response
|
||||
->withHeader('X-Clockwork-Id', $clockworkRequest->id)
|
||||
->withHeader('X-Clockwork-Version', $clockwork::VERSION);
|
||||
|
||||
$basePath = $request->getAttribute('base_uri');
|
||||
if ($basePath) {
|
||||
$response = $response->withHeader('X-Clockwork-Path', $basePath . '/__clockwork/');
|
||||
}
|
||||
|
||||
return $response->withHeader('Server-Timing', ServerTiming::fromRequest($clockworkRequest)->value());
|
||||
}
|
||||
|
||||
protected function debuggerRequest(RequestInterface $request, Clockwork $clockwork): Response
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
'Grav-Internal-SkipShutdown' => 1
|
||||
];
|
||||
|
||||
$path = $request->getUri()->getPath();
|
||||
$clockworkDataUri = '#/__clockwork(?:/(?<id>[0-9-]+))?(?:/(?<direction>(?:previous|next)))?(?:/(?<count>\d+))?#';
|
||||
if (preg_match($clockworkDataUri, $path, $matches) === false) {
|
||||
$response = ['message' => 'Bad Input'];
|
||||
|
||||
return new Response(400, $headers, json_encode($response));
|
||||
}
|
||||
|
||||
$id = $matches['id'] ?? null;
|
||||
$direction = $matches['direction'] ?? null;
|
||||
$count = $matches['count'] ?? null;
|
||||
|
||||
$storage = $clockwork->getStorage();
|
||||
|
||||
if ($direction === 'previous') {
|
||||
$data = $storage->previous($id, $count);
|
||||
} elseif ($direction === 'next') {
|
||||
$data = $storage->next($id, $count);
|
||||
} elseif ($id === 'latest') {
|
||||
$data = $storage->latest();
|
||||
} else {
|
||||
$data = $storage->find($id);
|
||||
}
|
||||
|
||||
if (preg_match('#(?<id>[0-9-]+|latest)/extended#', $path)) {
|
||||
$clockwork->extendRequest($data);
|
||||
}
|
||||
|
||||
if (!$data) {
|
||||
$response = ['message' => 'Not Found'];
|
||||
|
||||
return new Response(404, $headers, json_encode($response));
|
||||
}
|
||||
|
||||
$data = is_array($data) ? array_map(function ($item) { return $item->toArray(); }, $data) : $data->toArray();
|
||||
|
||||
return new Response(200, $headers, json_encode($data));
|
||||
}
|
||||
|
||||
protected function initializeConfig()
|
||||
{
|
||||
// Initialize Configuration
|
||||
$grav = $this->container;
|
||||
/** @var Config $config */
|
||||
$config = $grav['config'];
|
||||
$config->init();
|
||||
$grav['plugins']->setup();
|
||||
}
|
||||
|
||||
protected function initializeLogger()
|
||||
{
|
||||
// Initialize Logging
|
||||
$grav = $this->container;
|
||||
/** @var Config $config */
|
||||
$config = $grav['config'];
|
||||
switch ($config->get('system.log.handler', 'file')) {
|
||||
case 'syslog':
|
||||
$log = $grav['log'];
|
||||
$log->popHandler();
|
||||
|
||||
$facility = $config->get('system.log.syslog.facility', 'local6');
|
||||
$logHandler = new SyslogHandler('grav', $facility);
|
||||
$formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%");
|
||||
$logHandler->setFormatter($formatter);
|
||||
|
||||
$log->pushHandler($logHandler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function initializeErrors()
|
||||
{
|
||||
// Initialize Error Handlers
|
||||
$this->container['errors']->resetHandlers();
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = $this->container['config'];
|
||||
$config->debug();
|
||||
|
||||
// Use output buffering to prevent headers from being sent too early.
|
||||
ob_start();
|
||||
@@ -73,8 +239,5 @@ class InitializeProcessor extends ProcessorBase
|
||||
}
|
||||
|
||||
$this->container->setLocale();
|
||||
$this->stopTimer();
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user