";
43 |
44 |
45 | my $totalnumber = 0;
46 | my $passnumber = 0;
47 | my $failnumber = 0;
48 | my $jsn;
49 | my $content;
50 | my $browser = WWW::Mechanize->new();
51 | my $donechecks;
52 | my $color = '#33FF00';
53 | my $message;
54 |
55 | if (defined($opts{u}) && defined($opts{p}) ) {
56 | $browser->credentials($opts{u}, $opts{p});
57 | }
58 | if (defined($opts{A})) {
59 | eval {
60 | $browser->get( $opts{A} );
61 | $jsn = $browser->content();
62 | $content = decode_json( $jsn );
63 | };
64 | if ($@) {
65 | print "Symfony Health Unknown - Failed connecting to health page: $opts{A}\n";
66 | exit 3;
67 | }
68 | } else {
69 | my $url = "https://" . $opts{H} . "/monitor/health/run";
70 |
71 | eval {
72 | $browser->get( $url );
73 | $jsn = $browser->content();
74 | $content = decode_json( $jsn );
75 | };
76 | if ($@) {
77 | print "Symfony Health Unknown - Failed connecting to health page for $opts{H}\n";
78 | exit 3;
79 | }
80 | }
81 |
82 | foreach (@{$content->{checks}})
83 | {
84 | $totalnumber += 1;
85 | if ($_->{status}) {
86 | $failnumber += 1;
87 | $color = '#F83838';
88 | } else {
89 | $passnumber += 1;
90 | $color = '#33FF00';
91 | }
92 | $donechecks .= "
| | | $_->{checkName} | $_->{message} |
";
93 | }
94 |
95 | if ($failnumber > 0) {
96 | $message = "Symfony Heath Critical - ${totalnumber} checks ran ${failnumber} failed ${java}";
97 | } else {
98 | $message = "Symfony Heath OK - ${totalnumber} checks ran ${passnumber} ok ${java}";
99 | }
100 |
101 | $message .= $htmldivide;
102 |
103 | $message .= $donechecks;
104 |
105 | $message .= $htmlend;
106 |
107 | print "$message\n";
108 |
109 | if ($failnumber < $opts{w} or $failnumber == 0 ) {
110 | exit 0;
111 | }
112 |
113 | if ($failnumber >= $opts{c}) {
114 | exit 2;
115 | }
116 | exit 1;
117 |
--------------------------------------------------------------------------------
/Command/ListChecksCommand.php:
--------------------------------------------------------------------------------
1 | runnerManager = $runnerManager;
20 | $this->runner = $runner;
21 |
22 | parent::__construct($name);
23 | }
24 |
25 | protected function configure(): void
26 | {
27 | $this
28 | ->setName('monitor:list')
29 | ->setDescription('Lists Health Checks')
30 | ->addOption('all', 'a', InputOption::VALUE_NONE, 'Lists Health Checks of all groups')
31 | ->addOption('reporters', 'r', InputOption::VALUE_NONE, 'List registered additional reporters')
32 | ->addOption('group', 'g', InputOption::VALUE_REQUIRED, 'List checks for given group')
33 | ->addOption('groups', 'G', InputOption::VALUE_NONE, 'List all registered groups')
34 | ;
35 | }
36 |
37 | protected function execute(InputInterface $input, OutputInterface $output): int
38 | {
39 | switch (true) {
40 | case $input->getOption('reporters'):
41 | $this->listReporters($output);
42 | break;
43 | case $input->getOption('all'):
44 | $this->listAllChecks($output);
45 | break;
46 | case $input->getOption('groups'):
47 | $this->listGroups($output);
48 | break;
49 | default:
50 | $this->listChecks($input, $output);
51 | break;
52 | }
53 |
54 | return 0;
55 | }
56 |
57 | protected function listChecks(InputInterface $input, OutputInterface $output): void
58 | {
59 | $group = $input->getOption('group');
60 |
61 | $runner = $this->runnerManager->getRunner($group);
62 |
63 | if (null === $runner) {
64 | $output->writeln('
No such group.');
65 |
66 | return;
67 | }
68 |
69 | $this->doListChecks($output, $runner);
70 | }
71 |
72 | protected function listAllChecks(OutputInterface $output): void
73 | {
74 | foreach ($this->runnerManager->getRunners() as $group => $runner) {
75 | $output->writeln(sprintf('
%s>', $group));
76 |
77 | $this->doListChecks($output, $runner);
78 | }
79 | }
80 |
81 | protected function listReporters(OutputInterface $output): void
82 | {
83 | $reporters = $this->runner->getAdditionalReporters();
84 | if (0 === count($reporters)) {
85 | $output->writeln('No additional reporters configured.');
86 | }
87 |
88 | foreach (array_keys($reporters) as $reporter) {
89 | $output->writeln($reporter);
90 | }
91 | }
92 |
93 | protected function listGroups(OutputInterface $output): void
94 | {
95 | foreach ($this->runnerManager->getGroups() as $group) {
96 | $output->writeln($group);
97 | }
98 | }
99 |
100 | private function doListChecks(OutputInterface $output, Runner $runner): void
101 | {
102 | $checks = $runner->getChecks();
103 |
104 | if (0 === count($checks)) {
105 | $output->writeln('No checks configured.');
106 | }
107 |
108 | foreach ($runner->getChecks() as $alias => $check) {
109 | $output->writeln(sprintf('%s %s', $alias, $check->getLabel()));
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contribution Guidelines
2 | =======================
3 |
4 | First of all, each single contribution is appreciated, whether a typo fix,
5 | improved documentation, a fixed bug or a whole new feature.
6 |
7 | ## Feature request
8 |
9 | If you think a feature is missing, please report it or implement it. If you report it, describe the more
10 | precisely what you would like to see implemented. It would be nice if you can do
11 | some search before submitting it and link the resources to your description.
12 |
13 | ## Bug report
14 |
15 | If you think you have detected a bug or a doc issue, please report it (open [issue][issue]) or even better fix it. If you report it,
16 | please be the more precise possible. Here a little list of required information:
17 |
18 | * Symfony-standard fork which reproduces the bug.
19 | * Precise description of the bug.
20 | * Symfony version used.
21 | * Bundle version used.
22 |
23 | ## Bug fix
24 |
25 | Fork the repository, clone it and create a new branch with the following commands:
26 |
27 | ``` bash
28 | $ git clone git@github.com:liip/LiipMonitorBundle.git
29 | $ git checkout -b bug-fix-description
30 | ```
31 |
32 | Then, install the dependencies through [Composer][composer]
33 |
34 | ``` bash
35 | $ composer install
36 | ```
37 |
38 | When you're on the new branch with the dependencies, code as much as you want and when the fix is ready,
39 | you will need to add tests and update the documentation. Everything is tested with
40 | [PHPUnit][php-unit], documentation formatted with markdown under the `Resources/doc` directory.
41 |
42 | To run tests, use the following command:
43 |
44 | ``` bash
45 | $ phpunit
46 | ```
47 |
48 | ## Making your changes
49 |
50 | 1. Fork the repository on GitHub
51 | 2. Pull requests must be sent from a new hotfix/feature branch, not from `master`.
52 | 3. Make your modifications, coding standard for the project is [PSR-2][PSR-2]
53 | 4. Commit small logical changes, each with a descriptive commit message.
54 | Please don't mix unrelated changes in a single commit.
55 |
56 | ## Commit messages
57 |
58 | Please format your commit messages as follows:
59 |
60 | Short summary of the change (up to 50 characters)
61 |
62 | Optionally add a more extensive description of your change after a
63 | blank line. Wrap the lines in this and the following paragraphs after
64 | 72 characters.
65 |
66 | ## Submitting your changes
67 |
68 | 1. Push your changes to a topic branch in your fork of the repository.
69 | 2. [Submit a pull request][pr] to the original repository.
70 | Describe your changes as short as possible, but as detailed as needed for
71 | others to get an overview of your modifications.
72 | 3. If you have reworked you patch, please squash all your commits in a single one with the following commands (here, we
73 | will assume you would like to squash 3 commits in a single one):
74 |
75 | ``` bash
76 | $ git rebase -i HEAD~3
77 | ```
78 | 4. If your branch conflicts with the master branch, you will need to rebase and repush it with the following commands:
79 |
80 | ``` bash
81 | $ git remote add upstream git@github.com:liip/LiipMonitorBundle.git
82 | $ git pull --rebase upstream master
83 | $ git push origin bug-fix-description -f
84 | ```
85 | ## Further information
86 |
87 | * [General GitHub documentation][gh-help]
88 | * [GitHub pull request documentation][gh-pr]
89 | * [Symfony contribution guidelines][sf-gl]
90 |
91 |
92 | [php-unit]: http://phpunit.de/
93 | [composer]: https://getcomposer.org/
94 | [gh-help]: https://help.github.com
95 | [gh-pr]: https://help.github.com/send-pull-requests
96 | [issue]: https://github.com/liip/LiipMonitorBundle/issues/new
97 | [pr]: https://github.com/liip/LiipMonitorBundle/pull/new
98 | [PSR-2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
99 | [sf-gl]: http://symfony.com/doc/current/contributing/index.html
100 |
--------------------------------------------------------------------------------
/DependencyInjection/DoctrineMigrations/V3MigrationsLoader.php:
--------------------------------------------------------------------------------
1 | getConfigurationLoaderClass($container, $filename);
30 | $filenameHash = md5($filename);
31 | $configurationServiceId = 'liip_monitor.check.doctrine_migrations.configuration.'.$filenameHash;
32 | if (!$container->has($configurationServiceId)) {
33 | $container->register($configurationServiceId, $configurationClass)
34 | ->setPublic(false)
35 | ->setArguments([$filename]);
36 | }
37 |
38 | $connectionLoaderId = 'liip_monitor.check.doctrine_migrations.connection_loader.'.$connectionName;
39 | if (!$container->has($connectionLoaderId)) {
40 | $container->register($connectionLoaderId, ExistingConnection::class)
41 | ->setPublic(false)
42 | ->setArguments([new Reference(sprintf('doctrine.dbal.%s_connection', $connectionName))]);
43 | }
44 |
45 | $dependencyFactoryId = sprintf(
46 | 'liip_monitor.check.doctrine_migrations.dependency_factory.%s.%s',
47 | $connectionName,
48 | $filenameHash
49 | );
50 | if (!$container->has($dependencyFactoryId)) {
51 | $container->register($dependencyFactoryId, DependencyFactory::class)
52 | ->setFactory([DependencyFactory::class, 'fromConnection'])
53 | ->setPublic(false)
54 | ->setArguments([new Reference($configurationServiceId), new Reference($connectionLoaderId)]);
55 | }
56 |
57 | $container->setAlias($serviceId, new Alias($dependencyFactoryId, true));
58 |
59 | return;
60 | }
61 |
62 | $container->setAlias($serviceId, new Alias('doctrine.migrations.dependency_factory', true));
63 | }
64 |
65 | /**
66 | * Creates in-memory migration configuration for setting up container service.
67 | *
68 | * @param ContainerBuilder $container The container
69 | * @param string $filename Migrations configuration file
70 | *
71 | * @return string FQCN of configuration class loader
72 | */
73 | private function getConfigurationLoaderClass(ContainerBuilder $container, string $filename): string
74 | {
75 | // Available options are located under Doctrine\Migrations\Configuration\Migration namespace
76 | $map = [
77 | 'xml' => XmlFile::class,
78 | 'yaml' => YamlFile::class,
79 | 'yml' => YamlFile::class,
80 | 'php' => PhpFile::class,
81 | 'json' => JsonFile::class,
82 | ];
83 |
84 | $filename = $container->getParameterBag()->resolveValue($filename);
85 | $info = pathinfo($filename);
86 |
87 | $extension = $info['extension'] ?? '';
88 | if (empty($map[$extension])) {
89 | throw new \InvalidArgumentException(sprintf('Config file type "%s" is not supported', $extension));
90 | }
91 |
92 | return $map[$info['extension']];
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Command/HealthCheckCommand.php:
--------------------------------------------------------------------------------
1 | rawReporter = $rawReporter;
23 | $this->reporter = $reporter;
24 | $this->runnerManager = $runnerManager;
25 |
26 | parent::__construct($name);
27 | }
28 |
29 | protected function configure(): void
30 | {
31 | $this
32 | ->setName('monitor:health')
33 | ->setDescription('Runs Health Checks')
34 | ->addArgument(
35 | 'checkName',
36 | InputArgument::OPTIONAL,
37 | 'The name of the service to be used to perform the health check.'
38 | )
39 | ->addOption(
40 | 'reporter',
41 | null,
42 | InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
43 | 'Additional reporters to run.'
44 | )
45 | ->addOption('nagios', null, InputOption::VALUE_NONE, 'Suitable for using as a nagios NRPE command.')
46 | ->addOption(
47 | 'group',
48 | 'g',
49 | InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
50 | 'Run Health Checks for given group'
51 | )
52 | ->addOption('all', 'a', InputOption::VALUE_NONE, 'Run Health Checks of all groups')
53 | ;
54 | }
55 |
56 | protected function execute(InputInterface $input, OutputInterface $output): int
57 | {
58 | $failureCount = 0;
59 |
60 | $groups = $input->getOption('group') ?: [null];
61 | $allGroups = $input->getOption('all');
62 | $checkName = $input->getArgument('checkName');
63 | $nagios = $input->getOption('nagios');
64 | $additionalReporters = $input->getOption('reporter');
65 |
66 | if ($nagios) {
67 | $reporter = $this->rawReporter;
68 | } else {
69 | $reporter = $this->reporter;
70 | }
71 |
72 | $reporter->setOutput($output);
73 |
74 | if ($allGroups) {
75 | $groups = $this->runnerManager->getGroups();
76 | }
77 |
78 | foreach ($groups as $group) {
79 | if (count($groups) > 1 || $allGroups) {
80 | $output->writeln(sprintf('%s>', $group));
81 | }
82 |
83 | $runner = $this->runnerManager->getRunner($group);
84 |
85 | if (null === $runner) {
86 | $output->writeln('No such group.');
87 |
88 | return 1;
89 | }
90 |
91 | $runner->addReporter($reporter);
92 | $runner->useAdditionalReporters($additionalReporters);
93 |
94 | if (0 === count($runner->getChecks())) {
95 | $output->writeln('No checks configured.');
96 | }
97 |
98 | $results = $runner->run($checkName);
99 |
100 | if ($nagios) {
101 | if ($results->getUnknownCount()) {
102 | return 3;
103 | }
104 | if ($results->getFailureCount()) {
105 | return 2;
106 | }
107 | if ($results->getWarningCount()) {
108 | return 1;
109 | }
110 | }
111 |
112 | $failureCount += $results->getFailureCount();
113 | }
114 |
115 | return $failureCount > 0 ? 1 : 0;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/Check/SymfonyVersion.php:
--------------------------------------------------------------------------------
1 |
17 | * @author Kevin Bond
18 | */
19 | class SymfonyVersion implements CheckInterface
20 | {
21 | public const PACKAGIST_URL = 'https://packagist.org/packages/symfony/symfony.json';
22 | public const VERSION_CHECK_URL = 'https://symfony.com/releases/%s.json';
23 |
24 | /**
25 | * @return ResultInterface
26 | */
27 | public function check()
28 | {
29 | $currentBranch = Kernel::MAJOR_VERSION.'.'.Kernel::MINOR_VERSION;
30 |
31 | // use symfony.com version checker to see if current branch is still maintained
32 | $response = $this->getResponseAndDecode(sprintf(self::VERSION_CHECK_URL, $currentBranch));
33 |
34 | if (!isset($response['eol']) || !isset($response['is_eoled'])) {
35 | throw new \Exception('Invalid response from Symfony version checker.');
36 | }
37 |
38 | $endOfLife = \DateTime::createFromFormat('m/Y', $response['eol'])->format('F, Y');
39 |
40 | if (true === $response['is_eoled']) {
41 | return new Failure(sprintf('Symfony branch "%s" reached it\'s end of life in %s.', $currentBranch, $endOfLife));
42 | }
43 |
44 | $currentVersion = Kernel::VERSION;
45 | $latestRelease = $this->getLatestVersion($currentBranch); // eg. 2.0.12
46 |
47 | if (version_compare($currentVersion, $latestRelease) < 0) {
48 | return new Warning(sprintf('There is a new release - update to %s from %s.', $latestRelease, $currentVersion));
49 | }
50 |
51 | return new Success(sprintf('Your current Symfony branch reaches it\'s end of life in %s.', $endOfLife));
52 | }
53 |
54 | /**
55 | * @return string
56 | */
57 | public function getLabel()
58 | {
59 | return 'Symfony version';
60 | }
61 |
62 | /**
63 | * @param string $branch
64 | *
65 | * @throws \Exception
66 | */
67 | private function getLatestVersion($branch): string
68 | {
69 | $response = $this->getResponseAndDecode(self::PACKAGIST_URL);
70 |
71 | if (!isset($response['package']['versions'])) {
72 | throw new \Exception('Invalid response from packagist.');
73 | }
74 |
75 | $branch = 'v'.$branch;
76 |
77 | // filter out branches and versions without current minor version
78 | $versions = array_filter(
79 | $response['package']['versions'],
80 | function ($value) use ($branch) {
81 | $value = $value['version'];
82 |
83 | if (stripos($value, 'PR') || stripos($value, 'RC') && stripos($value, 'BETA')) {
84 | return false;
85 | }
86 |
87 | return 0 === strpos($value, $branch);
88 | }
89 | );
90 |
91 | // just get versions
92 | $versions = array_keys($versions);
93 |
94 | // sort tags
95 | usort($versions, 'version_compare');
96 |
97 | // reverse to ensure latest is first
98 | $versions = array_reverse($versions);
99 |
100 | return str_replace('v', '', $versions[0]);
101 | }
102 |
103 | /**
104 | * @param string $url
105 | *
106 | * @throws \Exception
107 | */
108 | private function getResponseAndDecode($url): array
109 | {
110 | if (class_exists(HttpClient::class)) {
111 | return HttpClient::create()->request('GET', $url)->toArray();
112 | }
113 |
114 | $opts = [
115 | 'http' => [
116 | 'method' => 'GET',
117 | 'header' => "User-Agent: LiipMonitorBundle\r\n",
118 | ],
119 | ];
120 |
121 | $array = json_decode(file_get_contents($url, false, stream_context_create($opts)), true);
122 |
123 | if (empty($array)) {
124 | throw new \Exception(sprintf('Invalid response from "%s".', $url));
125 | }
126 |
127 | return $array;
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/Tests/Helper/RunnerManagerTest.php:
--------------------------------------------------------------------------------
1 | container
36 | ->expects($this->any())
37 | ->method('getParameter')
38 | ->with('liip_monitor.default_group')
39 | ->willReturn('default');
40 |
41 | $this->container
42 | ->expects($this->any())
43 | ->method('has')
44 | ->with('liip_monitor.runner_'.($group ?: 'default'))
45 | ->willReturn(true);
46 |
47 | $expectedResult = $this->getMockBuilder('Liip\MonitorBundle\Runner')->getMock();
48 |
49 | $this->container
50 | ->expects($this->any())
51 | ->method('get')
52 | ->with('liip_monitor.runner_'.($group ?: 'default'))
53 | ->willReturn($expectedResult);
54 |
55 | $result = $this->runnerManager->getRunner($group);
56 |
57 | $this->assertSame($expectedResult, $result);
58 | }
59 |
60 | public function testGetRunnerReturnsNull(): void
61 | {
62 | $this->container
63 | ->expects($this->any())
64 | ->method('has')
65 | ->with('liip_monitor.runner_testgroup')
66 | ->willReturn(false);
67 |
68 | $result = $this->runnerManager->getRunner('testgroup');
69 |
70 | $this->assertNull($result);
71 | }
72 |
73 | public function testGetRunners(): void
74 | {
75 | $this->container
76 | ->expects($this->any())
77 | ->method('getParameter')
78 | ->with('liip_monitor.runners')
79 | ->willReturn(['liip_monitor.runner_group_1', 'liip_monitor.runner_group_2']);
80 |
81 | $runnerMockBuilder = $this->getMockBuilder('Liip\MonitorBundle\Runner');
82 | $runner1 = $runnerMockBuilder->getMock();
83 | $runner2 = $runnerMockBuilder->getMock();
84 | $this->container
85 | ->expects($this->exactly(2))
86 | ->method('get')
87 | ->withConsecutive(
88 | ['liip_monitor.runner_group_1'],
89 | ['liip_monitor.runner_group_2']
90 | )
91 | ->willReturnOnConsecutiveCalls($runner1, $runner2);
92 |
93 | $result = $this->runnerManager->getRunners();
94 |
95 | $this->assertTrue(is_array($result));
96 | $this->assertCount(2, $result);
97 | $this->assertArrayHasKey('group_1', $result);
98 | $this->assertArrayHasKey('group_2', $result);
99 | $this->assertSame($runner1, $result['group_1']);
100 | $this->assertSame($runner2, $result['group_2']);
101 | }
102 |
103 | public function testGetGroups(): void
104 | {
105 | $this->container
106 | ->expects($this->any())
107 | ->method('getParameter')
108 | ->with('liip_monitor.runners')
109 | ->willReturn(['liip_monitor.runner_group_1', 'liip_monitor.runner_group_2']);
110 |
111 | $result = $this->runnerManager->getGroups();
112 |
113 | $this->assertTrue(is_array($result));
114 | $this->assertCount(2, $result);
115 | $this->assertContains('group_1', $result);
116 | $this->assertContains('group_2', $result);
117 | }
118 |
119 | public function testGetDefaultGroup(): void
120 | {
121 | $expectedResult = 'default';
122 |
123 | $this->container
124 | ->expects($this->any())
125 | ->method('getParameter')
126 | ->with('liip_monitor.default_group')
127 | ->willReturn($expectedResult);
128 |
129 | $result = $this->runnerManager->getDefaultGroup();
130 |
131 | $this->assertEquals($expectedResult, $result);
132 | }
133 |
134 | protected function setUp(): void
135 | {
136 | $this->container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock();
137 |
138 | $this->runnerManager = new RunnerManager($this->container);
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/Controller/HealthCheckController.php:
--------------------------------------------------------------------------------
1 | runnerManager = $runnerManager;
23 | $this->pathHelper = $pathHelper;
24 | $this->template = $template;
25 | $this->failureStatusCode = $failureStatusCode;
26 | }
27 |
28 | public function indexAction(Request $request): Response
29 | {
30 | $group = $this->getGroup($request);
31 |
32 | $urls = $this->pathHelper->getRoutesJs([
33 | 'liip_monitor_run_all_checks' => ['group' => $group],
34 | 'liip_monitor_run_single_check' => ['checkId' => 'replaceme', 'group' => $group],
35 | ]);
36 |
37 | $css = $this->pathHelper->getStyleTags([
38 | 'bundles/liipmonitor/css/bootstrap/css/bootstrap.min.css',
39 | 'bundles/liipmonitor/css/style.css',
40 | ]);
41 |
42 | $javascript = $this->pathHelper->getScriptTags([
43 | 'bundles/liipmonitor/javascript/jquery-1.7.1.min.js',
44 | 'bundles/liipmonitor/javascript/ember-0.9.5.min.js',
45 | 'bundles/liipmonitor/javascript/app.js',
46 | ]);
47 |
48 | // this is a hack to make the bundle template agnostic.
49 | // URL generation for Assets and Routes is still handled by the framework.
50 | ob_start();
51 | include $this->template;
52 | $content = ob_get_clean();
53 |
54 | return new Response($content, 200, ['Content-Type' => 'text/html']);
55 | }
56 |
57 | public function listAction(Request $request): JsonResponse
58 | {
59 | $ret = [];
60 |
61 | $runner = $this->getRunner($request);
62 |
63 | foreach ($runner->getChecks() as $alias => $check) {
64 | $ret[] = $alias;
65 | }
66 |
67 | return new JsonResponse($ret);
68 | }
69 |
70 | public function listAllAction(): JsonResponse
71 | {
72 | $allChecks = [];
73 |
74 | foreach ($this->runnerManager->getRunners() as $group => $runner) {
75 | foreach ($runner->getChecks() as $alias => $check) {
76 | $allChecks[$group][] = $alias;
77 | }
78 | }
79 |
80 | return new JsonResponse($allChecks);
81 | }
82 |
83 | public function listGroupsAction(): JsonResponse
84 | {
85 | $groups = $this->runnerManager->getGroups();
86 |
87 | return new JsonResponse($groups);
88 | }
89 |
90 | public function runAllChecksAction(Request $request): JsonResponse
91 | {
92 | $report = $this->runTests($request);
93 |
94 | return new JsonResponse([
95 | 'checks' => $report->getResults(),
96 | 'globalStatus' => $report->getGlobalStatus(),
97 | ]);
98 | }
99 |
100 | public function runAllChecksHttpStatusAction(Request $request): Response
101 | {
102 | $report = $this->runTests($request);
103 |
104 | return new Response(
105 | '',
106 | ArrayReporter::STATUS_OK === $report->getGlobalStatus() ? 200 : $this->failureStatusCode
107 | );
108 | }
109 |
110 | /**
111 | * @param string $checkId
112 | */
113 | public function runSingleCheckHttpStatusAction($checkId, Request $request): Response
114 | {
115 | $report = $this->runTests($request, $checkId);
116 |
117 | return new Response(
118 | '',
119 | ArrayReporter::STATUS_OK === $report->getGlobalStatus() ? 200 : $this->failureStatusCode
120 | );
121 | }
122 |
123 | /**
124 | * @param string $checkId
125 | */
126 | public function runSingleCheckAction($checkId, Request $request): JsonResponse
127 | {
128 | $results = $this->runTests($request, $checkId)->getResults();
129 |
130 | return new JsonResponse($results[0]);
131 | }
132 |
133 | /**
134 | * @param string|null $checkId
135 | */
136 | protected function runTests(Request $request, $checkId = null): ArrayReporter
137 | {
138 | $reporters = $request->query->all('reporters') ?? [];
139 |
140 | if (!is_array($reporters)) {
141 | $reporters = [$reporters];
142 | }
143 |
144 | $reporter = new ArrayReporter();
145 |
146 | $runner = $this->getRunner($request);
147 |
148 | $runner->addReporter($reporter);
149 | $runner->useAdditionalReporters($reporters);
150 | $runner->run($checkId);
151 |
152 | return $reporter;
153 | }
154 |
155 | /**
156 | * @throws \Exception
157 | */
158 | private function getRunner(Request $request): Runner
159 | {
160 | $group = $this->getGroup($request);
161 |
162 | $runner = $this->runnerManager->getRunner($group);
163 |
164 | if ($runner) {
165 | return $runner;
166 | }
167 |
168 | throw new \RuntimeException(sprintf('Unknown check group "%s"', $group));
169 | }
170 |
171 | private function getGroup(Request $request): string
172 | {
173 | return $request->query->get('group') ?: $this->runnerManager->getDefaultGroup();
174 | }
175 |
176 | public function listReportersAction(): JsonResponse
177 | {
178 | return new JsonResponse($this->runnerManager->getReporters());
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/DependencyInjection/LiipMonitorExtension.php:
--------------------------------------------------------------------------------
1 | migrationsLoader = new DoctrineMigrationsLoader();
28 | }
29 |
30 | /**
31 | * Loads the services based on your application configuration.
32 | */
33 | public function load(array $configs, ContainerBuilder $container): void
34 | {
35 | $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
36 | $loader->load('runner.xml');
37 | $loader->load('helper.xml');
38 | $loader->load('commands.xml');
39 |
40 | $configuration = $this->getConfiguration($configs, $container);
41 | $config = $this->processConfiguration($configuration, $configs);
42 |
43 | if (null === $config['view_template']) {
44 | $config['view_template'] = __DIR__.'/../Resources/views/health/index.html.php';
45 | }
46 |
47 | if ($config['enable_controller']) {
48 | $container->setParameter(sprintf('%s.view_template', $this->getAlias()), $config['view_template']);
49 | $container->setParameter(sprintf('%s.failure_status_code', $this->getAlias()), $config['failure_status_code']);
50 | $loader->load('controller.xml');
51 | }
52 |
53 | $this->configureMailer($container, $config);
54 |
55 | $container->setParameter(sprintf('%s.default_group', $this->getAlias()), $config['default_group']);
56 |
57 | if (empty($config['checks'])) {
58 | return;
59 | }
60 |
61 | $checksLoaded = [];
62 | $containerParams = [];
63 | foreach ($config['checks']['groups'] as $group => $checks) {
64 | if (empty($checks)) {
65 | continue;
66 | }
67 |
68 | foreach ($checks as $check => $values) {
69 | if (empty($values)) {
70 | continue;
71 | }
72 |
73 | $containerParams['groups'][$group][$check] = $values;
74 | $this->setParameters($container, $check, $group, $values);
75 |
76 | if (!in_array($check, $checksLoaded)) {
77 | $loader->load('checks/'.$check.'.xml');
78 | $checksLoaded[] = $check;
79 | }
80 | }
81 | }
82 |
83 | $container->setParameter(sprintf('%s.checks', $this->getAlias()), $containerParams);
84 | $this->configureDoctrineMigrationsCheck($container, $containerParams);
85 | }
86 |
87 | public function process(ContainerBuilder $container): void
88 | {
89 | $this->migrationsLoader->process($container);
90 | }
91 |
92 | /**
93 | * @param string $checkName
94 | * @param string $group
95 | * @param array $values
96 | */
97 | private function setParameters(ContainerBuilder $container, $checkName, $group, $values): void
98 | {
99 | $prefix = sprintf('%s.check.%s', $this->getAlias(), $checkName);
100 | switch ($checkName) {
101 | case 'class_exists':
102 | case 'cpu_performance':
103 | case 'php_extensions':
104 | case 'php_version':
105 | case 'php_flags':
106 | case 'readable_directory':
107 | case 'writable_directory':
108 | case 'process_running':
109 | case 'doctrine_dbal':
110 | case 'doctrine_mongodb':
111 | case 'http_service':
112 | case 'guzzle_http_service':
113 | case 'memcache':
114 | case 'memcached':
115 | case 'redis':
116 | case 'rabbit_mq':
117 | case 'stream_wrapper_exists':
118 | case 'file_ini':
119 | case 'file_json':
120 | case 'file_xml':
121 | case 'file_yaml':
122 | case 'expressions':
123 | case 'pdo_connections':
124 | case 'messenger_transports':
125 | $container->setParameter($prefix.'.'.$group, $values);
126 | break;
127 | case 'symfony_version':
128 | case 'opcache_memory':
129 | break;
130 |
131 | case 'doctrine_migrations':
132 | if (!class_exists(DoctrineMigrationConfiguration::class)) {
133 | throw new \InvalidArgumentException('Please require at least "v2.0.0" of "Doctrine Migrations Library"');
134 | }
135 |
136 | $container->setParameter($prefix.'.'.$group, $values);
137 | break;
138 | }
139 |
140 | if (is_array($values)) {
141 | foreach ($values as $key => $value) {
142 | $container->setParameter($prefix.'.'.$key.'.'.$group, $value);
143 | }
144 | }
145 | }
146 |
147 | /**
148 | * Set up doctrine migration configuration services.
149 | *
150 | * @param ContainerBuilder $container The container
151 | * @param array $params Container params
152 | */
153 | private function configureDoctrineMigrationsCheck(ContainerBuilder $container, array $params): void
154 | {
155 | if (!$container->hasDefinition('liip_monitor.check.doctrine_migrations') || !isset($params['groups'])) {
156 | return;
157 | }
158 |
159 | foreach ($params['groups'] as $groupName => $groupChecks) {
160 | if (!isset($groupChecks['doctrine_migrations'])) {
161 | continue;
162 | }
163 |
164 | $services = $this->migrationsLoader->loadMigrationChecks(
165 | $container,
166 | $groupChecks['doctrine_migrations'],
167 | $groupName
168 | );
169 |
170 | $parameter = sprintf('%s.check.%s.%s', $this->getAlias(), 'doctrine_migrations', $groupName);
171 | $container->setParameter($parameter, $services);
172 | }
173 | }
174 |
175 | private function configureMailer(ContainerBuilder $container, array $config): void
176 | {
177 | if (false === $config['mailer']['enabled']) {
178 | return;
179 | }
180 |
181 | foreach ($config['mailer'] as $key => $value) {
182 | $container->setParameter(sprintf('%s.mailer.%s', $this->getAlias(), $key), $value);
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/Resources/public/css/bootstrap/css/bootstrap-responsive.min.css:
--------------------------------------------------------------------------------
1 | .clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
2 | .clearfix:after{clear:both;}
3 | .hidden{display:none;visibility:hidden;}
4 | @media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:18px;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} .input-prepend input[class*="span"],.input-append input[class*="span"]{width:auto;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .modal{position:absolute;top:10px;left:10px;right:10px;width:auto;margin:0;}.modal.fade.in{top:auto;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (max-width:767px){.container{width:auto;padding:0 20px;} .row-fluid{width:100%;} .row{margin-left:0;} .row>[class*="span"],.row-fluid>[class*="span"]{float:none;display:block;width:auto;margin:0;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .span1{width:42px;} .span2{width:104px;} .span3{width:166px;} .span4{width:228px;} .span5{width:290px;} .span6{width:352px;} .span7{width:414px;} .span8{width:476px;} .span9{width:538px;} .span10{width:600px;} .span11{width:662px;} .span12,.container{width:724px;} .offset1{margin-left:82px;} .offset2{margin-left:144px;} .offset3{margin-left:206px;} .offset4{margin-left:268px;} .offset5{margin-left:330px;} .offset6{margin-left:392px;} .offset7{margin-left:454px;} .offset8{margin-left:516px;} .offset9{margin-left:578px;} .offset10{margin-left:640px;} .offset11{margin-left:702px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.762430939%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid>.span1{width:5.801104972%;} .row-fluid>.span2{width:14.364640883%;} .row-fluid>.span3{width:22.928176794%;} .row-fluid>.span4{width:31.491712705%;} .row-fluid>.span5{width:40.055248616%;} .row-fluid>.span6{width:48.618784527%;} .row-fluid>.span7{width:57.182320438000005%;} .row-fluid>.span8{width:65.74585634900001%;} .row-fluid>.span9{width:74.30939226%;} .row-fluid>.span10{width:82.87292817100001%;} .row-fluid>.span11{width:91.436464082%;} .row-fluid>.span12{width:99.999999993%;} input.span1,textarea.span1,.uneditable-input.span1{width:32px;} input.span2,textarea.span2,.uneditable-input.span2{width:94px;} input.span3,textarea.span3,.uneditable-input.span3{width:156px;} input.span4,textarea.span4,.uneditable-input.span4{width:218px;} input.span5,textarea.span5,.uneditable-input.span5{width:280px;} input.span6,textarea.span6,.uneditable-input.span6{width:342px;} input.span7,textarea.span7,.uneditable-input.span7{width:404px;} input.span8,textarea.span8,.uneditable-input.span8{width:466px;} input.span9,textarea.span9,.uneditable-input.span9{width:528px;} input.span10,textarea.span10,.uneditable-input.span10{width:590px;} input.span11,textarea.span11,.uneditable-input.span11{width:652px;} input.span12,textarea.span12,.uneditable-input.span12{width:714px;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top{position:static;margin-bottom:18px;} .navbar-fixed-top .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .navbar .nav-collapse{clear:left;} .navbar .nav{float:none;margin:0 0 9px;} .navbar .nav>li{float:none;} .navbar .nav>li>a{margin-bottom:2px;} .navbar .nav>.divider-vertical{display:none;} .navbar .nav .nav-header{color:#999999;text-shadow:none;} .navbar .nav>li>a,.navbar .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .navbar .dropdown-menu li+li a{margin-bottom:2px;} .navbar .nav>li>a:hover,.navbar .dropdown-menu a:hover{background-color:#222222;} .navbar .dropdown-menu{position:static;top:auto;left:auto;float:none;display:block;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .navbar .dropdown-menu:before,.navbar .dropdown-menu:after{display:none;} .navbar .dropdown-menu .divider{display:none;} .navbar-form,.navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222222;border-bottom:1px solid #222222;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);} .navbar .nav.pull-right{float:none;margin-left:0;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;} .btn-navbar{display:block;} .nav-collapse{overflow:hidden;height:0;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:30px;} .span1{width:70px;} .span2{width:170px;} .span3{width:270px;} .span4{width:370px;} .span5{width:470px;} .span6{width:570px;} .span7{width:670px;} .span8{width:770px;} .span9{width:870px;} .span10{width:970px;} .span11{width:1070px;} .span12,.container{width:1170px;} .offset1{margin-left:130px;} .offset2{margin-left:230px;} .offset3{margin-left:330px;} .offset4{margin-left:430px;} .offset5{margin-left:530px;} .offset6{margin-left:630px;} .offset7{margin-left:730px;} .offset8{margin-left:830px;} .offset9{margin-left:930px;} .offset10{margin-left:1030px;} .offset11{margin-left:1130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.564102564%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid>.span1{width:5.982905983%;} .row-fluid>.span2{width:14.529914530000001%;} .row-fluid>.span3{width:23.076923077%;} .row-fluid>.span4{width:31.623931624%;} .row-fluid>.span5{width:40.170940171000005%;} .row-fluid>.span6{width:48.717948718%;} .row-fluid>.span7{width:57.264957265%;} .row-fluid>.span8{width:65.81196581200001%;} .row-fluid>.span9{width:74.358974359%;} .row-fluid>.span10{width:82.905982906%;} .row-fluid>.span11{width:91.45299145300001%;} .row-fluid>.span12{width:100%;} input.span1,textarea.span1,.uneditable-input.span1{width:60px;} input.span2,textarea.span2,.uneditable-input.span2{width:160px;} input.span3,textarea.span3,.uneditable-input.span3{width:260px;} input.span4,textarea.span4,.uneditable-input.span4{width:360px;} input.span5,textarea.span5,.uneditable-input.span5{width:460px;} input.span6,textarea.span6,.uneditable-input.span6{width:560px;} input.span7,textarea.span7,.uneditable-input.span7{width:660px;} input.span8,textarea.span8,.uneditable-input.span8{width:760px;} input.span9,textarea.span9,.uneditable-input.span9{width:860px;} input.span10,textarea.span10,.uneditable-input.span10{width:960px;} input.span11,textarea.span11,.uneditable-input.span11{width:1060px;} input.span12,textarea.span12,.uneditable-input.span12{width:1160px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;}}
5 |
--------------------------------------------------------------------------------
/DependencyInjection/DoctrineMigrations/V2MigrationsLoader.php:
--------------------------------------------------------------------------------
1 | migrationConfigurationsServices as $services) {
41 | [$configurationService, $configuration] = $services;
42 | /** @var Definition $configurationService */
43 | /** @var DoctrineMigrationConfiguration $configuration */
44 | $versions = $this->getPredefinedMigrations($container, $configuration, $this->fakeConnection);
45 | if ($versions) {
46 | $configurationService->addMethodCall('registerMigrations', [$versions]);
47 | }
48 | }
49 | }
50 |
51 | public function createMigrationConfigurationService(
52 | ContainerBuilder $container,
53 | string $connectionName,
54 | string $serviceId,
55 | ?string $filename = null,
56 | ): void {
57 | if (!$container->has(Configuration::class)) {
58 | $container->register(Configuration::class)
59 | ->setAbstract(true)
60 | ->setPublic(true)
61 | ->setArguments([null])
62 | ->addMethodCall('setContainer', [new Reference('service_container')]);
63 | }
64 |
65 | $configuration = $this->createTemporaryConfiguration($container, $this->getConnection(), $filename);
66 |
67 | $serviceConfiguration = new ChildDefinition(Configuration::class);
68 |
69 | $this->migrationConfigurationsServices[] = [$serviceConfiguration, $configuration];
70 |
71 | $serviceConfiguration->replaceArgument(
72 | 0,
73 | new Reference(sprintf('doctrine.dbal.%s_connection', $connectionName))
74 | );
75 |
76 | if ($configuration->getMigrationsNamespace()) {
77 | $serviceConfiguration->addMethodCall(
78 | 'setMigrationsNamespace',
79 | [$configuration->getMigrationsNamespace()]
80 | );
81 | }
82 |
83 | if ($configuration->getMigrationsTableName()) {
84 | $serviceConfiguration->addMethodCall(
85 | 'setMigrationsTableName',
86 | [$configuration->getMigrationsTableName()]
87 | );
88 | }
89 |
90 | if ($configuration->getMigrationsColumnName()) {
91 | $serviceConfiguration->addMethodCall(
92 | 'setMigrationsColumnName',
93 | [$configuration->getMigrationsColumnName()]
94 | );
95 | }
96 |
97 | if ($configuration->getName()) {
98 | $serviceConfiguration->addMethodCall('setName', [$configuration->getName()]);
99 | }
100 |
101 | if ($configuration->getMigrationsDirectory()) {
102 | $directory = $configuration->getMigrationsDirectory();
103 | $pathPlaceholders = ['kernel.root_dir', 'kernel.cache_dir', 'kernel.logs_dir'];
104 | foreach ($pathPlaceholders as $parameter) {
105 | $kernelDir = realpath($container->getParameter($parameter));
106 | if (0 === strpos(realpath($directory), $kernelDir)) {
107 | $directory = str_replace($kernelDir, "%{$parameter}%", $directory);
108 | break;
109 | }
110 | }
111 |
112 | $serviceConfiguration->addMethodCall(
113 | 'setMigrationsDirectory',
114 | [$directory]
115 | );
116 | }
117 |
118 | $serviceConfiguration->addMethodCall('configure', []);
119 |
120 | if ($configuration->areMigrationsOrganizedByYear()) {
121 | $serviceConfiguration->addMethodCall('setMigrationsAreOrganizedByYear', [true]);
122 | } elseif ($configuration->areMigrationsOrganizedByYearAndMonth()) {
123 | $serviceConfiguration->addMethodCall('setMigrationsAreOrganizedByYearAndMonth', [true]);
124 | }
125 |
126 | $container->setDefinition($serviceId, $serviceConfiguration);
127 | }
128 |
129 | /**
130 | * Creates in-memory migration configuration for setting up container service.
131 | *
132 | * @param ContainerBuilder $container The container
133 | * @param Connection $connection Fake connection
134 | * @param string $filename Migrations configuration file
135 | */
136 | private function createTemporaryConfiguration(
137 | ContainerBuilder $container,
138 | Connection $connection,
139 | ?string $filename = null,
140 | ): DoctrineMigrationConfiguration {
141 | if (null === $filename) {
142 | // this is configured from migrations bundle
143 | return new DoctrineMigrationConfiguration($connection);
144 | }
145 |
146 | // -------
147 | // This part must be in sync with Doctrine\Migrations\Tools\Console\Helper\ConfigurationHelper::loadConfig
148 | $map = [
149 | 'xml' => '\XmlConfiguration',
150 | 'yaml' => '\YamlConfiguration',
151 | 'yml' => '\YamlConfiguration',
152 | 'php' => '\ArrayConfiguration',
153 | 'json' => '\JsonConfiguration',
154 | ];
155 | // --------
156 |
157 | $filename = $container->getParameterBag()->resolveValue($filename);
158 | $info = pathinfo($filename);
159 | // check we can support this file type
160 | if (empty($map[$info['extension']])) {
161 | throw new \InvalidArgumentException('Given config file type is not supported');
162 | }
163 |
164 | $class = 'Doctrine\Migrations\Configuration';
165 | $class .= $map[$info['extension']];
166 | // -------
167 |
168 | /** @var AbstractFileConfiguration $configuration */
169 | $configuration = new $class($connection);
170 | $configuration->load($filename);
171 | $configuration->validate();
172 |
173 | return $configuration;
174 | }
175 |
176 | private function getConnection(): Connection
177 | {
178 | if (null === $this->fakeConnection) {
179 | if (!class_exists(Connection::class)) {
180 | throw new \InvalidArgumentException(sprintf('Can not configure doctrine migration checks, because of absence of "%s" class', Connection::class));
181 | }
182 |
183 | $driver = class_exists(Driver::class)
184 | ? new Driver()
185 | : new LegacyDriver();
186 |
187 | $this->fakeConnection = new Connection([], $driver);
188 | }
189 |
190 | return $this->fakeConnection;
191 | }
192 |
193 | /**
194 | * Return key-value array with migration version as key and class as a value defined in config file.
195 | *
196 | * @param ContainerBuilder $container The container
197 | * @param DoctrineMigrationConfiguration $config Current configuration
198 | * @param Connection $connection Fake connections
199 | *
200 | * @return string[]
201 | */
202 | private function getPredefinedMigrations(ContainerBuilder $container, DoctrineMigrationConfiguration $config, Connection $connection): array
203 | {
204 | $result = [];
205 |
206 | $diff = new Configuration($connection);
207 |
208 | if ($namespace = $config->getMigrationsNamespace()) {
209 | $diff->setMigrationsNamespace($config->getMigrationsNamespace());
210 | }
211 |
212 | if ($dir = $config->getMigrationsDirectory()) {
213 | $diff->setMigrationsDirectory($dir);
214 | }
215 |
216 | $diff->setContainer($container);
217 | $diff->configure();
218 |
219 | foreach ($config->getMigrations() as $version) {
220 | $result[$version->getVersion()] = get_class($version->getMigration());
221 | }
222 |
223 | foreach ($diff->getAvailableVersions() as $version) {
224 | unset($result[$version]);
225 | }
226 |
227 | return $result;
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/Resources/views/health/index.html.php:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | Health Check
7 |
8 |
9 |
10 |
11 |
12 |
System Health Status
13 |
44 |
45 |
46 |
47 |
Documentation
48 |
This service performs user defined health checks for the various services that compose an application.
49 |
It offers a REST API where you can list available health checks and also gives the chance to run them individually or all together.
50 | This page is just a HTML view of the JSON response provided by one of those API methods.
51 |
52 |
Repeating failed tests
53 |
54 | The third column of the table displays a button labeled GO. By pressing this button you can re run a failed the tests to see if it came back to normal.
55 |
56 |
REST API
57 |
58 | - getPathInfo(); ?>
59 |
60 | Returns this HTML view. If the check was performed without errors then the table row will be green, else it will be shown as red.
61 |
62 | - getPathInfo().'checks'; ?>
63 | -
64 | Returns a list of available health checks as a JSON array.
65 |
66 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'checks'); ?>
67 |
68 | [
69 | "monitor.check.jackrabbit",
70 | "monitor.check.redis",
71 | "monitor.check.memcache",
72 | "monitor.check.php_extensions"
73 | ]
74 |
75 |
76 | - getPathInfo().'all_checks'; ?>
77 | -
78 | Returns a list of available groups and health checks as a JSON object.
79 |
80 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'all_checks'); ?>
81 |
82 | {
83 | default: [
84 | "monitor.check.jackrabbit",
85 | "monitor.check.redis",
86 | "monitor.check.memcache",
87 | "monitor.check.php_extensions"
88 | ],
89 | app_server: [
90 | "monitor.check.jackrabbit",
91 | "monitor.check.redis",
92 | ],
93 | cron_server: [
94 | "monitor.check.redis",
95 | "monitor.check.memcache",
96 | "monitor.check.php_extensions"
97 | ]
98 | }
99 |
100 |
101 |
102 | - getPathInfo().'groups'; ?>
103 | -
104 | Returns a list of available health checks groups as a JSON array.
105 |
106 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'groups'); ?>
107 |
108 | [
109 | "default",
110 | "app_server",
111 | "cron_server"
112 | ]
113 |
114 |
115 | - getPathInfo().'list/reporters'; ?>
116 | -
117 | Returns a list of additional reporters available as a JSON array.
118 |
119 | $ curl -XGET -H "Accept: application/json" getUriForPath($request->getPathInfo().'list/reporters'); ?>
120 |
121 | [
122 | "newrelic_reporter",
123 | "file_reporter",
124 | "another_awesome_reporter"
125 | ]
126 |
127 |
128 | - getPathInfo().'http_status_checks'; ?>
129 | - Performs all health checks and returns the results within the HTTP Status Code (200 if checks are OK, 502 otherwise). The failure status code is configurable as
failure_status_code.
130 |
131 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'http_status_checks'); ?>
132 |
133 | HTTP/1.1 200 OK
134 |
135 |
136 |
137 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'http_status_checks'); ?>
138 |
139 | HTTP/1.1 502 Bad Gateway
140 |
141 |
142 |
143 | - getPathInfo().'http_status_check/check_id'; ?>
144 | - Performs the health check specified by
check_id and returns the result within the HTTP Status Code (200 if checks are OK, 502 otherwise). The failure status code is configurable as failure_status_code.
145 |
146 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'http_status_check/monitor.check.redis'); ?>
147 |
148 | HTTP/1.1 200 OK
149 |
150 |
151 |
152 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'http_status_check/monitor.check.redis'); ?>
153 |
154 | HTTP/1.1 502 Bad Gateway
155 |
156 |
157 |
158 | - getPathInfo().'run'; ?>
159 | - Performs all health checks and returns the results as an array of JSON objects.
160 |
161 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'run'); ?>
162 |
163 | {
164 | "checks":
165 | [
166 | {"checkName": "Jackrabbit Health Check", "message": "OK", "status":true, "service_id": "monitor.check.jackrabbit"},
167 | {"checkName": "Redis Health Check", "message": "OK", "status":true, "service_id": "monitor.check.redis"},
168 | {"checkName": "Memcache Health Check", "message": "KO - No configuration set for session.save_path", "status":false, "service_id": "monitor.check.memcache"},
169 | {"checkName": "PHP Extensions Health Check", "message": "OK", "status":true, "service_id": "monitor.check.php_extensions"}
170 | ],
171 | "globalStatus": "OK|KO"
172 | }
173 |
174 |
175 | - getPathInfo().'run/check_id'; ?>
176 | - Runs the health check specified by
check_id and returns the result as a JSON object.
177 |
178 | $ curl -XPOST -H "Accept: application/json" getUriForPath($request->getPathInfo().'run/monitor.check.redis'); ?>
179 |
180 | {
181 | "checkName": "Redis Health Check",
182 | "message": "OK",
183 | "status": true,
184 | "service_id": "monitor.check.redis"
185 | }
186 |
187 | - Check Result JSON Structure
188 | -
189 |
190 | checkName
191 | - A string providing the health check name.
192 | message
193 | - A message returned by the health check. In case of an error the exception message is shown here.
194 | status
195 | - A boolean indication if the health check passed.
196 | service_id
197 | - The
service_id specified in the service container configuration.
198 |
199 |
200 |
201 |
Grouping Checks
202 |
203 | The following URLs accept an optional query parameter
?group= to specify the check group:
204 |
205 | - getPathInfo().'checks?group='.$group; ?>
206 | - getPathInfo().'http_status_checks?group='.$group; ?>
207 | - getPathInfo().'http_status_check/check_id?group='.$group; ?>
208 | - getPathInfo().'run?group='.$group; ?>
209 | - getPathInfo().'run/check_id?group='.$group; ?>
210 |
211 |
212 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------