-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpKernel] LoggerDataCollector: splitting logs on different sub-requests #23659
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
Conversation
Should the profile for the master request get all logs? At least yes when |
if (func_num_args() === 1) { | ||
$requestHash = func_get_arg(0); | ||
if (isset($this->recordsRequest[$requestHash]['records']) | ||
&& $requestHash !== $this->masterRequestHash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We usually don't split these long if()
conditions, so this should be one line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -45,6 +66,15 @@ public function __invoke(array $record) | |||
*/ | |||
public function getLogs() | |||
{ | |||
if (func_num_args() === 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Symfony code we use Yoda conditions, so this should be 1 === func_num_args ()
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
if (func_num_args() === 1) { | ||
$requestHash = func_get_arg(0); | ||
if (isset($this->recordsRequest[$requestHash]['errorCount']) | ||
&& $requestHash !== $this->masterRequestHash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same with this if()
condition
I guess that profile should for the master request get all logs |
…1598) - added local cache for a logger collector - overwrite symfony`s data_collector.logger class - added tests
c0a300d
to
c02cedd
Compare
@vtsykun same to me. OK to finish this PR then? |
ping @vtsykun |
Hi @nicolas-grekas, this done, please review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice 👍
@@ -25,6 +25,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte | |||
{ | |||
private $logger; | |||
private $containerPathPrefix; | |||
private $splRequestHash; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$currentRequestHash
? (compared to $masterRequestHash above)
} | ||
|
||
/** | ||
* @param GetResponseEvent $event |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be removed i guess
return; | ||
} | ||
|
||
$this->masterRequestHash = spl_object_hash($event->getRequest()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might store the current request hash as well (to use if not passed on the calling side)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is passing it on the calling side really needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thinking the better move it on LoggerDataCollector
side.
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; | ||
|
||
class DebugProcessor implements DebugLoggerInterface | ||
{ | ||
private $records = array(); | ||
private $errorCount = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about array for both? in favor of array_column
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
almost
if (null !== $this->requestStack && $this->requestStack->getMasterRequest() !== $request) { | ||
$this->currentRequestHash = spl_object_hash($request); | ||
} else { | ||
//gets all logs for the master request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space missing + gets > get
} | ||
|
||
if (1 === func_num_args()) { | ||
$requestHash = func_get_arg(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
collector might pass null
here, should we be explicit? the key would be ""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@@ -27,7 +27,7 @@ class Logger extends BaseLogger implements DebugLoggerInterface | |||
public function getLogs() | |||
{ | |||
if ($logger = $this->getDebugLogger()) { | |||
return $logger->getLogs(); | |||
return call_user_func_array(array($logger, 'getLogs'), func_get_args()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be replace with: $logger->getLogs(...func_get_args());
which is easier to read and faster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not php 5.5 compat
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it not supported on php < 5.6 http://sandbox.onlinephpfunctions.com/code/3ba4ee65a58af1267040434818d752f26bc885a1
@@ -39,7 +39,7 @@ public function getLogs() | |||
public function countErrors() | |||
{ | |||
if ($logger = $this->getDebugLogger()) { | |||
return $logger->countErrors(); | |||
return call_user_func_array(array($logger, 'countErrors'), func_get_args()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
From #24275; do events have this same issue? |
4684570
to
1ec0653
Compare
1ec0653
to
840525d
Compare
@vtsykun thank you for this PR, and sorry I didn't manage to review it earlier. I just rebased it on top of the latest version of branch 3.4, with a few minor changes. The code looks to good to me. It sill misses a few unit tests. Would you be up for adding them? If yes, don't forget to fetch+rebase --hard on your remote |
840525d
to
a124770
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I just pushed some unit tests)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like something for 4.1/master intead
It could go on 4.1 for sure. The only thing that made me keep it for 3.4 is that the reported behavior affects 3.4 (sub-requests heavy pages suffer from a significant penalty because of log duplication.) |
a124770
to
d0cb1de
Compare
Rebased on master, ready for 4.1. |
Thank you @vtsykun. |
…fferent sub-requests (vtsykun) This PR was merged into the 4.1-dev branch. Discussion ---------- [HttpKernel] LoggerDataCollector: splitting logs on different sub-requests | Q | A | ------------- | --- | Branch? | 4.1 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | - | Fixed tickets | #23620 | License | MIT | Doc PR | - This PR fixed performance problem in dev mode and prevent logs serialize several times for each sub-request. STR: 1) Install any symfony application v2.8-3.4 2) Create a simple page with 20-50 sub-requests and 5k-10k logs 3) Open page in dev mode **Actual** - debug toolbar not open (404 not found) - sets of logs (in the logger debug panel) for different requests are same - log processing takes about 20-30s - gc also run about 50% of execution time **Expected** - Debug toolbar should be open - As developer, I want to see in logger panel only those logs that are relevant to the given sub-request ### Profile and performance Tested on page with 7k logs and 70 sub-request. Comparison: - v3.3.5 - this patch: https://blackfire.io/profiles/compare/b1d410b3-c4a7-4778-9b6d-514f72193e28/graph - v3.3.5 - patch #23644 https://blackfire.io/profiles/compare/d0715b04-7834-4981-8da2-9f1dcb2ef90c/graph Commits ------- d0cb1de [HttpKernel] LoggerDataCollector: splitting logs on different sub-requests
…0NL) This PR was merged into the 4.1 branch. Discussion ---------- [MonologBridge] Return empty list for unknown requests | Q | A | ------------- | --- | Branch? | 4.1 | Bug fix? | yes | New feature? | no | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #... <!-- #-prefixed issue number(s), if any --> | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> Small continuation of #23659. Currently if the specified request is unknown, you'll get all available requests merged. This fixes it. Commits ------- 69be8e6 [MonologBridge] Return empty list for unknonwn requests
This PR was merged into the 3.4 branch. Discussion ---------- [EventDispatcher] Unwrap wrapped listeners internally | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | partially #24275 | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> I believe what happens is we re-register the listeners on the wrapped dispatcher, so in case of sub request we get those and wrap it again. The profiler seems to confirm this in case of an exception (default 404 here) and thus creates a sub-request. ## Before: (main request) No exception: (OK)  Exception: (KO)  ## After (main request): No exception: same Exception: (OK)  I haven't furhter investigated if we should split events per request as done in #23659 for logs. It seems somewhere we deduplicate events.. so im not sure the profiler actually shows correct data. Commits ------- 448e2e2 [EventDispatcher] Unwrap wrapped listeners internally
This PR was squashed before being merged into the 4.3-dev branch (closes #29312). Discussion ---------- [EventDispatcher] Split events across requests | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | #24275 | License | MIT | Doc PR | symfony/symfony-docs#... <!-- required for new features --> Split events per request, as currently a profiled sub-request includes all events. Follows same approach how logs are split in #23659. Commits ------- c3477ba [EventDispatcher] Split events across requests
This PR fixed performance problem in dev mode and prevent logs serialize several times for each sub-request.
STR:
Actual
Expected
Profile and performance
Tested on page with 7k logs and 70 sub-request.
Comparison: