Skip to content

Commit fc2005d

Browse files
committed
Add a built-in profiler inside Nextcloud
The webui is provided by a seperate application named profiler Signed-off-by: Carl Schwan <carl@carlschwan.eu>
1 parent cf4c77e commit fc2005d

43 files changed

Lines changed: 1984 additions & 189 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/dav/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@
272272
'OCA\\DAV\\Migration\\Version1016Date20201109085907' => $baseDir . '/../lib/Migration/Version1016Date20201109085907.php',
273273
'OCA\\DAV\\Migration\\Version1017Date20210216083742' => $baseDir . '/../lib/Migration/Version1017Date20210216083742.php',
274274
'OCA\\DAV\\Migration\\Version1018Date20210312100735' => $baseDir . '/../lib/Migration/Version1018Date20210312100735.php',
275+
'OCA\\DAV\\Profiler\\ProfilerPlugin' => $baseDir . '/../lib/Profiler/ProfilerPlugin.php',
275276
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
276277
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
277278
'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php',

apps/dav/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ class ComposerStaticInitDAV
287287
'OCA\\DAV\\Migration\\Version1016Date20201109085907' => __DIR__ . '/..' . '/../lib/Migration/Version1016Date20201109085907.php',
288288
'OCA\\DAV\\Migration\\Version1017Date20210216083742' => __DIR__ . '/..' . '/../lib/Migration/Version1017Date20210216083742.php',
289289
'OCA\\DAV\\Migration\\Version1018Date20210312100735' => __DIR__ . '/..' . '/../lib/Migration/Version1018Date20210312100735.php',
290+
'OCA\\DAV\\Profiler\\ProfilerPlugin' => __DIR__ . '/..' . '/../lib/Profiler/ProfilerPlugin.php',
290291
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
291292
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
292293
'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php',
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
/**
3+
* @copyright 2021 Carl Schwan <carl@carlschwan.eu>
4+
*
5+
* @author Carl Schwan <carl@carlschwan.eu>
6+
*
7+
* @license AGPL-3.0-or-later
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
namespace OCA\DAV\Profiler;
25+
26+
use OCP\IRequest;
27+
use Sabre\DAV\Server;
28+
use Sabre\HTTP\RequestInterface;
29+
use Sabre\HTTP\ResponseInterface;
30+
31+
class ProfilerPlugin extends \Sabre\DAV\ServerPlugin {
32+
private IRequest $request;
33+
34+
public function __construct(IRequest $request) {
35+
$this->request = $request;
36+
}
37+
38+
/** @return void */
39+
public function initialize(Server $server) {
40+
$server->on('afterMethod:*', [$this, 'afterMethod']);
41+
}
42+
43+
/** @return void */
44+
public function afterMethod(RequestInterface $request, ResponseInterface $response) {
45+
$response->addHeader('X-Debug-Token', $this->request->getId());
46+
}
47+
}

apps/dav/lib/Server.php

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636

3737
use OCA\DAV\Connector\Sabre\RequestIdHeaderPlugin;
3838
use OCP\Diagnostics\IEventLogger;
39+
use OCP\Profiler\IProfiler;
40+
use OCA\DAV\Profiler\ProfilerPlugin;
41+
use OCP\AppFramework\Http\Response;
3942
use Psr\Log\LoggerInterface;
4043
use OCA\DAV\AppInfo\PluginManager;
4144
use OCA\DAV\CalDAV\BirthdayService;
@@ -78,17 +81,19 @@
7881
use SearchDAV\DAV\SearchPlugin;
7982

8083
class Server {
84+
private IRequest $request;
85+
private string $baseUri;
86+
public Connector\Sabre\Server $server;
87+
private IProfiler $profiler;
88+
89+
public function __construct(IRequest $request, string $baseUri) {
90+
$this->profiler = \OC::$server->get(IProfiler::class);
91+
if ($this->profiler->isEnabled()) {
92+
/** @var IEventLogger $eventLogger */
93+
$eventLogger = \OC::$server->get(IEventLogger::class);
94+
$eventLogger->start('runtime', 'DAV Runtime');
95+
}
8196

82-
/** @var IRequest */
83-
private $request;
84-
85-
/** @var string */
86-
private $baseUri;
87-
88-
/** @var Connector\Sabre\Server */
89-
public $server;
90-
91-
public function __construct(IRequest $request, $baseUri) {
9297
$this->request = $request;
9398
$this->baseUri = $baseUri;
9499
$logger = \OC::$server->getLogger();
@@ -115,6 +120,7 @@ public function __construct(IRequest $request, $baseUri) {
115120
$this->server->httpRequest->setUrl($this->request->getRequestUri());
116121
$this->server->setBaseUri($this->baseUri);
117122

123+
$this->server->addPlugin(new ProfilerPlugin($this->request));
118124
$this->server->addPlugin(new BlockLegacyClientPlugin(\OC::$server->getConfig()));
119125
$this->server->addPlugin(new AnonymousOptionsPlugin());
120126
$authPlugin = new Plugin();
@@ -343,6 +349,11 @@ public function exec() {
343349
$eventLogger->start('dav_server_exec', '');
344350
$this->server->exec();
345351
$eventLogger->end('dav_server_exec');
352+
if ($this->profiler->isEnabled()) {
353+
$eventLogger->end('runtime');
354+
$profile = $this->profiler->collect(\OC::$server->get(IRequest::class), new Response());
355+
$this->profiler->saveProfile($profile);
356+
}
346357
}
347358

348359
private function requestIsForSubtree(array $subTrees): bool {

apps/user_ldap/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
'OCA\\User_LDAP\\ConnectionFactory' => $baseDir . '/../lib/ConnectionFactory.php',
2727
'OCA\\User_LDAP\\Controller\\ConfigAPIController' => $baseDir . '/../lib/Controller/ConfigAPIController.php',
2828
'OCA\\User_LDAP\\Controller\\RenewPasswordController' => $baseDir . '/../lib/Controller/RenewPasswordController.php',
29+
'OCA\\User_LDAP\\DataCollector\\LdapDataCollector' => $baseDir . '/../lib/DataCollector/LdapDataCollector.php',
2930
'OCA\\User_LDAP\\Events\\GroupBackendRegistered' => $baseDir . '/../lib/Events/GroupBackendRegistered.php',
3031
'OCA\\User_LDAP\\Events\\UserBackendRegistered' => $baseDir . '/../lib/Events/UserBackendRegistered.php',
3132
'OCA\\User_LDAP\\Exceptions\\AttributeNotSet' => $baseDir . '/../lib/Exceptions/AttributeNotSet.php',

apps/user_ldap/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class ComposerStaticInitUser_LDAP
4141
'OCA\\User_LDAP\\ConnectionFactory' => __DIR__ . '/..' . '/../lib/ConnectionFactory.php',
4242
'OCA\\User_LDAP\\Controller\\ConfigAPIController' => __DIR__ . '/..' . '/../lib/Controller/ConfigAPIController.php',
4343
'OCA\\User_LDAP\\Controller\\RenewPasswordController' => __DIR__ . '/..' . '/../lib/Controller/RenewPasswordController.php',
44+
'OCA\\User_LDAP\\DataCollector\\LdapDataCollector' => __DIR__ . '/..' . '/../lib/DataCollector/LdapDataCollector.php',
4445
'OCA\\User_LDAP\\Events\\GroupBackendRegistered' => __DIR__ . '/..' . '/../lib/Events/GroupBackendRegistered.php',
4546
'OCA\\User_LDAP\\Events\\UserBackendRegistered' => __DIR__ . '/..' . '/../lib/Events/UserBackendRegistered.php',
4647
'OCA\\User_LDAP\\Exceptions\\AttributeNotSet' => __DIR__ . '/..' . '/../lib/Exceptions/AttributeNotSet.php',
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
/**
3+
* @copyright 2022 Carl Schwan <carl@carlschwan.eu>
4+
*
5+
* @author Carl Schwan <carl@carlschwan.eu>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
namespace OCA\User_LDAP\DataCollector;
25+
26+
use OC\AppFramework\Http\Request;
27+
use OCP\AppFramework\Http\Response;
28+
use OCP\DataCollector\AbstractDataCollector;
29+
30+
class LdapDataCollector extends AbstractDataCollector {
31+
public function startLdapRequest(string $query, array $args): void {
32+
$this->data[] = [
33+
'start' => microtime(true),
34+
'query' => $query,
35+
'args' => $args,
36+
'end' => microtime(true),
37+
];
38+
}
39+
40+
public function stopLastLdapRequest(): void {
41+
$this->data[count($this->data) - 1]['end'] = microtime(true);
42+
}
43+
44+
public function getName(): string {
45+
return 'ldap';
46+
}
47+
48+
public function collect(Request $request, Response $response, \Throwable $exception = null): void {
49+
}
50+
}

apps/user_ldap/lib/LDAP.php

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* @author Robin McCorkell <robin@mccorkell.me.uk>
1515
* @author Roeland Jago Douma <roeland@famdouma.nl>
1616
* @author Roger Szabo <roger.szabo@web.de>
17+
* @author Carl Schwan <carl@carlschwan.eu>
1718
*
1819
* @license AGPL-3.0
1920
*
@@ -32,7 +33,9 @@
3233
*/
3334
namespace OCA\User_LDAP;
3435

36+
use OCP\Profiler\IProfiler;
3537
use OC\ServerNotAvailableException;
38+
use OCA\User_LDAP\DataCollector\LdapDataCollector;
3639
use OCA\User_LDAP\Exceptions\ConstraintViolationException;
3740
use OCA\User_LDAP\PagedResults\IAdapter;
3841
use OCA\User_LDAP\PagedResults\Php73;
@@ -45,9 +48,18 @@ class LDAP implements ILDAPWrapper {
4548
/** @var IAdapter */
4649
protected $pagedResultsAdapter;
4750

51+
private ?LdapDataCollector $dataCollector = null;
52+
4853
public function __construct(string $logFile = '') {
4954
$this->pagedResultsAdapter = new Php73();
5055
$this->logFile = $logFile;
56+
57+
/** @var IProfiler $profiler */
58+
$profiler = \OC::$server->get(IProfiler::class);
59+
if ($profiler->isEnabled()) {
60+
$this->dataCollector = new LdapDataCollector();
61+
$profiler->add($this->dataCollector);
62+
}
5163
}
5264

5365
/**
@@ -295,24 +307,26 @@ protected function invokeLDAPMethod() {
295307
if ($this->isResultFalse($result)) {
296308
$this->postFunctionCall();
297309
}
310+
if ($this->dataCollector !== null) {
311+
$this->dataCollector->stopLastLdapRequest();
312+
}
298313
return $result;
299314
}
300315
return null;
301316
}
302317

303-
/**
304-
* @param string $functionName
305-
* @param array $args
306-
*/
307-
private function preFunctionCall($functionName, $args) {
318+
private function preFunctionCall(string $functionName, array $args): void {
308319
$this->curFunc = $functionName;
309320
$this->curArgs = $args;
310321

322+
if ($this->dataCollector !== null) {
323+
$args = array_map(fn ($item) => (!$this->isResource($item) ? $item : '(resource)'), $this->curArgs);
324+
325+
$this->dataCollector->startLdapRequest($this->curFunc, $args);
326+
}
327+
311328
if ($this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
312-
$args = array_reduce($this->curArgs, static function (array $carry, $item): array {
313-
$carry[] = !is_resource($item) ? $item : '(resource)';
314-
return $carry;
315-
}, []);
329+
$args = array_map(fn ($item) => (!$this->isResource($item) ? $item : '(resource)'), $this->curArgs);
316330
file_put_contents(
317331
$this->logFile,
318332
$this->curFunc . '::' . json_encode($args) . "\n",

build/psalm-baseline.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,6 @@
10231023
</RedundantCondition>
10241024
<TypeDoesNotContainType occurrences="2">
10251025
<code>get_class($res) === 'OpenSSLAsymmetricKey'</code>
1026-
<code>is_object($res)</code>
10271026
</TypeDoesNotContainType>
10281027
</file>
10291028
<file src="apps/encryption/lib/Crypto/EncryptAll.php">
@@ -2638,11 +2637,6 @@
26382637
<code>$default</code>
26392638
</MoreSpecificImplementedParamType>
26402639
</file>
2641-
<file src="lib/private/AppFramework/Utility/SimpleContainer.php">
2642-
<UndefinedMethod occurrences="1">
2643-
<code>getName</code>
2644-
</UndefinedMethod>
2645-
</file>
26462640
<file src="lib/private/Archive/TAR.php">
26472641
<UndefinedDocblockClass occurrences="1">
26482642
<code>$this-&gt;tar-&gt;extractInString($path)</code>

config/config.sample.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,14 @@
962962
*/
963963
'log_rotate_size' => 100 * 1024 * 1024,
964964

965+
/**
966+
* Enable built-in profiler. Helpful when trying to debug performance
967+
* issues.
968+
*
969+
* Note that this has a performance impact and shouldn't be enabled
970+
* on production.
971+
*/
972+
'profiler' => false,
965973

966974
/**
967975
* Alternate Code Locations

0 commit comments

Comments
 (0)