diff --git a/Command/DumpStatsCommand.php b/Command/DumpStatsCommand.php index e94c5e1..1ca768a 100644 --- a/Command/DumpStatsCommand.php +++ b/Command/DumpStatsCommand.php @@ -24,13 +24,16 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use vierbergenlars\AuthserverStatsBundle\Event\StatsEvent; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Helper\Table; class DumpStatsCommand extends Command { protected function configure() { - $this->setName('stats:dump')->addOption('module', 'm', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Modules to fetch statistics for'); + $this->setName('stats:dump') + ->addOption('module', 'm', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Modules to fetch statistics for') + ->addOption('munin', null, InputOption::VALUE_OPTIONAL, 'Output data for consumption by munin', false); } protected function execute(InputInterface $input, OutputInterface $output) @@ -45,7 +48,29 @@ class DumpStatsCommand extends Command $event = new StatsEvent($input->getOption('module')); $eventDispatcher->dispatch(StatsEvent::class, $event); - foreach ($event->getStatistics() as $name => $value) - $output->writeln(sprintf('%s:%s', $name, $value), OutputInterface::OUTPUT_RAW); + if ($input->getOption('munin') !== false) { + foreach ($event->getModules() as $module) { + $output->writeln('multigraph authserver_' . $module, OutputInterface::OUTPUT_RAW); + if ($input->getOption('munin') === 'config') { + $stats = $event->getMuninConfig($module); + $suffix = ' '; + } else { + $stats = $event->getModuleStatistics($module); + $suffix = '.value '; + } + foreach ($stats as $k => $v) { + $output->writeln($k . $suffix . $v, OutputInterface::OUTPUT_RAW); + } + } + } else { + $table = new Table($output); + foreach ($event->getStatistics() as $name => $value) { + $table->addRow([ + $name, + $value + ]); + } + $table->render(); + } } } \ No newline at end of file diff --git a/Event/StatsEvent.php b/Event/StatsEvent.php index fdf26ac..3fd1fe7 100644 --- a/Event/StatsEvent.php +++ b/Event/StatsEvent.php @@ -29,6 +29,8 @@ class StatsEvent extends Event private $stats = []; + private $muninConfig = []; + public function __construct($modules) { $this->modules = $modules; @@ -41,6 +43,16 @@ class StatsEvent extends Event return in_array($module, $this->modules); } + public function setMuninConfig($module, $config) + { + $this->muninConfig[$module] = $config; + } + + public function getMuninConfig($module) + { + return $this->muninConfig[$module]; + } + public function addStatistics(array $statistics) { foreach ($statistics as $statName => $value) { @@ -51,16 +63,35 @@ class StatsEvent extends Event public function addStatistic($name, $value) { - if (isset($this->stats[$name])) + list ($module, $statistic) = explode('.', $name, 2); + if (!isset($this->stats[$module])) + $this->stats[$module] = []; + if (isset($this->stats[$module][$statistic])) throw new \OutOfBoundsException(sprintf('Statistic "%s" already exists and cannot be overwritten.', $name)); - $this->stats[$name] = $value; + $this->stats[$module][$statistic] = $value; return $this; } public function getStatistics() { - return $this->stats; + $stats = []; + foreach ($this->getModules() as $module) { + foreach ($this->getModuleStatistics($module) as $stat => $value) { + $stats[$module . '.' . $stat] = $value; + } + } + return $stats; + } + + public function getModules() + { + return array_keys($this->stats); + } + + public function getModuleStatistics($module) + { + return $this->stats[$module]; } } \ No newline at end of file diff --git a/EventListener/CoreStatsListener.php b/EventListener/CoreStatsListener.php index c136fc1..4eb85dd 100644 --- a/EventListener/CoreStatsListener.php +++ b/EventListener/CoreStatsListener.php @@ -57,6 +57,17 @@ class CoreStatsListener implements EventSubscriberInterface { if (!$event->isEnabled('user')) return; + + $event->setMuninConfig('user', [ + 'graph_title' => 'Authserver users', + 'graph_vlabel' => 'Number of users', + 'graph_category' => 'authserver', + 'enabled.label' => 'Enabled users', + 'enabled.draw' => 'AREA', + 'disabled.label' => 'Disabled users', + 'disabled.draw' => 'AREASTACK' + ]); + $queryBuilder = $this->registry->getRepository(User::class)->createQueryBuilder('u'); /* @var $queryBuilder \Doctrine\ORM\QueryBuilder */ @@ -69,9 +80,9 @@ class CoreStatsListener implements EventSubscriberInterface ]; foreach ($rawStats as $rawStat) { if ($rawStat['enabled']) { - $stats['user.enabled'] += $rawStat['count']; + $stats['user.enabled'] += $rawStat['1']; } else { - $stats['user.disabled'] += $rawStat['count']; + $stats['user.disabled'] += $rawStat['1']; } } @@ -82,6 +93,14 @@ class CoreStatsListener implements EventSubscriberInterface { if (!$event->isEnabled('group')) return; + + $event->setMuninConfig('group', [ + 'graph_title' => 'Authserver groups', + 'graph_vlabel' => 'Number of groups', + 'graph_category' => 'authserver', + 'count.label' => 'Groups', + 'count.draw' => 'AREA' + ]); $queryBuilder = $this->registry->getRepository(Group::class)->createQueryBuilder('g'); /* @var $queryBuilder \Doctrine\ORM\QueryBuilder */ diff --git a/EventListener/LoginStatsListener.php b/EventListener/LoginStatsListener.php index 1f71930..3c44f47 100644 --- a/EventListener/LoginStatsListener.php +++ b/EventListener/LoginStatsListener.php @@ -66,6 +66,18 @@ class LoginStatsListener implements EventSubscriberInterface { if (!$event->isEnabled('login')) return; + + $event->setMuninConfig('login', [ + 'graph_title' => 'Authserver logins', + 'graph_vlabel' => 'Number of logins', + 'graph_category' => 'authserver', + '5min.label' => 'Logins in past 5 minutes', + '1hour.label' => 'Logins in past hour', + '1day.label' => 'Logins in past day', + '1week.label' => 'Logins in past week', + 'total.label' => 'Logins per ${graph_period}', + 'total.type' => 'COUNTER' + ]); $queryBuilder = $this->registry->getRepository(LoginEntry::class)->createQueryBuilder('e'); /* @var $queryBuilder \Doctrine\ORM\QueryBuilder */ @@ -81,5 +93,9 @@ class LoginStatsListener implements EventSubscriberInterface ->setParameter('time', new \DateTime($timeAgo . ' ago')) ->getSingleScalarResult()); } + + $event->addStatistic('login.total', $queryBuilder->resetDQLPart('where') + ->getQuery() + ->getSingleScalarResult()); } } \ No newline at end of file