Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
move some profiler commands to core
Signed-off-by: Robin Appelman <[email protected]>
  • Loading branch information
icewind1991 committed Sep 17, 2023
commit 5bcc1356167eb28560fa1204d5578bc976e6b97b
34 changes: 34 additions & 0 deletions core/Command/Profiler/Clear.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

// SPDX-FileCopyrightText: 2022 Robin Appelman <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OC\Core\Command\Profiler;

use OC\Core\Command\Base;
use OCP\Profiler\IProfiler;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class Clear extends Base {
private IProfiler $profiler;

public function __construct(IProfiler $profiler) {
parent::__construct();
$this->profiler = $profiler;
}

protected function configure() {
$this
->setName('profiler:clear')
->setDescription('Remove all saved profiles');
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$this->profiler->clear();

return 0;
}
}
33 changes: 33 additions & 0 deletions core/Command/Profiler/Disable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

// SPDX-FileCopyrightText: 2022 Robin Appelman <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OC\Core\Command\Profiler;

use OCP\IConfig;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class Disable extends Command {
private IConfig $config;

public function __construct(IConfig $config) {
parent::__construct();
$this->config = $config;
}

protected function configure() {
$this
->setName('profiler:disable')
->setDescription('Disable profiling');
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$this->config->setSystemValue('profiler', false);
return 0;
}
}
33 changes: 33 additions & 0 deletions core/Command/Profiler/Enable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

// SPDX-FileCopyrightText: 2022 Robin Appelman <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OC\Core\Command\Profiler;

use OCP\IConfig;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class Enable extends Command {
private IConfig $config;

public function __construct(IConfig $config) {
parent::__construct();
$this->config = $config;
}

protected function configure() {
$this
->setName('profiler:enable')
->setDescription('Enable profiling');
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$this->config->setSystemValue('profiler', true);
return 0;
}
}
50 changes: 50 additions & 0 deletions core/Command/Profiler/Export.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

// SPDX-FileCopyrightText: 2022 Robin Appelman <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OC\Core\Command\Profiler;

use OC\Core\Command\Base;
use OCP\Profiler\IProfiler;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Export extends Base {
private IProfiler $profiler;

public function __construct(IProfiler $profiler) {
parent::__construct();
$this->profiler = $profiler;
}

protected function configure() {
$this
->setName('profiler:export')
->setDescription('Export captured profiles as json')
->addOption('limit', null, InputOption::VALUE_REQUIRED, 'Maximum number of profiles to return')
->addOption('url', null, InputOption::VALUE_REQUIRED, 'Url to list profiles for')
->addOption('since', null, InputOption::VALUE_REQUIRED, 'Minimum date for listed profiles, as unix timestamp')
->addOption('before', null, InputOption::VALUE_REQUIRED, 'Maximum date for listed profiles, as unix timestamp');
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$since = $input->getOption('since') ? (int)$input->getOption('since') : null;
$before = $input->getOption('before') ? (int)$input->getOption('before') : null;
$limit = $input->getOption('limit') ? (int)$input->getOption('limit') : 1000;
$url = $input->getOption('url');

$profiles = $this->profiler->find($url, $limit, null, $since, $before);
$profiles = array_reverse($profiles);
$profiles = array_map(function (array $profile) {
return $this->profiler->loadProfile($profile['token']);
}, $profiles);

$output->writeln(json_encode($profiles));

return 0;
}
}
81 changes: 81 additions & 0 deletions core/Command/Profiler/ListCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

// SPDX-FileCopyrightText: 2022 Robin Appelman <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OC\Core\Command\Profiler;

use OC\Core\Command\Base;
use OC\Profiler\DataCollector\DbDataCollector;
use OC\Profiler\DataCollector\MemoryDataCollector;
use OCP\Profiler\IProfiler;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class ListCommand extends Base {
private IProfiler $profiler;

public function __construct(IProfiler $profiler) {
parent::__construct();
$this->profiler = $profiler;
}

protected function configure() {
parent::configure();
$this
->setName('profiler:list')
->setDescription('List captured profiles')
->addOption('limit', null, InputOption::VALUE_REQUIRED, 'Maximum number of profiles to return')
->addOption('url', null, InputOption::VALUE_REQUIRED, 'Url to list profiles for')
->addOption('since', null, InputOption::VALUE_REQUIRED, 'Minimum date for listed profiles, as unix timestamp')
->addOption('before', null, InputOption::VALUE_REQUIRED, 'Maximum date for listed profiles, as unix timestamp');
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$since = $input->getOption('since') ? (int)$input->getOption('since') : null;
$before = $input->getOption('before') ? (int)$input->getOption('before') : null;
$limit = $input->getOption('limit') ? (int)$input->getOption('limit') : 1000;
$url = $input->getOption('url');

$profiles = $this->profiler->find($url, $limit, null, $since, $before);
$profiles = array_reverse($profiles);
foreach ($profiles as &$profile) {
$info = $this->profiler->loadProfile($profile['token']);

/** @var DbDataCollector $dbCollector */
$dbCollector = $info->getCollector('db');
/** @var MemoryDataCollector $memoryCollector */
$memoryCollector = $info->getCollector('memory');

if ($dbCollector) {
$profile['queries'] = count($dbCollector->getQueries());
} else {
$profile['queries'] = '--';
}
if ($memoryCollector) {
$profile['memory'] = $memoryCollector->getMemory();
} else {
$profile['memory'] = '--';
}
}

$outputType = $input->getOption('output');

if ($profiles) {
if ($outputType === self::OUTPUT_FORMAT_JSON || $outputType === self::OUTPUT_FORMAT_JSON_PRETTY) {
$this->writeArrayInOutputFormat($input, $output, $profiles);
} else {
$table = new Table($output);
$table->setHeaders(array_keys($profiles[0]));
$table->setRows($profiles);
$table->render();
}
}

return 0;
}
}
6 changes: 6 additions & 0 deletions core/register_command.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@
$application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager()));
$application->add(\OC::$server->get(\OC\Core\Command\Security\BruteforceAttempts::class));
$application->add(\OC::$server->get(\OC\Core\Command\Security\BruteforceResetAttempts::class));

$application->add(\OC::$server->get(OC\Core\Command\Profiler\Clear::class));
$application->add(\OC::$server->get(OC\Core\Command\Profiler\Disable::class));
$application->add(\OC::$server->get(OC\Core\Command\Profiler\Enable::class));
$application->add(\OC::$server->get(OC\Core\Command\Profiler\Export::class));
$application->add(\OC::$server->get(OC\Core\Command\Profiler\ListCommand::class));
} else {
$application->add(\OC::$server->get(\OC\Core\Command\Maintenance\Install::class));
}