Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEW Add new execmetric debur URL parameter to print out exection time and peak memory usage #8733

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions _config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@ SilverStripe\Core\Manifest\VersionProvider:
Name: httpconfig-dev
Only:
environment: dev
After:
- 'requestprocessors'
---
# Set dev level to disabled with a higher forcing level
SilverStripe\Control\Middleware\HTTPCacheControlMiddleware:
defaultState: 'disabled'
defaultForcingLevel: 3

SilverStripe\Core\Injector\Injector:
SilverStripe\Control\Director:
properties:
Middlewares:
ExecMetricMiddleware: '%$SilverStripe\Control\Middleware\ExecMetricMiddleware'
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ session variables, used templates and much more.
| isDev | | 1 | | Put the site into [development mode](../), enabling debugging messages to the browser on a live server. For security, you'll be asked to log in with an administrator log-in. Will persist for the current browser session. |
| isTest | | 1 | | See above. |
| debug | | 1 | | Show a collection of debugging information about the director / controller operation |
| debug_request | | 1 | | Show all steps of the request from initial [HTTPRequest](api:SilverStripe\Control\HTTPRequest) to [Controller](api:SilverStripe\Control\Controller) to Template Rendering |
| debug_request | | 1 | | Show all steps of the request from initial [HTTPRequest](api:SilverStripe\Control\HTTPRequest) to [Controller](api:SilverStripe\Control\Controller) to Template Rendering |
| execmetric | | 1 | | Display the execution time and peak memory usage for the request |

## Classes and Objects

Expand Down
67 changes: 67 additions & 0 deletions src/Control/Middleware/ExecMetricMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace SilverStripe\Control\Middleware;

use SilverStripe\Assets\File;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Dev\Debug;

/**
* Secures requests by only allowing a whitelist of Host values
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really what this middleware does?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh whoops that's a retrospective review. Explains why I didn't see all the options when submitting it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ I copied over one of the other files. Forgot to update the comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do a follow up PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*/
class ExecMetricMiddleware implements HTTPMiddleware
{
/**
* @inheritdoc
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is equivalent to not having a doc block at all

public function process(HTTPRequest $request, callable $delegate)
{
if (!$this->showMetric($request)) {
return $delegate($request);
}

$start = microtime(true);
try {
return $delegate($request);
} finally {
$end = microtime(true);
Debug::message(
sprintf(
"Execution time: %s, Peak memory usage: %s\n",
$this->formatExecutionTime($start, $end),
$this->formatPeakMemoryUsage()
),
false
);
}
}

private function showMetric(HTTPRequest $request)
{
return Director::isDev() && array_key_exists('execmetric', $request->getVars());
}

/**
* Convert the provided start and end time to a interval in secs.
* @param float $start
* @param float $end
* @return string
*/
private function formatExecutionTime($start, $end)
{
$diff = round($end - $start, 4);
return $diff . ' seconds';
}

/**
* Get the peak memory usage formatted has a string and a meaningful unit.
* @return string
*/
private function formatPeakMemoryUsage()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer protected over private

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those 3 methods are implementations details and are not meant to be reuse. In theory, I could have implemented all of those directly in process, but I wanted to split them out for readability. In this context, I don't think it's worthwhile increasing our public API surface.

{
$bytes = memory_get_peak_usage(true);
return File::format_size($bytes);
}
}