Skip to content

Commit

Permalink
Merge pull request #2 from roma-glushko/1-magento-log-notifications
Browse files Browse the repository at this point in the history
📦 #1 Magento Log Notification Task
  • Loading branch information
roma-glushko authored Mar 29, 2020
2 parents c534536 + ea00787 commit fffec25
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 27 deletions.
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ Magento 2 specific tasks for <a href="https://github.com/phpro/grumphp">GrumPHP<

The easiest way to install this package is through composer:
```bash
composer config repositories.grumphp-magento2 vcs https://github.com/roma-glushko/grumphp-magento2
composer require --dev roma-glushko/grumphp-magento2
```

Expand All @@ -20,7 +19,7 @@ parameters:
## Usage
### MagentoModuleRegistration
### 🛠 MagentoModuleRegistration
It's a common practice to commit config.php file in Magento 2. Especially, the file is useful for managing modules. The common issue is when during development people forget to register newly added modules to the config.php which can lead to outcomes that hard to troubleshoot. This task helps to watch for such cases and let to know when registration is missing.
Expand Down Expand Up @@ -79,3 +78,39 @@ Key of the array is a package name. The value is a list of module names that the
*Default: `./app/code/*/*/registration.php`*

A glob() pattern that helps to find custom non-composer magento modules.

### 🛠 MagentoLogNotification

It's useful to be notified when you have recently added records in Magento logs. This tasks checks log files located
under `log_patterns` and informs if there are logs that have been added inside of time frame defined in `record_stale_threshold`.
The `exclude_severities` helps to reduce noisy records.

```yaml
parameters:
tasks:
magento2-log-notification:
log_patterns:
- "./var/*/*.log"
record_stale_threshold: 1 # in days
exclude_severities:
- "INFO"
- "DEBUG"
```

**log_patterns**

*Default: `./var/*/*.log`*

Paths where log files should be watched

**record_stale_threshold**

*Default: `1`*

Stale threshold (in days) that helps to ignore old records in logs.

**exclude_severities**

*Default: `INFO, DEBUG`*

This config excludes records with specified severity levels.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"require": {
"php": ">=7.0",
"phpro/grumphp": "~0.15",
"composer/composer": "^1.6"
"composer/composer": "^1.6",
"roma-glushko/monolog-parser": "^1.0"
},
"minimum-stability": "stable"
}
90 changes: 66 additions & 24 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/Extension/Loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Glushko\GrumphpMagento2\Extension;

use Glushko\GrumphpMagento2\Task\MagentoModuleRegistrationTask;
use Glushko\GrumphpMagento2\Task\MagentoLogNotificationTask;
use GrumPHP\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
Expand All @@ -24,5 +25,11 @@ public function load(ContainerBuilder $container)
->addArgument(new Reference('process_builder'))
->addArgument(new Reference('formatter.raw_process'))
->addTag('grumphp.task', ['config' => 'magento2-module-registration']);

$container->register('magento2.log-watcher', MagentoLogNotificationTask::class)
->addArgument(new Reference('config'))
->addArgument(new Reference('process_builder'))
->addArgument(new Reference('formatter.raw_process'))
->addTag('grumphp.task', ['config' => 'magento2-log-notification']);
}
}
131 changes: 131 additions & 0 deletions src/Task/MagentoLogNotificationTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php

namespace Glushko\GrumphpMagento2\Task;

use DateTime;
use Exception;
use GrumPHP\Runner\TaskResult;
use GrumPHP\Runner\TaskResultInterface;
use GrumPHP\Task\AbstractExternalTask;
use GrumPHP\Task\Context\ContextInterface;
use GrumPHP\Task\Context\GitPreCommitContext;
use GrumPHP\Task\Context\RunContext;
use MonologParser\Reader\LogReader;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* MagentoLogNotificationTask task
*/
class MagentoLogNotificationTask extends AbstractExternalTask
{
/**
* @return string
*/
public function getName(): string
{
return 'magento2-log-notification';
}

/**
* @return OptionsResolver
*/
public function getConfigurableOptions(): OptionsResolver
{
$resolver = new OptionsResolver();

$resolver->setDefaults([
'log_patterns' => ['./var/*/*.log'],
'record_stale_threshold' => '1',
'exclude_severities' => ['INFO', 'DEBUG'],
]);

$resolver->addAllowedTypes('log_patterns', ['array']);
$resolver->addAllowedTypes('exclude_severities', ['array']);
$resolver->addAllowedTypes('record_stale_threshold', ['integer']);

return $resolver;
}

/**
* {@inheritdoc}
*/
public function canRunInContext(ContextInterface $context): bool
{
return ($context instanceof GitPreCommitContext || $context instanceof RunContext);
}

/**
* Notify about recently added records in Magento logs
*
* @param ContextInterface $context
*
* @return TaskResultInterface
*
* @throws Exception
*/
public function run(ContextInterface $context): TaskResultInterface
{
$config = $this->getConfiguration();
$logPatterns = $config['log_patterns'];
$excludedSeverities = $config['exclude_severities'];
$recordStaleThreshold = $config['record_stale_threshold'];

$logFiles = [];

foreach ($logPatterns as $logPattern) {
$logFiles[] = glob($logPattern, GLOB_NOSORT);
}

$logFiles = array_merge(...$logFiles);

$dateNow = new DateTime();
$logReport = [];

foreach ($logFiles as $logPath) {
$logReader = new LogReader($logPath);
$logCount = count($logReader);

// go from the bottom to the top of the log file
// and count how many records are inside of report interval (like not older then 1 day)
for ($i = $logCount - 1; $i >= 0; $i--) {
$lastLine = $logReader[$i];

// calculate log relevance in hours
$recordFreshness = $dateNow->diff($lastLine['date'])->days;

// check log relevance
if ($recordFreshness > $recordStaleThreshold) {
break;
}

// check record severity
if (in_array($lastLine['level'], $excludedSeverities, true)) {
continue;
}

$logReport[$logPath] = array_key_exists($logPath, $logReport) ? $logReport[$logPath] + 1 : 1;
}
}

if (0 === count($logReport)) {
return TaskResult::createPassed($this, $context);
}

$message = '✘ Magento Logs have recently added records:' . PHP_EOL;

foreach ($logReport as $logPath => $recentLogCount) {
$message .= sprintf(
'• %s - %s %s',
$logPath,
$recentLogCount,
$recentLogCount > 1 ? 'records' : 'record'
) . PHP_EOL;
}

return TaskResult::createFailed(
$this,
$context,
$message
);
}
}

0 comments on commit fffec25

Please sign in to comment.