Custom Health Checks
OpConsole's only callable extension point is the HealthCheck contract. config/opconsole.php contains zero closures by design, so php artisan config:cache always works — custom checks are registered as class names, resolved from the container.
The contract
namespace AshrafTalha\OpConsole\Contracts;
interface HealthCheck
{
/**
* @return array{group: string, label: string, ok: bool, severity: 'danger'|'warning'|'info', hint: string, value: ?string, fix: ?string, id?: string, status?: 'healthy'|'warning'|'critical'|'unknown'}
*/
public function run(): array;
}A worked example
namespace App\HealthChecks;
use AshrafTalha\OpConsole\Contracts\HealthCheck;
use Illuminate\Support\Facades\Storage;
class BackupDiskCheck implements HealthCheck
{
public function run(): array
{
$ok = Storage::disk('local')->exists('backups');
return [
'id' => 'backups', // reported as custom.backups
'group' => 'Backups',
'label' => 'Backup folder',
'ok' => $ok,
'severity' => 'warning', // danger, warning or info
'hint' => 'The backup folder must exist.',
'value' => $ok ? 'Found' : 'Missing',
'fix' => $ok ? null : 'mkdir -p storage/app/backups',
];
}
}Register it:
// config/opconsole.php
'checks' => [
App\HealthChecks\BackupDiskCheck::class,
],Because implementations are resolved from the container, constructor dependencies are injected normally — inject a repository, an HTTP client, whatever the check needs.
The id and status keys
idgives the check a stable slug, stored and reported ascustom.<slug>. Without it, OpConsole falls back to a class-derived identifier.statuslets a check report explicitly that it cannot verify something, by returning'status' => 'unknown'— for example, a dependency on an external service you have no reliable way to probe synchronously.
Making an unknown check matter
By default, unknown checks stay non-failing for the overall report (health.unknown_policy defaults to healthy, for compatibility with monitoring integrations that only look at overall status). Two ways to make a specific check matter:
// config/opconsole.php
'health' => [
'required_checks' => ['custom.backups'], // always critical if unknown
'unknown_policy' => 'healthy', // or 'warning' / 'critical' globally
],Add the check's custom.<id> string to required_checks to make it always critical when unknown — including when the check itself throws. A required custom check that throws is reported as a critical Required check … entry rather than disappearing from the report silently.
Where custom checks appear
Everywhere built-in checks do: the Health tab, the Overview summary, the opconsole:health CLI command, and the JSON health endpoint. They follow the same severity ordering and grouping as built-in checks.
Rules enforced by the framework
- Duplicate custom check classes in
config('opconsole.checks')are deduplicated. - A custom check attempting to reuse a built-in
(group, label)pair is skipped with a warning logged, rather than silently shadowing a built-in check. HealthChecksvalidates the scalar types and shape of whatrun()returns — malformed output doesn't propagate into the UI unpredictably.
Practical guidance
- Keep checks fast. Every dashboard load, CLI run, and health-endpoint request runs every check synchronously, including yours. OpConsole cannot interrupt a slow check.
- Bound your own network calls. If a check makes an HTTP request, give it an explicit short timeout — don't rely on PHP's default.
- Don't return secrets in
value. Like built-in checks, custom check output is rendered directly in the UI (escaped, but visible to anyone withviewOpConsole).
See also Extension Points & Contracts for the broader picture of what is and isn't extensible.