liip / LiipMonitorBundle

Integrates the LiipMonitor library into Symfony
http://liip.ch
467 stars 103 forks source link

OhDear Reporter & Health Check controller #276

Closed kbond closed 1 year ago

kbond commented 1 year ago

Not sure if we should include here or a separate bundle?

Ref: https://twitter.com/zenstruck/status/1471115679986335747 Ref: https://ohdear.app/docs/general/application-health-monitoring

Here is how I wired it up in my app:

use Laminas\Diagnostics\Check\CheckInterface;
use Laminas\Diagnostics\Result\Collection as ResultsCollection;
use Laminas\Diagnostics\Result\ResultInterface;
use Laminas\Diagnostics\Result\Skip;
use Laminas\Diagnostics\Result\Success;
use Laminas\Diagnostics\Result\Warning;
use Laminas\Diagnostics\Runner\Reporter\ReporterInterface;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
final class OhDearReporter implements ReporterInterface
{
    private array $results = [];

    public function results(): array
    {
        return $this->results;
    }

    public function onAfterRun(CheckInterface $check, ResultInterface $result, $checkAlias = null): void
    {
        $this->results[] = [
            'name' => $checkAlias ?? $check->getLabel(),
            'label' => $check->getLabel(),
            'status' => self::statusFor($result),
            'notificationMessage' => $result->getMessage(),
            'shortSummary' => $result->getMessage(),
            'meta' => [],
        ];
    }

    public function onStart(\ArrayObject $checks, $runnerConfig): void
    {
    }

    public function onBeforeRun(CheckInterface $check, $checkAlias = null): void
    {
    }

    public function onStop(ResultsCollection $results): void
    {
    }

    public function onFinish(ResultsCollection $results): void
    {
    }

    private static function statusFor(ResultInterface $result): string
    {
        switch (true) {
            case $result instanceof Success:
                return 'ok';
            case $result instanceof Warning:
                return 'warning';
            case $result instanceof Skip:
                return 'skipped';
        }

        return 'crashed';
    }
}
use ...\OhDearReporter;
use Liip\MonitorBundle\Runner;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Contracts\Cache\CacheInterface;

/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
final class HealthCheckController
{
    private Runner $runner;
    private string $secret;

    public function __construct(Runner $runner, string $secret)
    {
        $this->runner = $runner;
        $this->secret = $secret;
    }

    public function __invoke(Request $request, CacheInterface $cache): JsonResponse
    {
        if ($this->secret !== $request->headers->get('oh-dear-health-check-secret')) {
            throw new NotFoundHttpException();
        }

        $results = $cache->get('ohdear-health-check', function(CacheItem $item) {
            $this->runner->addReporter($reporter = new OhDearReporter());
            $this->runner->run();

            $item->expiresAfter(300);

            return $reporter->results();
        });

        return new JsonResponse([
            'finishedAt' => \time(),
            'checkResults' => $results,
        ]);
    }
}
stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 1 year ago

This issue has been automatically closed. Feel free to re-open if it is still relevant.