LiipMonitorBundle icon indicating copy to clipboard operation
LiipMonitorBundle copied to clipboard

OhDear Reporter & Health Check controller

Open kbond opened this issue 3 years ago • 0 comments

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 <[email protected]>
 */
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 <[email protected]>
 */
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,
        ]);
    }
}

kbond avatar Sep 21 '22 14:09 kbond