├── .github ├── stale.yml └── workflows │ └── ci.yml ├── .gitignore ├── .php-cs-fixer.dist.php ├── .scrutinizer.yml ├── CONTRIBUTING.md ├── Check ├── CustomErrorPages.php ├── DoctrineDbal.php ├── DoctrineDbalCollection.php ├── DoctrineMigrationsCollection.php ├── DoctrineMongoDb.php ├── DoctrineMongoDbCollection.php ├── Expression.php ├── ExpressionCollection.php ├── GuzzleHttpServiceCollection.php ├── HttpServiceCollection.php ├── MemcacheCollection.php ├── MemcachedCollection.php ├── PdoConnectionCollection.php ├── PhpFlagsCollection.php ├── PhpVersionCollection.php ├── ProcessRunningCollection.php ├── RabbitMQCollection.php ├── RedisCollection.php ├── SymfonyMessengerTransportCount.php ├── SymfonyMessengerTransportCountCollection.php ├── SymfonyRequirements.php └── SymfonyVersion.php ├── Command ├── HealthCheckCommand.php └── ListChecksCommand.php ├── Composer └── ScriptHandler.php ├── Controller └── HealthCheckController.php ├── DependencyInjection ├── Compiler │ ├── AddGroupsCompilerPass.php │ ├── AdditionalReporterCompilerPass.php │ ├── CheckAssetsEnabledPass.php │ ├── CheckCollectionTagCompilerPass.php │ ├── CheckTagCompilerPass.php │ ├── GroupRunnersCompilerPass.php │ └── MailerCompilerPass.php ├── Configuration.php ├── DoctrineMigrations │ ├── AbstractDoctrineMigrationsLoader.php │ ├── DoctrineMigrationsLoader.php │ ├── V2MigrationsLoader.php │ └── V3MigrationsLoader.php └── LiipMonitorExtension.php ├── DoctrineMigrations └── Configuration.php ├── Helper ├── AbstractMailReporter.php ├── ArrayReporter.php ├── ConsoleReporter.php ├── PathHelper.php ├── RawConsoleReporter.php ├── RunnerManager.php ├── SwiftMailerReporter.php └── SymfonyMailerReporter.php ├── LiipMonitorBundle.php ├── README.md ├── Resources ├── config │ ├── checks │ │ ├── apc_fragmentation.xml │ │ ├── apc_memory.xml │ │ ├── class_exists.xml │ │ ├── cpu_performance.xml │ │ ├── custom_error_pages.xml │ │ ├── disk_usage.xml │ │ ├── doctrine_dbal.xml │ │ ├── doctrine_migrations.xml │ │ ├── doctrine_mongodb.xml │ │ ├── expressions.xml │ │ ├── file_ini.xml │ │ ├── file_json.xml │ │ ├── file_xml.xml │ │ ├── file_yaml.xml │ │ ├── guzzle_http_service.xml │ │ ├── http_service.xml │ │ ├── memcache.xml │ │ ├── memcached.xml │ │ ├── messenger_transports.xml │ │ ├── opcache_memory.xml │ │ ├── pdo_connections.xml │ │ ├── php_extensions.xml │ │ ├── php_flags.xml │ │ ├── php_version.xml │ │ ├── process_running.xml │ │ ├── rabbit_mq.xml │ │ ├── readable_directory.xml │ │ ├── redis.xml │ │ ├── security_advisory.xml │ │ ├── stream_wrapper_exists.xml │ │ ├── symfony_requirements.xml │ │ ├── symfony_version.xml │ │ └── writable_directory.xml │ ├── commands.xml │ ├── controller.xml │ ├── helper.xml │ ├── routing.php │ ├── routing.xml │ ├── runner.xml │ ├── swift_mailer.xml │ └── symfony_mailer.xml ├── doc │ └── screenshot.png ├── meta │ └── LICENSE ├── public │ ├── css │ │ ├── bootstrap │ │ │ ├── css │ │ │ │ ├── bootstrap-responsive.css │ │ │ │ ├── bootstrap-responsive.min.css │ │ │ │ ├── bootstrap.css │ │ │ │ └── bootstrap.min.css │ │ │ ├── img │ │ │ │ ├── glyphicons-halflings-white.png │ │ │ │ └── glyphicons-halflings.png │ │ │ └── js │ │ │ │ ├── bootstrap.js │ │ │ │ └── bootstrap.min.js │ │ └── style.css │ └── javascript │ │ ├── app.js │ │ ├── ember-0.9.5.min.js │ │ └── jquery-1.7.1.min.js ├── scripts │ ├── check_symfony2.pl │ └── check_symfony2.py └── views │ └── health │ └── index.html.php ├── Runner.php ├── Tests ├── Check │ ├── ExpressionTest.php │ ├── RedisCollectionTest.php │ └── SymfonyMessengerTransportCountTest.php ├── DependencyInjection │ ├── Compiler │ │ ├── AddGroupsCompilerPassTest.php │ │ ├── AdditionalReporterCompilerPassTest.php │ │ ├── CheckCollectionTagCompilerPassTest.php │ │ ├── CheckTagCompilerPassTest.php │ │ ├── GroupRunnersCompilerPassTest.php │ │ └── MailerCompilerPassTest.php │ └── LiipMonitorExtensionTest.php ├── Helper │ ├── PathHelperTest.php │ ├── RunnerManagerTest.php │ ├── SwiftMailerReporterTest.php │ └── SymfonyMailerReporterTest.php ├── LiipMonitorBundleTest.php ├── RunnerTest.php ├── app │ ├── AppKernel.php │ ├── config_symfony4.yml │ ├── config_symfony5.yml │ ├── config_symfony6.yml │ ├── config_symfony7.yml │ └── routing.yml └── bootstrap.php ├── UPGRADE.md ├── composer.json └── phpunit.xml.dist /.github/stale.yml: -------------------------------------------------------------------------------- 1 | daysUntilStale: 60 2 | daysUntilClose: 7 3 | exemptLabels: [] 4 | staleLabel: stale 5 | issues: 6 | markComment: > 7 | This issue has been automatically marked as stale because it has not had 8 | recent activity. It will be closed if no further activity occurs. Thank you 9 | for your contributions. 10 | closeComment: > 11 | This issue has been automatically closed. Feel free to re-open if it is 12 | still relevant. 13 | pulls: 14 | markComment: > 15 | This pull request has been automatically marked as stale because it has not 16 | had recent activity. It will be closed if no further activity occurs. Thank 17 | you for your contributions. 18 | closeComment: > 19 | This pull request has been automatically closed. Feel free to re-create if it 20 | is still relevant. 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 0 1,16 * *' 8 | 9 | jobs: 10 | symfony-version-tests: 11 | name: "Test: PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}" 12 | 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | fail-fast: true 17 | matrix: 18 | include: 19 | - php: 7.4 20 | symfony: 5.4.* 21 | - php: 8.0 22 | symfony: 5.4.* 23 | - php: 8.1 24 | symfony: 6.4.* 25 | - php: 8.2 26 | symfony: 6.4.* 27 | - php: 8.2 28 | symfony: 7.0.* 29 | - php: 8.3 30 | symfony: 7.0.* 31 | 32 | steps: 33 | - name: Checkout code 34 | uses: actions/checkout@v4 35 | 36 | - name: Setup PHP 37 | uses: shivammathur/setup-php@v2 38 | with: 39 | php-version: ${{ matrix.php }} 40 | coverage: none 41 | tools: flex 42 | 43 | - name: Install symfony/mailer 44 | run: composer require --dev "symfony/mailer" --no-update 45 | 46 | - name: Install dependencies 47 | uses: ramsey/composer-install@v2 48 | with: 49 | composer-options: --prefer-dist 50 | env: 51 | SYMFONY_REQUIRE: ${{ matrix.symfony }} 52 | 53 | - name: Run tests 54 | run: vendor/bin/phpunit -v 55 | 56 | prefer-lowest-tests: 57 | name: "Test: prefer-lowest" 58 | 59 | runs-on: ubuntu-latest 60 | 61 | steps: 62 | - name: Checkout code 63 | uses: actions/checkout@v4 64 | 65 | - name: Setup PHP 66 | uses: shivammathur/setup-php@v2 67 | with: 68 | php-version: 7.3 69 | coverage: none 70 | 71 | - name: Install dependencies 72 | uses: ramsey/composer-install@v2 73 | with: 74 | dependency-versions: lowest 75 | composer-options: --prefer-dist 76 | 77 | - name: Run tests 78 | run: vendor/bin/phpunit -v 79 | 80 | code-coverage: 81 | name: Code Coverage 82 | runs-on: ubuntu-latest 83 | steps: 84 | - name: Checkout code 85 | uses: actions/checkout@v4 86 | 87 | - name: Setup PHP 88 | uses: shivammathur/setup-php@v2 89 | with: 90 | php-version: 7.4 91 | coverage: xdebug 92 | 93 | - name: Install symfony/mailer 94 | run: composer require --dev "symfony/mailer" --no-update 95 | 96 | - name: Install dependencies 97 | uses: ramsey/composer-install@v2 98 | with: 99 | composer-options: --prefer-dist 100 | 101 | - name: Run code coverage 102 | run: vendor/bin/phpunit -v --coverage-text 103 | 104 | composer-validate: 105 | name: Validate composer.json 106 | runs-on: ubuntu-latest 107 | steps: 108 | - name: Checkout code 109 | uses: actions/checkout@v4 110 | 111 | - name: Setup PHP 112 | uses: shivammathur/setup-php@v2 113 | with: 114 | php-version: 7.4 115 | coverage: none 116 | 117 | - name: Validate composer.json 118 | run: composer validate --strict --no-check-lock 119 | 120 | cs-check: 121 | name: PHP Coding Standards 122 | runs-on: ubuntu-latest 123 | steps: 124 | - name: Checkout code 125 | uses: actions/checkout@v4 126 | 127 | - name: Setup PHP 128 | uses: shivammathur/setup-php@v2 129 | with: 130 | php-version: 7.4 131 | coverage: none 132 | 133 | - name: Install dependencies 134 | uses: ramsey/composer-install@v2 135 | with: 136 | composer-options: --prefer-dist 137 | 138 | - name: Check CS 139 | run: vendor/bin/php-cs-fixer fix --diff --dry-run --verbose 140 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Tests/app/cache 2 | /Tests/app/logs 3 | /Tests/app/var 4 | /vendor 5 | composer.lock 6 | .phpunit.result.cache 7 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | exclude('vendor') 5 | ->exclude('Tests/app/var') 6 | ->in(__DIR__) 7 | ; 8 | 9 | return (new PhpCsFixer\Config()) 10 | ->setRules([ 11 | '@Symfony' => true, 12 | 'no_superfluous_phpdoc_tags' => [ 13 | 'allow_mixed' => true, 14 | 'allow_unused_params' => false, 15 | 'remove_inheritdoc' => true, 16 | ], 17 | ]) 18 | ->setFinder($finder) 19 | ->setUsingCache(false) 20 | ; 21 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | dependency_paths: [vendor/] 3 | checks: 4 | php: true 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Check/CustomErrorPages.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class CustomErrorPages implements CheckInterface 16 | { 17 | /** 18 | * @var array 19 | */ 20 | protected $errorCodes; 21 | 22 | /** 23 | * @var string 24 | */ 25 | protected $path; 26 | 27 | /** 28 | * @var string 29 | */ 30 | protected $projectDir; 31 | 32 | public function __construct(array $errorCodes, $path, $projectDir) 33 | { 34 | $this->errorCodes = $errorCodes; 35 | $this->path = $path; 36 | $this->projectDir = $projectDir; 37 | } 38 | 39 | /** 40 | * @return ResultInterface 41 | */ 42 | public function check() 43 | { 44 | $dir = $this->getCustomTemplateDirectory(); 45 | $missingTemplates = []; 46 | 47 | foreach ($this->errorCodes as $errorCode) { 48 | $template = sprintf('%s/error%d.html.twig', $dir, $errorCode); 49 | 50 | if (!file_exists($template)) { 51 | $missingTemplates[] = $errorCode; 52 | } 53 | } 54 | 55 | if (count($missingTemplates) > 0) { 56 | return new Failure(sprintf('No custom error page found for the following codes: %s', implode(', ', $missingTemplates))); 57 | } 58 | 59 | return new Success(); 60 | } 61 | 62 | /** 63 | * @return string 64 | */ 65 | public function getLabel() 66 | { 67 | return 'Custom error pages'; 68 | } 69 | 70 | private function getCustomTemplateDirectory(): string 71 | { 72 | if ($this->projectDir !== $this->path) { 73 | return $this->path; // using custom directory 74 | } 75 | 76 | if (file_exists($dir = $this->projectDir.'/templates/bundles/TwigBundle/Exception')) { 77 | return $dir; // using standard 4.0+ directory 78 | } 79 | 80 | return $this->projectDir.'/app/Resources/TwigBundle/views/Exception'; // assume using 3.4 dir structure 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Check/DoctrineDbal.php: -------------------------------------------------------------------------------- 1 | manager = $registry; 18 | $this->connectionName = $connectionName; 19 | } 20 | 21 | /** 22 | * @return ResultInterface 23 | */ 24 | public function check() 25 | { 26 | $connection = $this->manager->getConnection($this->connectionName); 27 | $query = $connection->getDriver()->getDatabasePlatform($connection)->getDummySelectSQL(); 28 | 29 | // after dbal 2.11 fetchOne replace fetchColumn 30 | if (method_exists($connection, 'fetchOne')) { 31 | $connection->fetchOne($query); 32 | } else { 33 | $connection->fetchColumn($query); 34 | } 35 | 36 | return new Success(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Check/DoctrineDbalCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class DoctrineDbalCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct(ConnectionRegistry $manager, $connections) 16 | { 17 | if (!is_array($connections)) { 18 | $connections = [$connections]; 19 | } 20 | 21 | foreach ($connections as $connection) { 22 | $check = new DoctrineDbal($manager, $connection); 23 | $check->setLabel(sprintf('Doctrine DBAL "%s" connection', $connection)); 24 | 25 | $this->checks[sprintf('doctrine_dbal_%s_connection', $connection)] = $check; 26 | } 27 | } 28 | 29 | /** 30 | * @return array|\Traversable 31 | */ 32 | public function getChecks() 33 | { 34 | return $this->checks; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Check/DoctrineMigrationsCollection.php: -------------------------------------------------------------------------------- 1 | container = $container; 48 | $this->migrations = $migrations; 49 | } 50 | 51 | /** 52 | * @return array|\Traversable 53 | */ 54 | public function getChecks() 55 | { 56 | if (null === $this->checks) { 57 | $this->checks = []; 58 | foreach ($this->migrations as $key => $migration) { 59 | $check = new LaminasDoctrineMigration($this->container->get($migration)); 60 | $check->setLabel(sprintf('Doctrine migrations "%s"', $key)); 61 | 62 | $this->checks[$key] = $check; 63 | } 64 | } 65 | 66 | return $this->checks; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Check/DoctrineMongoDb.php: -------------------------------------------------------------------------------- 1 | manager = $registry; 21 | $this->connectionName = $connectionName; 22 | } 23 | 24 | /** 25 | * @return ResultInterface 26 | */ 27 | public function check() 28 | { 29 | $connection = $this->manager->getConnection($this->connectionName); 30 | 31 | // Using "mongo" PHP extension 32 | if (\method_exists($connection, 'connect')) { 33 | $connection->connect(); 34 | 35 | if ($connection->isConnected()) { 36 | return new Success(); 37 | } 38 | 39 | return new Failure( 40 | sprintf( 41 | 'Connection "%s" is unavailable.', 42 | $this->connectionName 43 | ) 44 | ); 45 | } 46 | 47 | // Using "mongodb" PHP extension 48 | try { 49 | $connection->getManager()->executeCommand('test', new Command(['ping' => 1])); 50 | } catch (ConnectionException $e) { 51 | return new Failure( 52 | sprintf( 53 | 'Connection "%s" is unavailable.', 54 | $this->connectionName 55 | ) 56 | ); 57 | } 58 | 59 | return new Success(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Check/DoctrineMongoDbCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class DoctrineMongoDbCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct(ConnectionRegistry $manager, $connections) 16 | { 17 | if (!is_array($connections)) { 18 | $connections = [$connections]; 19 | } 20 | 21 | foreach ($connections as $connection) { 22 | $check = new DoctrineMongoDb($manager, $connection); 23 | $check->setLabel(sprintf('Doctrine Mongo Db "%s" connection', $connection)); 24 | 25 | $this->checks[sprintf('doctrine_mongodb_%s_connection', $connection)] = $check; 26 | } 27 | } 28 | 29 | /** 30 | * @return array|\Traversable 31 | */ 32 | public function getChecks() 33 | { 34 | return $this->checks; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Check/Expression.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class Expression implements CheckInterface 16 | { 17 | private $label; 18 | private $warningCheck; 19 | private $criticalCheck; 20 | private $warningMessage; 21 | private $criticalMessage; 22 | 23 | public function __construct($label, $warningCheck = null, $criticalCheck = null, $warningMessage = null, $criticalMessage = null) 24 | { 25 | if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { 26 | throw new \Exception('The symfony/expression-language is required for this check.'); 27 | } 28 | 29 | if (!$warningCheck && !$criticalCheck) { 30 | throw new \InvalidArgumentException('Not checks set.'); 31 | } 32 | 33 | $this->label = $label; 34 | $this->warningCheck = $warningCheck; 35 | $this->warningMessage = $warningMessage; 36 | $this->criticalCheck = $criticalCheck; 37 | $this->criticalMessage = $criticalMessage; 38 | } 39 | 40 | /** 41 | * @return ResultInterface 42 | */ 43 | public function check() 44 | { 45 | $language = $this->getExpressionLanguage(); 46 | 47 | if ($this->criticalCheck && false === $language->evaluate($this->criticalCheck)) { 48 | return new Failure($this->criticalMessage); 49 | } 50 | 51 | if ($this->warningCheck && false === $language->evaluate($this->warningCheck)) { 52 | return new Warning($this->warningMessage); 53 | } 54 | 55 | return new Success(); 56 | } 57 | 58 | /** 59 | * @return string 60 | */ 61 | public function getLabel() 62 | { 63 | return $this->label; 64 | } 65 | 66 | protected function getExpressionLanguage(): ExpressionLanguage 67 | { 68 | $language = new ExpressionLanguage(); 69 | $language->register( 70 | 'ini', 71 | function ($value) { 72 | return $value; 73 | }, 74 | function ($arguments, $value) { 75 | return ini_get($value); 76 | } 77 | ); 78 | 79 | return $language; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Check/ExpressionCollection.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class ExpressionCollection implements CheckCollectionInterface 11 | { 12 | private $checks = []; 13 | 14 | public function __construct(array $configs) 15 | { 16 | foreach ($configs as $alias => $config) { 17 | $this->checks[sprintf('expression_%s', $alias)] = new Expression( 18 | $config['label'], 19 | $config['warning_expression'], 20 | $config['critical_expression'], 21 | $config['warning_message'], 22 | $config['critical_message'] 23 | ); 24 | } 25 | } 26 | 27 | /** 28 | * @return array|\Traversable 29 | */ 30 | public function getChecks() 31 | { 32 | return $this->checks; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Check/GuzzleHttpServiceCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class GuzzleHttpServiceCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct(array $configs) 16 | { 17 | foreach ($configs as $name => $config) { 18 | $check = new GuzzleHttpService( 19 | $config['url'], 20 | $config['headers'], 21 | $config['options'], 22 | $config['status_code'], 23 | $config['content'], 24 | null, 25 | $config['method'], 26 | $config['body'] 27 | ); 28 | $check->setLabel(sprintf('Guzzle Http Service "%s"', $name)); 29 | 30 | $this->checks[sprintf('guzzle_http_service_%s', $name)] = $check; 31 | } 32 | } 33 | 34 | /** 35 | * @return array|\Traversable 36 | */ 37 | public function getChecks() 38 | { 39 | return $this->checks; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Check/HttpServiceCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class HttpServiceCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct(array $configs) 16 | { 17 | foreach ($configs as $name => $config) { 18 | $check = new HttpService($config['host'], $config['port'], $config['path'], $config['status_code'], $config['content']); 19 | $check->setLabel(sprintf('Http Service "%s"', $name)); 20 | 21 | $this->checks[sprintf('http_service_%s', $name)] = $check; 22 | } 23 | } 24 | 25 | /** 26 | * @return array|\Traversable 27 | */ 28 | public function getChecks() 29 | { 30 | return $this->checks; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Check/MemcacheCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class MemcacheCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct(array $configs) 16 | { 17 | foreach ($configs as $name => $config) { 18 | $check = new Memcache($config['host'], $config['port']); 19 | $check->setLabel(sprintf('Memcache "%s"', $name)); 20 | 21 | $this->checks[sprintf('memcache_%s', $name)] = $check; 22 | } 23 | } 24 | 25 | /** 26 | * @return array|\Traversable 27 | */ 28 | public function getChecks() 29 | { 30 | return $this->checks; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Check/MemcachedCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class MemcachedCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct(array $configs) 16 | { 17 | foreach ($configs as $name => $config) { 18 | $check = new Memcached($config['host'], $config['port']); 19 | $check->setLabel(sprintf('Memcached "%s"', $name)); 20 | 21 | $this->checks[sprintf('memcached_%s', $name)] = $check; 22 | } 23 | } 24 | 25 | /** 26 | * @return array|\Traversable 27 | */ 28 | public function getChecks() 29 | { 30 | return $this->checks; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Check/PdoConnectionCollection.php: -------------------------------------------------------------------------------- 1 | $connection) { 15 | $check = new PDOCheck($connection['dsn'], $connection['username'], $connection['password'], $connection['timeout']); 16 | $this->checks[sprintf('pdo_%s', $name)] = $check; 17 | } 18 | } 19 | 20 | /** 21 | * @return array|\Traversable 22 | */ 23 | public function getChecks() 24 | { 25 | return $this->checks; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Check/PhpFlagsCollection.php: -------------------------------------------------------------------------------- 1 | $value) { 18 | $check = new PhpFlag($setting, $value); 19 | $check->setLabel(sprintf('PHP flag "%s"', $setting)); 20 | 21 | $this->checks[sprintf('php_flag_%s', $setting)] = $check; 22 | } 23 | } 24 | 25 | /** 26 | * @return array|\Traversable 27 | */ 28 | public function getChecks() 29 | { 30 | return $this->checks; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Check/PhpVersionCollection.php: -------------------------------------------------------------------------------- 1 | $comparisonOperator) { 18 | $check = new PhpVersion($version, $comparisonOperator); 19 | $check->setLabel(sprintf('PHP version "%s" "%s"', $comparisonOperator, $version)); 20 | 21 | $this->checks[sprintf('php_version_%s', $version)] = $check; 22 | } 23 | } 24 | 25 | /** 26 | * @return array|\Traversable 27 | */ 28 | public function getChecks() 29 | { 30 | return $this->checks; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Check/ProcessRunningCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class ProcessRunningCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct($processes) 16 | { 17 | if (!is_array($processes)) { 18 | $processes = [$processes]; 19 | } 20 | 21 | foreach ($processes as $process) { 22 | $check = new ProcessRunning($process); 23 | $check->setLabel(sprintf('Process "%s" running', $process)); 24 | 25 | $this->checks[sprintf('process_%s_running', $process)] = $check; 26 | } 27 | } 28 | 29 | /** 30 | * @return array|\Traversable 31 | */ 32 | public function getChecks() 33 | { 34 | return $this->checks; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Check/RabbitMQCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class RabbitMQCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct(array $configs) 16 | { 17 | foreach ($configs as $name => $config) { 18 | if (isset($config['dsn'])) { 19 | $config = array_merge($config, parse_url($config['dsn'])); 20 | if (isset($config['pass'])) { 21 | $config['password'] = $config['pass']; 22 | // Cleanup 23 | unset($config['pass']); 24 | } 25 | if (isset($config['path'])) { 26 | $config['vhost'] = urldecode(substr($config['path'], 1)); 27 | // Cleanup 28 | unset($config['path']); 29 | } 30 | } 31 | 32 | $check = new RabbitMQ($config['host'], $config['port'], $config['user'], $config['password'], $config['vhost']); 33 | $check->setLabel(sprintf('Rabbit MQ "%s"', $name)); 34 | 35 | $this->checks[sprintf('rabbit_mq_%s', $name)] = $check; 36 | } 37 | } 38 | 39 | /** 40 | * @return array|\Traversable 41 | */ 42 | public function getChecks() 43 | { 44 | return $this->checks; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Check/RedisCollection.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class RedisCollection implements CheckCollectionInterface 12 | { 13 | private $checks = []; 14 | 15 | public function __construct(array $configs) 16 | { 17 | foreach ($configs as $name => $config) { 18 | if (isset($config['dsn'])) { 19 | $this->parseDsn($config); 20 | } 21 | 22 | $check = new Redis($config['host'], $config['port'], $config['password']); 23 | $check->setLabel(\sprintf('Redis "%s"', $name)); 24 | 25 | $this->checks[\sprintf('redis_%s', $name)] = $check; 26 | } 27 | } 28 | 29 | private function parseDsn(array &$config): void 30 | { 31 | $config = \array_merge($config, \parse_url($config['dsn'])); 32 | 33 | if (isset($config['pass'])) { 34 | $config['password'] = $config['pass']; 35 | // Cleanup 36 | unset($config['pass']); 37 | } elseif (isset($config['user'])) { 38 | /* 39 | * since "redis://my-super-secret-password@redis-host:6379" is a valid redis 40 | * dsn but \parse_url does not understand this notation and extracts the auth as user, 41 | * we need to check for it. 42 | */ 43 | $config['password'] = $config['user']; 44 | unset($config['user']); 45 | } 46 | } 47 | 48 | /** 49 | * @return array|\Traversable 50 | */ 51 | public function getChecks() 52 | { 53 | return $this->checks; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Check/SymfonyMessengerTransportCount.php: -------------------------------------------------------------------------------- 1 | transport = $transport; 22 | $this->transportName = $transportName; 23 | 24 | $this->warningThreshold = $config['warning_threshold']; 25 | $this->criticalThreshold = $config['critical_threshold']; 26 | 27 | if ($this->warningThreshold && $this->warningThreshold >= $this->criticalThreshold) { 28 | throw new \LogicException('Warning threshold must be lower than critical threshold'); 29 | } 30 | } 31 | 32 | public function check() 33 | { 34 | $count = $this->transport->getMessageCount(); 35 | 36 | if ($count >= $this->criticalThreshold) { 37 | return new Failure(sprintf('Critical: count of messages (%d) in transport "%s" exceeds limit', $count, $this->transportName)); 38 | } 39 | if ($this->warningThreshold && $count >= $this->warningThreshold) { 40 | return new Warning(sprintf('Warning: count of messages (%d) in transport "%s" exceeds limit', $count, $this->transportName)); 41 | } 42 | 43 | return new Success(sprintf('Message count (%d) in "%s" expected range', $count, $this->transportName)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Check/SymfonyMessengerTransportCountCollection.php: -------------------------------------------------------------------------------- 1 | messengerLocator = $messengerReceiverLocator; 27 | $this->transports = $transportConfig; 28 | } 29 | 30 | public function getChecks() 31 | { 32 | $checks = []; 33 | foreach ($this->transports as $transportName => $config) { 34 | $serviceId = $config['service'] ?? self::SERVICE_ID_PREFIX.$transportName; 35 | if (!$this->messengerLocator->has($serviceId)) { 36 | throw new ServiceNotFoundException($serviceId); 37 | } 38 | $transport = $this->messengerLocator->get($serviceId); 39 | if (!$transport instanceof MessageCountAwareInterface) { 40 | throw new \Exception(sprintf('Cannot use transport "%s" for check, it does not implement MessageCountAwareInterface', $transportName)); 41 | } 42 | $checks[sprintf('messenger_transport_%s', $transportName)] = new SymfonyMessengerTransportCount($transport, $transportName, $config); 43 | } 44 | 45 | return $checks; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Check/SymfonyRequirements.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class SymfonyRequirements implements CheckInterface 15 | { 16 | public function __construct($file) 17 | { 18 | if (!file_exists($file)) { 19 | throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $file)); 20 | } 21 | 22 | require $file; 23 | } 24 | 25 | /** 26 | * @return ResultInterface 27 | */ 28 | public function check() 29 | { 30 | $symfonyRequirements = new \SymfonyRequirements(); 31 | 32 | if (count($symfonyRequirements->getFailedRequirements())) { 33 | return new Failure('Some Symfony2 requirements are not met.'); 34 | } 35 | 36 | if (count($symfonyRequirements->getFailedRecommendations())) { 37 | return new Warning('Some Symfony2 recommendations are not met.'); 38 | } 39 | 40 | return new Success(); 41 | } 42 | 43 | /** 44 | * @return string 45 | */ 46 | public function getLabel() 47 | { 48 | return 'Symfony2 Requirements'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Composer/ScriptHandler.php: -------------------------------------------------------------------------------- 1 | getIO()->write('Performing system health checks...'); 21 | static::executeCommand($event, $consoleDir, 'monitor:health'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /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/Compiler/AddGroupsCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasParameter('liip_monitor.checks')) { 15 | return; 16 | } 17 | 18 | $checkConfig = $container->getParameter('liip_monitor.checks'); 19 | 20 | list($checks, $checkCollections) = $this->parseGroups($container, $checkConfig['groups']); 21 | 22 | $this->addGroupTags($container, $checks, 'liip_monitor.check'); 23 | $this->addGroupTags($container, $checkCollections, 'liip_monitor.check_collection'); 24 | } 25 | 26 | private function parseGroups(ContainerBuilder $container, array $data): array 27 | { 28 | $checks = []; 29 | $checkCollections = []; 30 | 31 | foreach ($data as $group => $groupChecks) { 32 | foreach (array_keys($groupChecks) as $checkName) { 33 | $serviceId = self::SERVICE_ID_PREFIX.$checkName; 34 | $checkDefinition = $container->getDefinition($serviceId); 35 | 36 | if ($checkDefinition->hasTag('liip_monitor.check')) { 37 | $checks[$checkName][] = $group; 38 | } elseif ($checkDefinition->hasTag('liip_monitor.check_collection')) { 39 | $checkCollections[$checkName][] = $group; 40 | } 41 | } 42 | } 43 | 44 | return [$checks, $checkCollections]; 45 | } 46 | 47 | /** 48 | * This Method completes the service definitions of each check for a configured group. 49 | * 50 | * For every configured check (per group) a parameter has been generated in LiipMonitorExtension::setParameters. 51 | * So the finally generated parameters have to be injected into each check service definition. 52 | * (see the preg_match part). 53 | * 54 | * @param string $tag 55 | */ 56 | private function addGroupTags(ContainerBuilder $container, array $checks, $tag): void 57 | { 58 | foreach ($checks as $checkName => $groups) { 59 | $serviceId = self::SERVICE_ID_PREFIX.$checkName; 60 | $serviceDefinition = $container->getDefinition($serviceId); 61 | $serviceDefinition->clearTag($tag); 62 | 63 | foreach ($groups as $group) { 64 | $tmpDefinition = clone $serviceDefinition; 65 | $tmpDefinition->addTag($tag, ['group' => $group, 'alias' => $checkName]); 66 | 67 | foreach ($tmpDefinition->getArguments() as $argumentIndex => $argument) { 68 | if (is_string($argument) && preg_match('/^%%(.*)%%$/', $argument, $matches)) { 69 | $newArgument = $container->getParameter($matches[1].'.'.$group); 70 | $tmpDefinition->replaceArgument($argumentIndex, $newArgument); 71 | } 72 | } 73 | 74 | $container->setDefinition($serviceId.'.'.$group, $tmpDefinition); 75 | } 76 | 77 | $container->removeDefinition($serviceId); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/AdditionalReporterCompilerPass.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class AdditionalReporterCompilerPass implements CompilerPassInterface 13 | { 14 | public function process(ContainerBuilder $container): void 15 | { 16 | if (false === $container->hasParameter('liip_monitor.runners')) { 17 | return; 18 | } 19 | 20 | foreach ($container->getParameter('liip_monitor.runners') as $runnerServiceId) { 21 | $definition = $container->getDefinition($runnerServiceId); 22 | 23 | foreach ($container->findTaggedServiceIds('liip_monitor.additional_reporter') as $id => $tags) { 24 | foreach ($tags as $attributes) { 25 | $alias = empty($attributes['alias']) ? $id : $attributes['alias']; 26 | $definition->addMethodCall('addAdditionalReporter', [$alias, new Reference($id)]); 27 | } 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/CheckAssetsEnabledPass.php: -------------------------------------------------------------------------------- 1 | has('liip_monitor.health_controller') && !$container->has('assets.packages')) { 14 | throw new LogicException('Controller support cannot be enabled unless the frameworkbundle "assets" support is also enabled.'); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/CheckCollectionTagCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasParameter('liip_monitor.default_group')) { 14 | return; 15 | } 16 | 17 | $defaultGroup = $container->getParameter('liip_monitor.default_group'); 18 | 19 | foreach ($container->findTaggedServiceIds('liip_monitor.check_collection') as $id => $tags) { 20 | foreach ($tags as $attributes) { 21 | $group = empty($attributes['group']) ? $defaultGroup : $attributes['group']; 22 | 23 | $runnerDefinition = $container->getDefinition('liip_monitor.runner_'.$group); 24 | $runnerDefinition->addMethodCall('addChecks', [new Reference($id)]); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/CheckTagCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasParameter('liip_monitor.default_group')) { 14 | return; 15 | } 16 | 17 | $defaultGroup = $container->getParameter('liip_monitor.default_group'); 18 | 19 | foreach ($container->findTaggedServiceIds('liip_monitor.check') as $id => $tags) { 20 | foreach ($tags as $attributes) { 21 | $alias = empty($attributes['alias']) ? $id : $attributes['alias']; 22 | $group = empty($attributes['group']) ? $defaultGroup : $attributes['group']; 23 | 24 | $runnerDefinition = $container->getDefinition('liip_monitor.runner_'.$group); 25 | $runnerDefinition->addMethodCall('addCheck', [new Reference($id), $alias]); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/GroupRunnersCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition('liip_monitor.runner'); 14 | $noDefaultGroup = false === $container->hasParameter('liip_monitor.default_group'); 15 | 16 | if ($noRunner || $noDefaultGroup) { 17 | return; 18 | } 19 | 20 | $definition = $container->getDefinition('liip_monitor.runner'); 21 | $container->removeDefinition('liip_monitor.runner'); 22 | 23 | $defaultGroup = $container->getParameter('liip_monitor.default_group'); 24 | 25 | $checkServices = $container->findTaggedServiceIds('liip_monitor.check'); 26 | $checkCollectionServices = $container->findTaggedServiceIds('liip_monitor.check_collection'); 27 | 28 | $groups = array_merge( 29 | [$defaultGroup], 30 | $this->getGroups($checkServices), 31 | $this->getGroups($checkCollectionServices), 32 | $this->getGroupsFromParameter($container) 33 | ); 34 | $groups = array_unique($groups); 35 | 36 | $runners = []; 37 | foreach ($groups as $group) { 38 | $container->setDefinition('liip_monitor.runner_'.$group, clone $definition); 39 | $container->registerAliasForArgument('liip_monitor.runner_'.$group, Runner::class, $group.'Runner'); 40 | $runners[] = 'liip_monitor.runner_'.$group; 41 | } 42 | 43 | $container->setAlias('liip_monitor.runner', 'liip_monitor.runner_'.$defaultGroup); 44 | $container->setAlias(Runner::class, 'liip_monitor.runner'); 45 | $runner = $container->getAlias('liip_monitor.runner'); 46 | $runner->setPublic(true); 47 | 48 | $container->setParameter('liip_monitor.runners', $runners); 49 | } 50 | 51 | private function getGroups(array $services): array 52 | { 53 | $groups = []; 54 | foreach ($services as $tags) { 55 | foreach ($tags as $attributes) { 56 | if (!empty($attributes['group'])) { 57 | $groups[$attributes['group']] = true; 58 | } 59 | } 60 | } 61 | 62 | return array_keys($groups); 63 | } 64 | 65 | private function getGroupsFromParameter(ContainerBuilder $container): array 66 | { 67 | $groups = []; 68 | 69 | if ($container->hasParameter('liip_monitor.checks')) { 70 | $checks = $container->getParameter('liip_monitor.checks'); 71 | foreach (array_keys($checks['groups']) as $group) { 72 | $groups[] = $group; 73 | } 74 | } 75 | 76 | return $groups; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/MailerCompilerPass.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class MailerCompilerPass implements CompilerPassInterface 15 | { 16 | public function process(ContainerBuilder $container): void 17 | { 18 | if (false === $container->hasParameter('liip_monitor.mailer.enabled')) { 19 | return; 20 | } 21 | 22 | if (false === $container->getParameter('liip_monitor.mailer.enabled')) { 23 | return; 24 | } 25 | 26 | try { 27 | $definition = $container->findDefinition('mailer'); 28 | } catch (ServiceNotFoundException $e) { 29 | throw new \InvalidArgumentException('To enable mail reporting you have to install the "swiftmailer/swiftmailer" or "symfony/mailer".'); 30 | } 31 | 32 | $filename = \Swift_Mailer::class !== $definition->getClass() ? 'symfony_mailer.xml' : 'swift_mailer.xml'; 33 | 34 | $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../../Resources/config')); 35 | $loader->load($filename); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /DependencyInjection/DoctrineMigrations/AbstractDoctrineMigrationsLoader.php: -------------------------------------------------------------------------------- 1 | loader = class_exists(DoctrineCommand::class) 27 | ? new V2MigrationsLoader() 28 | : new V3MigrationsLoader(); 29 | } 30 | 31 | public function process(ContainerBuilder $container): void 32 | { 33 | if (!($this->loader instanceof CompilerPassInterface)) { 34 | return; 35 | } 36 | 37 | $this->loader->process($container); 38 | } 39 | 40 | public function loadMigrationChecks(ContainerBuilder $container, array $migrationChecksConfig, string $groupName): array 41 | { 42 | $services = []; 43 | foreach ($migrationChecksConfig as $key => $config) { 44 | try { 45 | $serviceId = sprintf('liip_monitor.check.doctrine_migrations.configuration.%s.%s', $groupName, $key); 46 | $this->loader->createMigrationConfigurationService( 47 | $container, 48 | $config['connection'], 49 | $serviceId, 50 | $config['configuration_file'] ?? null 51 | ); 52 | 53 | $services[$key] = $serviceId; 54 | } catch (\Exception $e) { 55 | throw new \RuntimeException(sprintf('Invalid doctrine migration check under "%s.%s": %s', $groupName, $key, $e->getMessage()), $e->getCode(), $e); 56 | } 57 | } 58 | 59 | return $services; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | // symfony3 does not define templating.helper.assets unless php templating is included 58 | if ($container->has('templating.helper.assets')) { 59 | $pathHelper = $container->getDefinition('liip_monitor.helper'); 60 | $pathHelper->replaceArgument(0, 'templating.helper.assets'); 61 | } 62 | 63 | // symfony3 does not define templating.helper.router unless php templating is included 64 | if ($container->has('templating.helper.router')) { 65 | $pathHelper = $container->getDefinition('liip_monitor.helper'); 66 | $pathHelper->replaceArgument(1, 'templating.helper.router'); 67 | } 68 | 69 | if (empty($config['checks'])) { 70 | return; 71 | } 72 | 73 | $checksLoaded = []; 74 | $containerParams = []; 75 | foreach ($config['checks']['groups'] as $group => $checks) { 76 | if (empty($checks)) { 77 | continue; 78 | } 79 | 80 | foreach ($checks as $check => $values) { 81 | if (empty($values)) { 82 | continue; 83 | } 84 | 85 | $containerParams['groups'][$group][$check] = $values; 86 | $this->setParameters($container, $check, $group, $values); 87 | 88 | if (!in_array($check, $checksLoaded)) { 89 | $loader->load('checks/'.$check.'.xml'); 90 | $checksLoaded[] = $check; 91 | } 92 | } 93 | } 94 | 95 | $container->setParameter(sprintf('%s.checks', $this->getAlias()), $containerParams); 96 | $this->configureDoctrineMigrationsCheck($container, $containerParams); 97 | } 98 | 99 | public function process(ContainerBuilder $container): void 100 | { 101 | $this->migrationsLoader->process($container); 102 | } 103 | 104 | /** 105 | * @param string $checkName 106 | * @param string $group 107 | * @param array $values 108 | */ 109 | private function setParameters(ContainerBuilder $container, $checkName, $group, $values): void 110 | { 111 | $prefix = sprintf('%s.check.%s', $this->getAlias(), $checkName); 112 | switch ($checkName) { 113 | case 'class_exists': 114 | case 'cpu_performance': 115 | case 'php_extensions': 116 | case 'php_version': 117 | case 'php_flags': 118 | case 'readable_directory': 119 | case 'writable_directory': 120 | case 'process_running': 121 | case 'doctrine_dbal': 122 | case 'doctrine_mongodb': 123 | case 'http_service': 124 | case 'guzzle_http_service': 125 | case 'memcache': 126 | case 'memcached': 127 | case 'redis': 128 | case 'rabbit_mq': 129 | case 'stream_wrapper_exists': 130 | case 'file_ini': 131 | case 'file_json': 132 | case 'file_xml': 133 | case 'file_yaml': 134 | case 'expressions': 135 | case 'pdo_connections': 136 | case 'messenger_transports': 137 | $container->setParameter($prefix.'.'.$group, $values); 138 | break; 139 | case 'symfony_version': 140 | case 'opcache_memory': 141 | break; 142 | 143 | case 'doctrine_migrations': 144 | if (!class_exists(DoctrineMigrationConfiguration::class)) { 145 | throw new \InvalidArgumentException('Please require at least "v2.0.0" of "Doctrine Migrations Library"'); 146 | } 147 | 148 | $container->setParameter($prefix.'.'.$group, $values); 149 | break; 150 | } 151 | 152 | if (is_array($values)) { 153 | foreach ($values as $key => $value) { 154 | $container->setParameter($prefix.'.'.$key.'.'.$group, $value); 155 | } 156 | } 157 | } 158 | 159 | /** 160 | * Set up doctrine migration configuration services. 161 | * 162 | * @param ContainerBuilder $container The container 163 | * @param array $params Container params 164 | */ 165 | private function configureDoctrineMigrationsCheck(ContainerBuilder $container, array $params): void 166 | { 167 | if (!$container->hasDefinition('liip_monitor.check.doctrine_migrations') || !isset($params['groups'])) { 168 | return; 169 | } 170 | 171 | foreach ($params['groups'] as $groupName => $groupChecks) { 172 | if (!isset($groupChecks['doctrine_migrations'])) { 173 | continue; 174 | } 175 | 176 | $services = $this->migrationsLoader->loadMigrationChecks( 177 | $container, 178 | $groupChecks['doctrine_migrations'], 179 | $groupName 180 | ); 181 | 182 | $parameter = sprintf('%s.check.%s.%s', $this->getAlias(), 'doctrine_migrations', $groupName); 183 | $container->setParameter($parameter, $services); 184 | } 185 | } 186 | 187 | private function configureMailer(ContainerBuilder $container, array $config): void 188 | { 189 | if (false === $config['mailer']['enabled']) { 190 | return; 191 | } 192 | 193 | foreach ($config['mailer'] as $key => $value) { 194 | $container->setParameter(sprintf('%s.mailer.%s', $this->getAlias(), $key), $value); 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /DoctrineMigrations/Configuration.php: -------------------------------------------------------------------------------- 1 | container = $container; 36 | } 37 | 38 | /** 39 | * Tune this configuration parameters according to migrations bundle. 40 | */ 41 | public function configure(): void 42 | { 43 | if (null === self::$haveMigrationBundle) { 44 | self::$haveMigrationBundle = class_exists(DoctrineCommand::class); 45 | } 46 | 47 | if (!self::$haveMigrationBundle) { 48 | return; 49 | } 50 | 51 | DoctrineCommand::configureMigrations($this->container, $this); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Helper/AbstractMailReporter.php: -------------------------------------------------------------------------------- 1 | recipients = $recipients; 38 | $this->sender = $sender; 39 | $this->subject = $subject; 40 | $this->sendOnWarning = $sendOnWarning; 41 | } 42 | 43 | /** 44 | * @return void 45 | */ 46 | public function onStart(\ArrayObject $checks, $runnerConfig) 47 | { 48 | } 49 | 50 | /** 51 | * @return bool|void 52 | */ 53 | public function onBeforeRun(CheckInterface $check, $checkAlias = null) 54 | { 55 | } 56 | 57 | /** 58 | * @return bool|void 59 | */ 60 | public function onAfterRun(CheckInterface $check, ResultInterface $result, $checkAlias = null) 61 | { 62 | } 63 | 64 | /** 65 | * @return void 66 | */ 67 | public function onStop(ResultsCollection $results) 68 | { 69 | } 70 | 71 | /** 72 | * @return void 73 | */ 74 | public function onFinish(ResultsCollection $results) 75 | { 76 | if ($results->getUnknownCount() > 0) { 77 | $this->sendEmail($results); 78 | 79 | return; 80 | } 81 | 82 | if ($results->getWarningCount() > 0 && $this->sendOnWarning) { 83 | $this->sendEmail($results); 84 | 85 | return; 86 | } 87 | 88 | if ($results->getFailureCount() > 0) { 89 | $this->sendEmail($results); 90 | 91 | return; 92 | } 93 | } 94 | 95 | abstract protected function sendEmail(ResultsCollection $results): void; 96 | } 97 | -------------------------------------------------------------------------------- /Helper/ArrayReporter.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class ArrayReporter implements ReporterInterface 17 | { 18 | public const STATUS_OK = 'OK'; 19 | public const STATUS_KO = 'KO'; 20 | 21 | private $globalStatus = self::STATUS_OK; 22 | private $results = []; 23 | private $checkRunTime = 0; 24 | 25 | public function getResults(): array 26 | { 27 | return $this->results; 28 | } 29 | 30 | public function getGlobalStatus(): string 31 | { 32 | return $this->globalStatus; 33 | } 34 | 35 | /** 36 | * @return bool|void 37 | */ 38 | public function onAfterRun(CheckInterface $check, ResultInterface $result, $checkAlias = null) 39 | { 40 | switch (true) { 41 | case $result instanceof SuccessInterface: 42 | $status = 0; 43 | $statusName = 'check_result_ok'; 44 | break; 45 | 46 | case $result instanceof WarningInterface: 47 | $status = 1; 48 | $statusName = 'check_result_warning'; 49 | $this->globalStatus = self::STATUS_KO; 50 | break; 51 | 52 | case $result instanceof SkipInterface: 53 | $status = 2; 54 | $statusName = 'check_result_skip'; 55 | break; 56 | 57 | default: 58 | $status = 3; 59 | $statusName = 'check_result_critical'; 60 | $this->globalStatus = self::STATUS_KO; 61 | } 62 | 63 | $this->results[] = [ 64 | 'checkName' => $check->getLabel(), 65 | 'message' => $result->getMessage(), 66 | 'status' => $status, 67 | 'status_name' => $statusName, 68 | 'service_id' => $checkAlias, 69 | 'duration' => microtime(true) - $this->checkRunTime, 70 | ]; 71 | } 72 | 73 | /** 74 | * @return void 75 | */ 76 | public function onStart(\ArrayObject $checks, $runnerConfig) 77 | { 78 | return; 79 | } 80 | 81 | /** 82 | * @return bool|void 83 | */ 84 | public function onBeforeRun(CheckInterface $check, $checkAlias = null) 85 | { 86 | $this->checkRunTime = microtime(true); 87 | } 88 | 89 | /** 90 | * @return void 91 | */ 92 | public function onStop(ResultsCollection $results) 93 | { 94 | return; 95 | } 96 | 97 | /** 98 | * @return void 99 | */ 100 | public function onFinish(ResultsCollection $results) 101 | { 102 | return; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Helper/ConsoleReporter.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | class ConsoleReporter implements ReporterInterface 19 | { 20 | /** 21 | * @var OutputInterface 22 | */ 23 | protected $output; 24 | 25 | public function __construct(?OutputInterface $output = null) 26 | { 27 | if (null === $output) { 28 | $output = new ConsoleOutput(); 29 | } 30 | $this->output = $output; 31 | } 32 | 33 | public function setOutput(OutputInterface $output): void 34 | { 35 | $this->output = $output; 36 | } 37 | 38 | /** 39 | * @return bool|void 40 | */ 41 | public function onAfterRun(CheckInterface $check, ResultInterface $result, $checkAlias = null) 42 | { 43 | switch (true) { 44 | case $result instanceof SuccessInterface: 45 | $this->output->write('OK'); 46 | break; 47 | 48 | case $result instanceof WarningInterface: 49 | $this->output->write('WARNING'); 50 | break; 51 | 52 | case $result instanceof SkipInterface: 53 | $this->output->write('SKIP'); 54 | break; 55 | 56 | default: 57 | $this->output->write('FAIL'); 58 | } 59 | 60 | $this->output->write(sprintf(' %s', $check->getLabel())); 61 | 62 | if ($message = $result->getMessage()) { 63 | $this->output->write(sprintf(': %s', $message)); 64 | } 65 | 66 | $this->output->writeln(''); 67 | } 68 | 69 | /** 70 | * @return void 71 | */ 72 | public function onStart(\ArrayObject $checks, $runnerConfig) 73 | { 74 | return; 75 | } 76 | 77 | /** 78 | * @return bool|void 79 | */ 80 | public function onBeforeRun(CheckInterface $check, $checkAlias = null) 81 | { 82 | return; 83 | } 84 | 85 | /** 86 | * @return void 87 | */ 88 | public function onStop(ResultsCollection $results) 89 | { 90 | return; 91 | } 92 | 93 | /** 94 | * @return void 95 | */ 96 | public function onFinish(ResultsCollection $results) 97 | { 98 | return; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Helper/PathHelper.php: -------------------------------------------------------------------------------- 1 | assetsHelper = $assetsHelper; 13 | $this->routerHelper = $routerHelper; 14 | } 15 | 16 | public function generateRoutes(array $routes): array 17 | { 18 | $ret = []; 19 | 20 | if (!method_exists($this->routerHelper, 'path')) { 21 | // symfony 2.7 and lower don't have the path method, BC layer 22 | foreach ($routes as $route => $params) { 23 | $ret[] = sprintf('api.%s = "%s";', $route, $this->routerHelper->generate($route, $params)); 24 | } 25 | 26 | return $ret; 27 | } 28 | 29 | foreach ($routes as $route => $params) { 30 | $ret[] = sprintf('api.%s = "%s";', $route, $this->routerHelper->path($route, $params)); 31 | } 32 | 33 | return $ret; 34 | } 35 | 36 | public function getRoutesJs(array $routes): string 37 | { 38 | $script = ''; 42 | 43 | return $script; 44 | } 45 | 46 | /** 47 | * @param string[] $paths 48 | */ 49 | public function getScriptTags(array $paths): string 50 | { 51 | $ret = ''; 52 | foreach ($paths as $path) { 53 | $ret .= sprintf('%s', $this->assetsHelper->getUrl($path), "\n"); 54 | } 55 | 56 | return $ret; 57 | } 58 | 59 | /** 60 | * @param string[] $paths 61 | */ 62 | public function getStyleTags(array $paths): string 63 | { 64 | $ret = ''; 65 | foreach ($paths as $path) { 66 | $ret .= sprintf('%s', $this->assetsHelper->getUrl($path), "\n"); 67 | } 68 | 69 | return $ret; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Helper/RawConsoleReporter.php: -------------------------------------------------------------------------------- 1 | output = $output; 31 | } 32 | 33 | public function setOutput(OutputInterface $output): void 34 | { 35 | $this->output = $output; 36 | } 37 | 38 | /** 39 | * @return bool|void 40 | */ 41 | public function onAfterRun(CheckInterface $check, ResultInterface $result, $checkAlias = null) 42 | { 43 | switch (true) { 44 | case $result instanceof SuccessInterface: 45 | $this->output->write('OK'); 46 | break; 47 | 48 | case $result instanceof WarningInterface: 49 | $this->output->write('WARNING'); 50 | break; 51 | 52 | case $result instanceof SkipInterface: 53 | $this->output->write('SKIP'); 54 | break; 55 | 56 | default: 57 | $this->output->write('FAIL'); 58 | } 59 | 60 | $performanceData = $this->getNagiosPerformanceData(); 61 | 62 | $this->output->writeln(sprintf(' %s', $check->getLabel().$performanceData)); 63 | } 64 | 65 | protected function getNagiosPerformanceData(): string 66 | { 67 | return ''; 68 | } 69 | 70 | /** 71 | * @return void 72 | */ 73 | public function onStart(\ArrayObject $checks, $runnerConfig) 74 | { 75 | return; 76 | } 77 | 78 | /** 79 | * @return bool|void 80 | */ 81 | public function onBeforeRun(CheckInterface $check, $checkAlias = null) 82 | { 83 | return; 84 | } 85 | 86 | /** 87 | * @return void 88 | */ 89 | public function onStop(ResultsCollection $results) 90 | { 91 | return; 92 | } 93 | 94 | /** 95 | * @return void 96 | */ 97 | public function onFinish(ResultsCollection $results) 98 | { 99 | return; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Helper/RunnerManager.php: -------------------------------------------------------------------------------- 1 | container = $container; 16 | } 17 | 18 | /** 19 | * @param string|null $group 20 | */ 21 | public function getRunner($group): ?Runner 22 | { 23 | $runnerServiceId = $this->getRunnerServiceId($group); 24 | 25 | return $runnerServiceId ? $this->container->get($runnerServiceId) : null; 26 | } 27 | 28 | /** 29 | * @return array|Runner[] key/value $group/$runner 30 | */ 31 | public function getRunners(): array 32 | { 33 | $runnerServiceIds = $this->container->getParameter('liip_monitor.runners'); 34 | 35 | $runners = []; 36 | 37 | foreach ($runnerServiceIds as $serviceId) { 38 | if (preg_match('/liip_monitor.runner_(.+)/', $serviceId, $matches)) { 39 | $runners[$matches[1]] = $this->container->get($serviceId); 40 | } 41 | } 42 | 43 | return $runners; 44 | } 45 | 46 | /** 47 | * @return array|string[] 48 | */ 49 | public function getGroups(): array 50 | { 51 | $runnerServiceIds = $this->container->getParameter('liip_monitor.runners'); 52 | 53 | $groups = []; 54 | 55 | foreach ($runnerServiceIds as $serviceId) { 56 | if (preg_match('/liip_monitor.runner_(.+)/', $serviceId, $matches)) { 57 | $groups[] = $matches[1]; 58 | } 59 | } 60 | 61 | return $groups; 62 | } 63 | 64 | public function getDefaultGroup(): string 65 | { 66 | return $this->container->getParameter('liip_monitor.default_group'); 67 | } 68 | 69 | /** 70 | * @param string|null $group 71 | */ 72 | private function getRunnerServiceId($group): ?string 73 | { 74 | if (null === $group) { 75 | $group = $this->getDefaultGroup(); 76 | } 77 | 78 | $runnerServiceId = 'liip_monitor.runner_'.$group; 79 | 80 | return $this->container->has($runnerServiceId) ? $runnerServiceId : null; 81 | } 82 | 83 | public function getReporters(): array 84 | { 85 | $runners = $this->getRunners(); 86 | $reporters = []; 87 | 88 | foreach ($runners as $runner) { 89 | $reporters += array_keys($runner->getReporters() + $runner->getAdditionalReporters()); 90 | } 91 | 92 | return $reporters; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Helper/SwiftMailerReporter.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class SwiftMailerReporter extends AbstractMailReporter 13 | { 14 | private $mailer; 15 | 16 | /** 17 | * @param string|array $recipients 18 | * @param string $sender 19 | * @param string $subject 20 | * @param bool $sendOnWarning 21 | */ 22 | public function __construct(\Swift_Mailer $mailer, $recipients, $sender, $subject, $sendOnWarning = true) 23 | { 24 | $this->mailer = $mailer; 25 | 26 | parent::__construct($recipients, $sender, $subject, $sendOnWarning); 27 | } 28 | 29 | protected function sendEmail(ResultsCollection $results): void 30 | { 31 | $body = ''; 32 | 33 | foreach ($results as $check) { 34 | /* @var $check CheckInterface */ 35 | /* @var $result ResultInterface */ 36 | $result = $results[$check] ?? null; 37 | 38 | if ($result instanceof ResultInterface) { 39 | $body .= sprintf("Check: %s\n", $check->getLabel()); 40 | $body .= sprintf("Message: %s\n\n", $result->getMessage()); 41 | } 42 | } 43 | 44 | $message = (new \Swift_Message()) 45 | ->setSubject($this->subject) 46 | ->setFrom($this->sender) 47 | ->setTo($this->recipients) 48 | ->setBody($body); 49 | 50 | $this->mailer->send($message); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Helper/SymfonyMailerReporter.php: -------------------------------------------------------------------------------- 1 | mailer = $mailer; 21 | 22 | parent::__construct($recipients, $sender, $subject, $sendOnWarning); 23 | } 24 | 25 | protected function sendEmail(ResultsCollection $results): void 26 | { 27 | $body = ''; 28 | 29 | foreach ($results as $check) { 30 | /* @var $check CheckInterface */ 31 | /* @var $result ResultInterface */ 32 | $result = $results[$check] ?? null; 33 | 34 | if ($result instanceof ResultInterface) { 35 | $body .= sprintf('[%s] %s', $check->getLabel(), $result->getMessage()); 36 | } 37 | } 38 | 39 | $message = (new Email()) 40 | ->subject($this->subject) 41 | ->from($this->sender) 42 | ->to(...$this->recipients) 43 | ->text($body); 44 | 45 | $this->mailer->send($message); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /LiipMonitorBundle.php: -------------------------------------------------------------------------------- 1 | registerForAutoconfiguration(CheckInterface::class) 22 | ->addTag('liip_monitor.check'); 23 | } 24 | 25 | $container->addCompilerPass(new CheckAssetsEnabledPass()); 26 | $container->addCompilerPass(new AddGroupsCompilerPass()); 27 | $container->addCompilerPass(new GroupRunnersCompilerPass()); 28 | $container->addCompilerPass(new CheckTagCompilerPass()); 29 | $container->addCompilerPass(new CheckCollectionTagCompilerPass()); 30 | $container->addCompilerPass(new AdditionalReporterCompilerPass()); 31 | $container->addCompilerPass(new MailerCompilerPass()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Resources/config/checks/apc_fragmentation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.apc_fragmentation.warning%% 10 | %%liip_monitor.check.apc_fragmentation.critical%% 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/config/checks/apc_memory.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.apc_memory.warning%% 10 | %%liip_monitor.check.apc_memory.critical%% 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/config/checks/class_exists.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.class_exists%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/cpu_performance.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.cpu_performance%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/custom_error_pages.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.custom_error_pages.error_codes%% 10 | %%liip_monitor.check.custom_error_pages.path%% 11 | %kernel.project_dir% 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Resources/config/checks/disk_usage.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.disk_usage.warning%% 10 | %%liip_monitor.check.disk_usage.critical%% 11 | %%liip_monitor.check.disk_usage.path%% 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Resources/config/checks/doctrine_dbal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | %%liip_monitor.check.doctrine_dbal%% 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/config/checks/doctrine_migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 10 | 11 | %%liip_monitor.check.doctrine_migrations%% 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Resources/config/checks/doctrine_mongodb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | %%liip_monitor.check.doctrine_mongodb%% 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/config/checks/expressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.expressions%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/file_ini.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | File (INI) 9 | 10 | 11 | 12 | 13 | %%liip_monitor.check.file_ini%% 14 | 15 | %liip_monitor.check.file_ini.label% 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Resources/config/checks/file_json.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | File (JSON) 9 | 10 | 11 | 12 | 13 | %%liip_monitor.check.file_json%% 14 | 15 | %liip_monitor.check.file_json.label% 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Resources/config/checks/file_xml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | File (XML) 9 | 10 | 11 | 12 | 13 | %%liip_monitor.check.file_xml%% 14 | 15 | %liip_monitor.check.file_xml.label% 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Resources/config/checks/file_yaml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | File (YAML) 9 | 10 | 11 | 12 | 13 | %%liip_monitor.check.file_yaml%% 14 | 15 | %liip_monitor.check.file_yaml.label% 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Resources/config/checks/guzzle_http_service.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.guzzle_http_service%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/http_service.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.http_service%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/memcache.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.memcache%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/memcached.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.memcached%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/messenger_transports.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | %%liip_monitor.check.messenger_transports%% 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/config/checks/opcache_memory.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.opcache_memory.warning%% 10 | %%liip_monitor.check.opcache_memory.critical%% 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/config/checks/pdo_connections.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.pdo_connections%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/php_extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.php_extensions%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/php_flags.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.php_flags%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/php_version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.php_version%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/process_running.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.process_running%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/rabbit_mq.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.rabbit_mq%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/readable_directory.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.readable_directory%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/redis.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.redis%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/security_advisory.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.security_advisory.lock_file%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/stream_wrapper_exists.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.stream_wrapper_exists%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/symfony_requirements.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.symfony_requirements.file%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/checks/symfony_version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Resources/config/checks/writable_directory.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %%liip_monitor.check.writable_directory%% 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/config/commands.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Resources/config/controller.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | %liip_monitor.view_template% 19 | %liip_monitor.failure_status_code% 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Resources/config/helper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/config/routing.php: -------------------------------------------------------------------------------- 1 | addCollection( 7 | $loader->import('@LiipMonitorBundle/Resources/config/routing.xml') 8 | ); 9 | 10 | return $routes; 11 | -------------------------------------------------------------------------------- /Resources/config/routing.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Liip\MonitorBundle\Controller\HealthCheckController::indexAction 8 | 9 | 10 | Liip\MonitorBundle\Controller\HealthCheckController::listAction 11 | 12 | 13 | Liip\MonitorBundle\Controller\HealthCheckController::listAllAction 14 | 15 | 16 | Liip\MonitorBundle\Controller\HealthCheckController::listGroupsAction 17 | 18 | 19 | Liip\MonitorBundle\Controller\HealthCheckController::runAllChecksHttpStatusAction 20 | 21 | 22 | Liip\MonitorBundle\Controller\HealthCheckController::runSingleCheckHttpStatusAction 23 | 24 | 25 | Liip\MonitorBundle\Controller\HealthCheckController::runAllChecksAction 26 | 27 | 28 | Liip\MonitorBundle\Controller\HealthCheckController::runSingleCheckAction 29 | 30 | 31 | Liip\MonitorBundle\Controller\HealthCheckController::listReportersAction 32 | 33 | 34 | -------------------------------------------------------------------------------- /Resources/config/runner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | r 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/config/swift_mailer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | %liip_monitor.mailer.recipient% 12 | %liip_monitor.mailer.sender% 13 | %liip_monitor.mailer.subject% 14 | %liip_monitor.mailer.send_on_warning% 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Resources/config/symfony_mailer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | %liip_monitor.mailer.recipient% 12 | %liip_monitor.mailer.sender% 13 | %liip_monitor.mailer.subject% 14 | %liip_monitor.mailer.send_on_warning% 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Resources/doc/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liip/LiipMonitorBundle/f0a398b572d603cda499d7dc547da8ee09efb3cf/Resources/doc/screenshot.png -------------------------------------------------------------------------------- /Resources/meta/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Liip AG 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Resources/public/css/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liip/LiipMonitorBundle/f0a398b572d603cda499d7dc547da8ee09efb3cf/Resources/public/css/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /Resources/public/css/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liip/LiipMonitorBundle/f0a398b572d603cda499d7dc547da8ee09efb3cf/Resources/public/css/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /Resources/public/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 2em; 3 | } 4 | 5 | h1 { 6 | margin-bottom: 0.5em; 7 | } 8 | 9 | table.test-result { 10 | font-family: helvetica; 11 | font-size: 16px; 12 | color: black; 13 | margin: 0 auto; 14 | width: 100%; 15 | } 16 | 17 | th { 18 | font-size: 16px; 19 | background: gray; 20 | } 21 | 22 | .check_result_ok { 23 | color: #000000; 24 | background: #65BF2A; 25 | } 26 | 27 | .check_result_warning { 28 | color: #000000; 29 | background: #ffcc00; 30 | } 31 | 32 | .check_result_critical { 33 | color: #000000; 34 | background: #FF3D3D; 35 | } 36 | 37 | .check_result_unknown { 38 | color: #000000; 39 | background: #999999; 40 | } 41 | 42 | .table tbody tr.check_result_warning:hover td { 43 | background: #FDFF87; 44 | } 45 | 46 | .table tbody tr.check_result_critical:hover td { 47 | background: #FF9D7D; 48 | } 49 | 50 | .table tbody tr.check_result_unknown:hover td { 51 | background: #999999; 52 | } 53 | 54 | .table tbody tr:hover td, .table tbody tr:hover th { 55 | background-color: #D1F2A5; 56 | } 57 | 58 | #info { 59 | margin-top: 2em; 60 | } 61 | 62 | dd pre { 63 | margin-top: 0.5em; 64 | } 65 | 66 | dd dl dt, dd dl dd { 67 | padding: 0.3em; 68 | } 69 | 70 | button { 71 | width: 100%; 72 | } 73 | -------------------------------------------------------------------------------- /Resources/public/javascript/app.js: -------------------------------------------------------------------------------- 1 | var Health = Em.Application.create( { 2 | ready: function() { 3 | Health.ResultView.appendTo('#container'); 4 | Health.healthController.runChecks(); 5 | } 6 | }); 7 | 8 | Health.Check = Em.Object.extend({ 9 | checkName: null, 10 | message: null, 11 | status: false, 12 | service_id: null, 13 | 14 | icon: function() { 15 | if (this.status_name === "check_result_ok") { 16 | return "icon-ok-sign"; 17 | } 18 | 19 | if (this.status_name === "check_result_warning") { 20 | return "icon-warning-sign"; 21 | } 22 | 23 | if (this.status_name === "check_result_critical") { 24 | return "icon-fire"; 25 | } 26 | 27 | if (this.status_name === "check_result_unknown") { 28 | return "icon-question-sign"; 29 | } 30 | 31 | return "icon-exclamation-sign"; 32 | }.property('status_name'), 33 | 34 | runUrl: function() { 35 | return api.liip_monitor_run_single_check.replace('replaceme', this.service_id); 36 | }.property('checkName') 37 | }); 38 | 39 | Health.healthController = Em.ArrayProxy.create({ 40 | 41 | content: [], 42 | 43 | runChecks: function() { 44 | var self = this; 45 | jQuery.ajax({ 46 | url: api.liip_monitor_run_all_checks, 47 | type: 'POST', 48 | dataType: 'json', 49 | success: function(data) { 50 | var checks = data.checks.map(function(item) { 51 | return Health.Check.create(item); 52 | }); 53 | self.set('content', checks); 54 | }, 55 | error: function() { 56 | console.log("error while loading health checks"); 57 | } 58 | }); 59 | }, 60 | 61 | repeatCheck: function(check) { 62 | var self = this; 63 | $.ajax({ 64 | url: check.get('runUrl'), 65 | type: 'POST', 66 | dataType: 'json', 67 | success: function(data) { 68 | var updatedCheck = Health.Check.create(data); 69 | var idx = self._findItemIndex(check); 70 | if (idx > -1) { 71 | Health.healthController.replaceContent(self._findItemIndex(check), 1, [updatedCheck]); 72 | } else { 73 | console.log('item is not part of the content collection'); 74 | } 75 | }, 76 | error: function() { 77 | console.log("error while running health check"); 78 | } 79 | }); 80 | }, 81 | 82 | _findItemIndex: function(check) { 83 | var len = this.content.get('length'); 84 | var last = null, next, found = false, ret = -1; 85 | 86 | for(var idx=0; idx undef, 31 | u => undef, 32 | A => undef, 33 | p => undef, 34 | w => 1, 35 | c => 1, 36 | ); 37 | getopts 'H:A:u:p:w:c', \%opts; 38 | die "Missing (-H or -A)\n" unless ($opts{H} or $opts{A}); 39 | 40 | my $java="
"; 41 | my $htmldivide="+
"; 42 | my $htmlend="
"; 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 .= "
${totalnumber}
$_->{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 | -------------------------------------------------------------------------------- /Resources/scripts/check_symfony2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import nagiosplugin 4 | 5 | import urllib2 6 | import simplejson 7 | 8 | """ 9 | 10 | A simple check script for use with LiipMonitorBundle to monitor symfony apps. 11 | 12 | Usage: 13 | 14 | 1. Place the script in your nagios plugin dir (or define a custom one) 15 | 16 | 2. Nagios config: 17 | define command{ 18 | command_name check_symfony_health 19 | command_line $USER1$/check_symfony2.py -w 0 -c 0 -u https://$HOSTNAME$ 20 | } 21 | 22 | 3. Restart nagios. 23 | 24 | 4. Profit. 25 | 26 | 5. Forgo profit as you just realized you are missing the nagiosplugin module. 27 | 28 | To remedy the situation, do: 29 | pip install nagiosplugin 30 | 31 | 32 | Author: Tarjei Huse, tarjei.huse@gmail.com 33 | 34 | """ 35 | 36 | class Symfony2Check(nagiosplugin.Check): 37 | name = "Symfony2 health check" 38 | version = "1.0" 39 | 40 | def __init__(self, optparser, logger): 41 | self.log = logger 42 | optparser.description = 'Health check of Symfony2 application' 43 | optparser.version = '1.0' 44 | optparser.add_option( 45 | '-w', '--warning', default='1', metavar='RANGE', 46 | help='warning threshold (default: %default%)') 47 | optparser.add_option( 48 | '-c', '--critical', default='1', metavar='RANGE', 49 | help='warning threshold (default: %default%)') 50 | optparser.add_option( 51 | '-u', '--url', help='Url to check') 52 | optparser.add_option( 53 | '-a', '--auth', help='Authentication', default=None) 54 | 55 | 56 | def process_args(self, options, args): 57 | self.warning = options.warning.rstrip('%') 58 | self.critical = options.critical.rstrip('%') 59 | if not options.url: 60 | raise Exception("Missing url option") 61 | self.url = options.url.strip() + "/monitor/health/run" 62 | self.hostUrl = options.url.strip() 63 | if options.auth is not None: 64 | self.username, self.password = options.auth.split(":") 65 | else: 66 | self.username = None 67 | 68 | def obtain_data(self): 69 | self.badChecks = [] 70 | try: 71 | content = self.fetch(self.url) 72 | json = simplejson.loads(content) 73 | 74 | if json['globalStatus'] is not 'OK': 75 | self.badChecks = [] 76 | for check in json['checks']: 77 | if check['status']: 78 | self.badChecks.append(check["checkName"]) 79 | 80 | except Exception, e: 81 | self.log.warn("Could not connect to url: " + self.url +" res:" + str(e)) 82 | self.badChecks.append("config_error_in_nagios") 83 | 84 | self.measures = [nagiosplugin.Measure("Num_failed_checks", len(self.badChecks), warning=self.warning, critical=self.critical, minimum=0 )] 85 | 86 | 87 | def default_message(self): 88 | if len(self.badChecks): 89 | return "The following checks failed: %s" % (", ".join(self.badChecks)) 90 | return "All checks pass." 91 | 92 | 93 | def fetch(self, url): 94 | if self.username is not None: 95 | passman = urllib2.HTTPPasswordMgrWithDefaultRealm() 96 | # this creates a password manager 97 | passman.add_password(None, url, self.username, self.password) 98 | authhandler = urllib2.HTTPBasicAuthHandler(passman) 99 | opener = urllib2.build_opener(authhandler) 100 | urllib2.install_opener(opener) 101 | handle = urllib2.urlopen(url) 102 | data = handle.read() 103 | return data 104 | 105 | 106 | main = nagiosplugin.Controller(Symfony2Check) 107 | if __name__ == '__main__': 108 | main() 109 | -------------------------------------------------------------------------------- /Runner.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class Runner extends BaseRunner 12 | { 13 | private $additionalReporters = []; 14 | 15 | /** 16 | * @param string $alias 17 | */ 18 | public function addAdditionalReporter($alias, ReporterInterface $reporter): void 19 | { 20 | $this->additionalReporters[$alias] = $reporter; 21 | } 22 | 23 | public function useAdditionalReporters(array $aliases): void 24 | { 25 | foreach ($this->additionalReporters as $alias => $reporter) { 26 | if (in_array($alias, $aliases)) { 27 | $this->addReporter($reporter); 28 | } 29 | } 30 | } 31 | 32 | public function getAdditionalReporters(): array 33 | { 34 | return $this->additionalReporters; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/Check/ExpressionTest.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class ExpressionTest extends \PHPUnit\Framework\TestCase 15 | { 16 | /** 17 | * @dataProvider checkResultProvider 18 | */ 19 | public function testCheckResult($warningCheck, $criticalCheck, $warningMessage, $criticalMessage, $expectedResultClass, $expectedMessage): void 20 | { 21 | $check = new Expression('foo', $warningCheck, $criticalCheck, $warningMessage, $criticalMessage); 22 | $this->assertSame('foo', $check->getLabel()); 23 | 24 | $result = $check->check(); 25 | $this->assertInstanceOf(ResultInterface::class, $result); 26 | $this->assertInstanceOf($expectedResultClass, $result); 27 | $this->assertSame($expectedMessage, $result->getMessage()); 28 | } 29 | 30 | public function checkResultProvider(): array 31 | { 32 | return [ 33 | ['true', 'true', null, null, Success::class, ''], 34 | ['false', 'true', 'warning', 'fail', Warning::class, 'warning'], 35 | ['true', 'false', 'warning', 'fail', Failure::class, 'fail'], 36 | ['false', 'false', 'warning', 'fail', Failure::class, 'fail'], 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Tests/Check/RedisCollectionTest.php: -------------------------------------------------------------------------------- 1 | $dsn, 22 | 'host' => 'localhost', 23 | 'port' => 6379, 24 | 'password' => null, 25 | ]; 26 | 27 | $collection = new RedisCollection(['default' => $config]); 28 | $checks = $collection->getChecks(); 29 | 30 | /** @var Redis $check */ 31 | $check = $checks['redis_default']; 32 | 33 | $this->assertAuthPropertyValue($check, self::AUTH); 34 | } 35 | 36 | private function assertAuthPropertyValue(Redis $check, string $auth): void 37 | { 38 | try { 39 | $refClass = new \ReflectionClass($check); 40 | $authProp = $refClass->getProperty('auth'); 41 | $authProp->setAccessible(true); 42 | self::assertSame($auth, $authProp->getValue($check)); 43 | } catch (\ReflectionException $e) { 44 | self::fail($e->getMessage()); 45 | } 46 | } 47 | 48 | public function provideDsnWithAut(): array 49 | { 50 | return [ 51 | 'incompatible with parse_url' => [sprintf('redis://%s@127.0.0.1:6379', static::AUTH)], 52 | 'compatible with parse_url' => [sprintf('redis://irrelevant-user:%s@127.0.0.1:6379', static::AUTH)], 53 | ]; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Tests/Check/SymfonyMessengerTransportCountTest.php: -------------------------------------------------------------------------------- 1 | expectException(\LogicException::class); 17 | new SymfonyMessengerTransportCount( 18 | $this->getMockBuilder(MessageCountAwareInterface::class)->getMock(), 19 | 'foo', 20 | ['warning_threshold' => 2, 'critical_threshold' => 1] 21 | ); 22 | } 23 | 24 | /** 25 | * @dataProvider checkResultProvider 26 | */ 27 | public function testCheckResult($config, $count, $expectedResult) 28 | { 29 | $transport = $this->getMockBuilder(MessageCountAwareInterface::class)->getMock(); 30 | $transport->method('getMessageCount')->will($this->returnValue($count)); 31 | 32 | $check = new SymfonyMessengerTransportCount( 33 | new Transport($count), 34 | 'foo', 35 | $config 36 | ); 37 | $this->assertInstanceOf($expectedResult, $check->check()); 38 | } 39 | 40 | public function checkResultProvider() 41 | { 42 | return [ 43 | [['warning_threshold' => null, 'critical_threshold' => 1], 0, Success::class], 44 | [['warning_threshold' => 0, 'critical_threshold' => 1], 0, Success::class], 45 | [['warning_threshold' => null, 'critical_threshold' => 0], 1, Failure::class], 46 | [['warning_threshold' => 10, 'critical_threshold' => 100], 9, Success::class], 47 | [['warning_threshold' => 10, 'critical_threshold' => 100], 10, Warning::class], 48 | [['warning_threshold' => 10, 'critical_threshold' => 100], 99, Warning::class], 49 | [['warning_threshold' => 10, 'critical_threshold' => 100], 100, Failure::class], 50 | ]; 51 | } 52 | } 53 | 54 | class Transport implements MessageCountAwareInterface 55 | { 56 | private $n; 57 | 58 | public function __construct(int $n) 59 | { 60 | $this->n = $n; 61 | } 62 | 63 | public function getMessageCount(): int 64 | { 65 | return $this->n; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/AddGroupsCompilerPassTest.php: -------------------------------------------------------------------------------- 1 | [ 16 | 'default' => [ 17 | 'check1' => [], 18 | ], 19 | 'app_server' => [ 20 | 'check1' => [], 21 | 'check_collection1' => [], 22 | ], 23 | ], 24 | ]; 25 | $this->setParameter('liip_monitor.checks', $checkConfig); 26 | 27 | $check1 = new Definition(); 28 | $check1->addTag('liip_monitor.check', ['alias' => 'check1']); 29 | $this->setDefinition('liip_monitor.check.check1', $check1); 30 | 31 | $checkCollection1 = new Definition(); 32 | $checkCollection1->addTag('liip_monitor.check_collection'); 33 | $this->setDefinition('liip_monitor.check.check_collection1', $checkCollection1); 34 | 35 | $this->compile(); 36 | 37 | $this->assertContainerBuilderHasServiceDefinitionWithTag( 38 | 'liip_monitor.check.check1.default', 39 | 'liip_monitor.check', 40 | ['group' => 'default', 'alias' => 'check1'] 41 | ); 42 | 43 | $this->assertContainerBuilderHasServiceDefinitionWithTag( 44 | 'liip_monitor.check.check1.app_server', 45 | 'liip_monitor.check', 46 | ['group' => 'app_server', 'alias' => 'check1'] 47 | ); 48 | 49 | $this->assertContainerBuilderHasServiceDefinitionWithTag( 50 | 'liip_monitor.check.check_collection1.app_server', 51 | 'liip_monitor.check_collection', 52 | ['group' => 'app_server', 'alias' => 'check_collection1'] 53 | ); 54 | 55 | $this->assertContainerBuilderNotHasService('liip_monitor.check.check1'); 56 | $this->assertContainerBuilderNotHasService('liip_monitor.check.check_collection1'); 57 | } 58 | 59 | protected function registerCompilerPass(ContainerBuilder $container): void 60 | { 61 | $container->addCompilerPass(new AddGroupsCompilerPass()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/AdditionalReporterCompilerPassTest.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class AdditionalReporterCompilerPassTest extends AbstractCompilerPassTestCase 15 | { 16 | public function testProcessWithAlias(): void 17 | { 18 | $runner = new Definition(); 19 | $this->setDefinition('liip_monitor.runner_default', $runner); 20 | $this->setParameter('liip_monitor.runners', ['liip_monitor.runner_default']); 21 | 22 | $reporter = new Definition(); 23 | $reporter->addTag('liip_monitor.additional_reporter', ['alias' => 'foo']); 24 | $this->setDefinition('foo_reporter', $reporter); 25 | 26 | $this->compile(); 27 | 28 | $this->assertContainerBuilderHasServiceDefinitionWithMethodCall( 29 | 'liip_monitor.runner_default', 30 | 'addAdditionalReporter', 31 | [ 32 | 'foo', 33 | new Reference('foo_reporter'), 34 | ] 35 | ); 36 | } 37 | 38 | public function testProcessWithoutAlias(): void 39 | { 40 | $runner = new Definition(); 41 | $this->setDefinition('liip_monitor.runner_default', $runner); 42 | $this->setParameter('liip_monitor.runners', ['liip_monitor.runner_default']); 43 | 44 | $reporter = new Definition(); 45 | $reporter->addTag('liip_monitor.additional_reporter'); 46 | $this->setDefinition('foo_reporter', $reporter); 47 | 48 | $this->compile(); 49 | 50 | $this->assertContainerBuilderHasServiceDefinitionWithMethodCall( 51 | 'liip_monitor.runner_default', 52 | 'addAdditionalReporter', 53 | [ 54 | 'foo_reporter', 55 | new Reference('foo_reporter'), 56 | ] 57 | ); 58 | } 59 | 60 | protected function registerCompilerPass(ContainerBuilder $container): void 61 | { 62 | $container->addCompilerPass(new AdditionalReporterCompilerPass()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/CheckCollectionTagCompilerPassTest.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class CheckCollectionTagCompilerPassTest extends AbstractCompilerPassTestCase 16 | { 17 | public function testProcess(): void 18 | { 19 | $defaultGroup = 'grupo_predeterminado'; 20 | 21 | $runner = new Definition(); 22 | $this->setDefinition('liip_monitor.runner', $runner); 23 | $this->setParameter('liip_monitor.default_group', $defaultGroup); 24 | 25 | $check = new Definition(); 26 | $check->addTag('liip_monitor.check_collection'); 27 | $this->setDefinition('example_check_collection', $check); 28 | 29 | $this->compile(); 30 | 31 | $this->assertContainerBuilderHasServiceDefinitionWithMethodCall( 32 | 'liip_monitor.runner_'.$defaultGroup, 33 | 'addChecks', 34 | [ 35 | new Reference('example_check_collection'), 36 | ] 37 | ); 38 | } 39 | 40 | protected function registerCompilerPass(ContainerBuilder $container): void 41 | { 42 | $container->addCompilerPass(new GroupRunnersCompilerPass()); 43 | $container->addCompilerPass(new CheckCollectionTagCompilerPass()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/CheckTagCompilerPassTest.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class CheckTagCompilerPassTest extends AbstractCompilerPassTestCase 16 | { 17 | public function testProcess(): void 18 | { 19 | $defaultGroup = 'gruppo_predefinito'; 20 | 21 | $runner = new Definition(); 22 | $this->setDefinition('liip_monitor.runner', $runner); 23 | $this->setParameter('liip_monitor.default_group', $defaultGroup); 24 | 25 | $check = new Definition(); 26 | $check->addTag('liip_monitor.check'); 27 | $this->setDefinition('example_check', $check); 28 | 29 | $this->compile(); 30 | 31 | $this->assertContainerBuilderHasServiceDefinitionWithMethodCall( 32 | 'liip_monitor.runner_'.$defaultGroup, 33 | 'addCheck', 34 | [ 35 | new Reference('example_check'), 36 | 'example_check', 37 | ] 38 | ); 39 | } 40 | 41 | protected function registerCompilerPass(ContainerBuilder $container): void 42 | { 43 | $container->addCompilerPass(new GroupRunnersCompilerPass()); 44 | $container->addCompilerPass(new CheckTagCompilerPass()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/GroupRunnersCompilerPassTest.php: -------------------------------------------------------------------------------- 1 | setDefinition('liip_monitor.runner', $runner); 19 | $this->setParameter('liip_monitor.default_group', $defaultGroup); 20 | $this->setParameter('liip_monitor.checks', ['groups' => ['foo' => [], 'baz' => []]]); 21 | 22 | $fooCheck = new Definition(); 23 | $fooCheck->addTag('liip_monitor.check', ['group' => 'foo']); 24 | $fooCheck->addTag('liip_monitor.check', ['group' => 'foobar']); 25 | $this->setDefinition('acme.check.foo', $fooCheck); 26 | 27 | $barCheckCollection = new Definition(); 28 | $barCheckCollection->addTag('liip_monitor.check_collection', ['group' => 'bar']); 29 | $this->setDefinition('acme.check.bar', $barCheckCollection); 30 | 31 | $this->compile(); 32 | 33 | $this->assertContainerBuilderHasAlias('liip_monitor.runner', 'liip_monitor.runner_'.$defaultGroup); 34 | $this->assertContainerBuilderHasService('liip_monitor.runner_'.$defaultGroup); 35 | $this->assertContainerBuilderHasService('liip_monitor.runner_foo'); 36 | $this->assertContainerBuilderHasService('liip_monitor.runner_foobar'); 37 | $this->assertContainerBuilderHasService('liip_monitor.runner_bar'); 38 | $this->assertContainerBuilderHasService('liip_monitor.runner_baz'); 39 | $this->assertContainerBuilderHasAlias(Runner::class.' $fooRunner', 'liip_monitor.runner_foo'); 40 | $this->assertContainerBuilderHasAlias(Runner::class.' $foobarRunner', 'liip_monitor.runner_foobar'); 41 | $this->assertContainerBuilderHasAlias(Runner::class.' $barRunner', 'liip_monitor.runner_bar'); 42 | $this->assertContainerBuilderHasAlias(Runner::class.' $bazRunner', 'liip_monitor.runner_baz'); 43 | $this->assertContainerBuilderHasAlias(Runner::class.' $groupeParDéfautRunner', 'liip_monitor.runner_'.$defaultGroup); 44 | $this->assertContainerBuilderHasAlias(Runner::class, 'liip_monitor.runner'); 45 | } 46 | 47 | protected function registerCompilerPass(ContainerBuilder $container): void 48 | { 49 | $container->addCompilerPass(new GroupRunnersCompilerPass()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/MailerCompilerPassTest.php: -------------------------------------------------------------------------------- 1 | setParameter('liip_monitor.mailer.enabled', false); 19 | 20 | $this->compile(); 21 | 22 | $this->assertContainerBuilderNotHasService('liip_monitor.reporter.symfony_mailer'); 23 | $this->assertContainerBuilderNotHasService('liip_monitor.reporter.swift_mailer'); 24 | } 25 | 26 | public function testSwiftMailer(): void 27 | { 28 | $this->setParameter('liip_monitor.mailer.enabled', true); 29 | $this->setDefinition('mailer', new Definition(\Swift_Mailer::class)); 30 | 31 | $this->compile(); 32 | 33 | $this->assertContainerBuilderNotHasService('liip_monitor.reporter.symfony_mailer'); 34 | $this->assertContainerBuilderHasService('liip_monitor.reporter.swift_mailer', SwiftMailerReporter::class); 35 | 36 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 37 | 'liip_monitor.reporter.swift_mailer', 38 | 0, 39 | new Reference('mailer') 40 | ); 41 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 42 | 'liip_monitor.reporter.swift_mailer', 43 | 1, 44 | '%liip_monitor.mailer.recipient%' 45 | ); 46 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 47 | 'liip_monitor.reporter.swift_mailer', 48 | 2, 49 | '%liip_monitor.mailer.sender%' 50 | ); 51 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 52 | 'liip_monitor.reporter.swift_mailer', 53 | 3, 54 | '%liip_monitor.mailer.subject%' 55 | ); 56 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 57 | 'liip_monitor.reporter.swift_mailer', 58 | 4, 59 | '%liip_monitor.mailer.send_on_warning%' 60 | ); 61 | $this->assertContainerBuilderHasServiceDefinitionWithTag( 62 | 'liip_monitor.reporter.swift_mailer', 63 | 'liip_monitor.additional_reporter', 64 | ['alias' => 'swift_mailer'] 65 | ); 66 | } 67 | 68 | public function testSwiftMailerWithAliasDefinition(): void 69 | { 70 | $this->setParameter('liip_monitor.mailer.enabled', true); 71 | $this->setDefinition('swift.mailer', new Definition(\Swift_Mailer::class)); 72 | $this->container->setAlias('mailer', 'swift.mailer'); 73 | 74 | $this->assertContainerBuilderHasAlias('mailer'); 75 | 76 | $this->compile(); 77 | 78 | $this->assertContainerBuilderHasService('liip_monitor.reporter.swift_mailer', SwiftMailerReporter::class); 79 | } 80 | 81 | public function testSymfonyMailer(): void 82 | { 83 | $this->setParameter('liip_monitor.mailer.enabled', true); 84 | $this->setDefinition('mailer', new Definition(MailerInterface::class)); 85 | 86 | $this->compile(); 87 | 88 | $this->assertContainerBuilderNotHasService('liip_monitor.reporter.swift_mailer'); 89 | $this->assertContainerBuilderHasService('liip_monitor.reporter.symfony_mailer', SymfonyMailerReporter::class); 90 | 91 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 92 | 'liip_monitor.reporter.symfony_mailer', 93 | 0, 94 | new Reference('mailer') 95 | ); 96 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 97 | 'liip_monitor.reporter.symfony_mailer', 98 | 1, 99 | '%liip_monitor.mailer.recipient%' 100 | ); 101 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 102 | 'liip_monitor.reporter.symfony_mailer', 103 | 2, 104 | '%liip_monitor.mailer.sender%' 105 | ); 106 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 107 | 'liip_monitor.reporter.symfony_mailer', 108 | 3, 109 | '%liip_monitor.mailer.subject%' 110 | ); 111 | $this->assertContainerBuilderHasServiceDefinitionWithArgument( 112 | 'liip_monitor.reporter.symfony_mailer', 113 | 4, 114 | '%liip_monitor.mailer.send_on_warning%' 115 | ); 116 | $this->assertContainerBuilderHasServiceDefinitionWithTag( 117 | 'liip_monitor.reporter.symfony_mailer', 118 | 'liip_monitor.additional_reporter', 119 | ['alias' => 'symfony_mailer'] 120 | ); 121 | } 122 | 123 | public function testSymfonyMailerWithAliasDefinition(): void 124 | { 125 | $this->setParameter('liip_monitor.mailer.enabled', true); 126 | $this->setDefinition('symfony.mailer', new Definition(MailerInterface::class)); 127 | $this->container->setAlias('mailer', 'symfony.mailer'); 128 | 129 | $this->assertContainerBuilderHasAlias('mailer'); 130 | 131 | $this->compile(); 132 | 133 | $this->assertContainerBuilderHasService('liip_monitor.reporter.symfony_mailer', SymfonyMailerReporter::class); 134 | } 135 | 136 | public function testMailerWithoutPackage(): void 137 | { 138 | $this->setParameter('liip_monitor.mailer.enabled', true); 139 | $this->expectExceptionMessage('To enable mail reporting you have to install the "swiftmailer/swiftmailer" or "symfony/mailer".'); 140 | $this->expectException(\InvalidArgumentException::class); 141 | 142 | $this->assertContainerBuilderNotHasService('mailer'); 143 | $this->compile(); 144 | } 145 | 146 | public function testMailerMissingAliasDefinition(): void 147 | { 148 | $this->setParameter('liip_monitor.mailer.enabled', true); 149 | $this->setDefinition('swift.mailer', new Definition(\Swift_Mailer::class)); 150 | 151 | $this->assertFalse($this->container->hasAlias('mailer')); 152 | 153 | $this->expectException(\InvalidArgumentException::class); 154 | $this->expectExceptionMessage('To enable mail reporting you have to install the "swiftmailer/swiftmailer" or "symfony/mailer".'); 155 | 156 | $this->compile(); 157 | } 158 | 159 | protected function registerCompilerPass(ContainerBuilder $container): void 160 | { 161 | $container->addCompilerPass(new MailerCompilerPass()); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Tests/Helper/PathHelperTest.php: -------------------------------------------------------------------------------- 1 | $environment]); 21 | 22 | $container = $client->getKernel()->getContainer(); 23 | 24 | $pathHelper = $container->get('liip_monitor.helper'); 25 | 26 | // test route is defined in Tests/app/routing.yml 27 | $routes = $pathHelper->generateRoutes(['test_route' => []]); 28 | 29 | $this->assertEquals(['api.test_route = "/monitor";'], $routes); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Tests/Helper/SwiftMailerReporterTest.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | class SwiftMailerReporterTest extends \PHPUnit\Framework\TestCase 19 | { 20 | /** 21 | * @dataProvider sendNoEmailProvider 22 | */ 23 | public function testSendNoEmail(ResultInterface $result, $sendOnWarning): void 24 | { 25 | $mailer = $this->createMock('Swift_Mailer'); 26 | $mailer 27 | ->expects(self::never()) 28 | ->method('send'); 29 | 30 | $results = new Collection(); 31 | $results[$this->createMock(CheckInterface::class)] = $result; 32 | 33 | $reporter = new SwiftMailerReporter($mailer, 'foo@bar.com', 'bar@foo.com', 'foo bar', $sendOnWarning); 34 | $reporter->onFinish($results); 35 | } 36 | 37 | /** 38 | * @dataProvider sendEmailProvider 39 | */ 40 | public function testSendEmail(ResultInterface $result, $sendOnWarning): void 41 | { 42 | $mailer = $this->createMock('Swift_Mailer'); 43 | $mailer 44 | ->expects(self::once()) 45 | ->method('send') 46 | ->with(self::isInstanceOf('Swift_Message')); 47 | 48 | $results = new Collection(); 49 | $results[$this->createMock(CheckInterface::class)] = $result; 50 | 51 | $reporter = new SwiftMailerReporter($mailer, 'foo@bar.com', 'bar@foo.com', 'foo bar', $sendOnWarning); 52 | $reporter->onFinish($results); 53 | } 54 | 55 | public function sendEmailProvider(): array 56 | { 57 | return [ 58 | [new Failure(), true], 59 | [new Warning(), true], 60 | [new Unknown(), true], 61 | [new Failure(), false], 62 | ]; 63 | } 64 | 65 | public function sendNoEmailProvider(): array 66 | { 67 | return [ 68 | [new Success(), true], 69 | [new Skip(), true], 70 | [new Warning(), false], 71 | ]; 72 | } 73 | } 74 | 75 | class Unknown extends AbstractResult 76 | { 77 | } 78 | -------------------------------------------------------------------------------- /Tests/Helper/SymfonyMailerReporterTest.php: -------------------------------------------------------------------------------- 1 | mailer = $this->createMock(MailerInterface::class); 25 | } 26 | 27 | /** 28 | * @dataProvider getTestData 29 | */ 30 | public function testSendMail(array $recipients, string $sender, string $subject): void 31 | { 32 | $reporter = new SymfonyMailerReporter($this->mailer, $recipients, $sender, $subject); 33 | 34 | $check = $this->createStub(CheckInterface::class); 35 | $check->method('getLabel')->willReturn('Some Label'); 36 | 37 | $checks = new Collection(); 38 | $checks[$check] = new Failure('Something goes wrong'); 39 | 40 | $this->mailer 41 | ->expects(self::once()) 42 | ->method('send') 43 | ->with(self::callback(static function (Email $message) use ($recipients, $sender, $subject): bool { 44 | self::assertEquals(Address::createArray($recipients), $message->getTo(), 'Check if Recipient is sent correctly.'); 45 | self::assertEquals([Address::create($sender)], $message->getFrom(), 'Check that the from header is set correctly.'); 46 | self::assertSame($subject, $message->getSubject(), 'Check that the subject has been set.'); 47 | self::assertSame('[Some Label] Something goes wrong', $message->getTextBody(), 'Check if the text body has been set.'); 48 | 49 | return true; 50 | })); 51 | 52 | $reporter->onFinish($checks); 53 | } 54 | 55 | public static function getTestData(): iterable 56 | { 57 | return [ 58 | [ 59 | ['foo@bar.tld'], 60 | 'test@foobar.tld', 61 | 'Something went wrogin', 62 | ], 63 | ]; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Tests/LiipMonitorBundleTest.php: -------------------------------------------------------------------------------- 1 | true, 30 | 'Liip\MonitorBundle\DependencyInjection\Compiler\AddGroupsCompilerPass' => true, 31 | 'Liip\MonitorBundle\DependencyInjection\Compiler\GroupRunnersCompilerPass' => true, 32 | 'Liip\MonitorBundle\DependencyInjection\Compiler\CheckTagCompilerPass' => true, 33 | 'Liip\MonitorBundle\DependencyInjection\Compiler\CheckCollectionTagCompilerPass' => true, 34 | 'Liip\MonitorBundle\DependencyInjection\Compiler\AdditionalReporterCompilerPass' => true, 35 | 'Liip\MonitorBundle\DependencyInjection\Compiler\MailerCompilerPass' => true, 36 | ]; 37 | 38 | $this->container->expects($this->exactly(count($compilerPasses))) 39 | ->method('addCompilerPass') 40 | ->with($this->isInstanceOf('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')) 41 | ->willReturnCallback( 42 | function ($compilerPass) use (&$compilerPasses) { 43 | $class = get_class($compilerPass); 44 | unset($compilerPasses[$class]); 45 | 46 | return $this->container; 47 | } 48 | ); 49 | 50 | $definition = null; 51 | 52 | if (method_exists('Symfony\Component\DependencyInjection\ContainerBuilder', 'registerForAutoconfiguration')) { 53 | $this->container->method('registerForAutoconfiguration')->willReturn($definition = new ChildDefinition('')); 54 | } 55 | 56 | $this->bundle->build($this->container); 57 | $this->assertEmpty($compilerPasses); 58 | 59 | if ($definition) { 60 | $this->assertTrue($definition->hasTag('liip_monitor.check')); 61 | } 62 | } 63 | 64 | /** 65 | * Sets up test. 66 | */ 67 | protected function setUp(): void 68 | { 69 | $this->container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder') 70 | ->disableOriginalConstructor() 71 | ->getMock(); 72 | 73 | $this->bundle = new LiipMonitorBundle(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Tests/RunnerTest.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class RunnerTest extends \PHPUnit\Framework\TestCase 12 | { 13 | public function testAdditionalReporters(): void 14 | { 15 | $runner = new Runner(); 16 | 17 | $this->assertCount(0, $runner->getReporters()); 18 | 19 | $runner->addAdditionalReporter('foo', $this->createMockReporter()); 20 | $runner->addAdditionalReporter('bar', $this->createMockReporter()); 21 | 22 | $this->assertCount(0, $runner->getReporters()); 23 | 24 | $runner->useAdditionalReporters(['baz']); 25 | 26 | $this->assertCount(0, $runner->getReporters()); 27 | 28 | $runner->useAdditionalReporters(['foo']); 29 | 30 | $this->assertCount(1, $runner->getReporters()); 31 | 32 | $runner->useAdditionalReporters(['bar']); 33 | 34 | $this->assertCount(2, $runner->getReporters()); 35 | 36 | $runner = new Runner(); 37 | $runner->addAdditionalReporter('foo', $this->createMockReporter()); 38 | $runner->addAdditionalReporter('bar', $this->createMockReporter()); 39 | $runner->useAdditionalReporters(['bar', 'foo']); 40 | 41 | $this->assertCount(2, $runner->getReporters()); 42 | } 43 | 44 | /** 45 | * @return ReporterInterface 46 | */ 47 | private function createMockReporter() 48 | { 49 | return $this->getMockBuilder(ReporterInterface::class)->getMock(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/app/AppKernel.php: -------------------------------------------------------------------------------- 1 | load(__DIR__.'/config_'.$this->environment.'.yml'); 23 | } 24 | 25 | public function getProjectDir(): string 26 | { 27 | return __DIR__; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/app/config_symfony4.yml: -------------------------------------------------------------------------------- 1 | # symfony 4 config (requires assets defined) 2 | framework: 3 | router: 4 | resource: "%kernel.project_dir%/routing.yml" 5 | secret: test 6 | templating: 7 | engines: ['twig'] 8 | test: ~ 9 | assets: ~ 10 | profiler: 11 | collect: false 12 | 13 | liip_monitor: 14 | enable_controller: true 15 | -------------------------------------------------------------------------------- /Tests/app/config_symfony5.yml: -------------------------------------------------------------------------------- 1 | # symfony 5 config (requires assets defined) 2 | framework: 3 | router: 4 | resource: "%kernel.project_dir%/routing.yml" 5 | secret: test 6 | test: ~ 7 | assets: ~ 8 | profiler: 9 | collect: false 10 | 11 | liip_monitor: 12 | enable_controller: true 13 | -------------------------------------------------------------------------------- /Tests/app/config_symfony6.yml: -------------------------------------------------------------------------------- 1 | # symfony 6 config (requires assets defined) 2 | framework: 3 | router: 4 | resource: "%kernel.project_dir%/routing.yml" 5 | secret: test 6 | test: ~ 7 | assets: ~ 8 | profiler: 9 | collect: false 10 | 11 | liip_monitor: 12 | enable_controller: true 13 | -------------------------------------------------------------------------------- /Tests/app/config_symfony7.yml: -------------------------------------------------------------------------------- 1 | # symfony 7 config (requires assets defined) 2 | framework: 3 | router: 4 | resource: "%kernel.project_dir%/routing.yml" 5 | secret: test 6 | test: ~ 7 | assets: ~ 8 | profiler: 9 | collect: false 10 | 11 | liip_monitor: 12 | enable_controller: true 13 | -------------------------------------------------------------------------------- /Tests/app/routing.yml: -------------------------------------------------------------------------------- 1 | test_route: 2 | path: "/monitor" 3 | -------------------------------------------------------------------------------- /Tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ./Tests 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ./ 18 | 19 | ./Resources 20 | ./Tests 21 | ./vendor 22 | 23 | 24 | 25 | 26 | --------------------------------------------------------------------------------