liberusoftware/observability-api
A Laravel/PHP package that exposes an observability API for your application, providing endpoints and tooling to surface health, metrics, and runtime signals for monitoring, debugging, and operational insight. Designed to make application status easier to inspect and integrate with dashboards or ale...
The package is a presentation adapter — it does not collect telemetry itself, it exposes observability data collected elsewhere (health probes, metrics registries, log/trace buffers) over HTTP. Treat it as the "read side" of a modular observability stack.
Minimal steps:
composer require liberusoftware/observability-api
config/app.php. If the module ships a module.json (Liberu modules usually do), make sure your module loader (nwidart/laravel-modules or a custom registrar) is enabled so its routes/providers get booted:
php artisan about # provider listed?
php artisan route:list --path=observability
php artisan vendor:publish --provider="Liberu\ObservabilityApi\ObservabilityApiServiceProvider"
Expect a config/observability-api.php holding route prefix, middleware stack, auth guard, and which endpoints (health / metrics / logs / traces) are enabled.config/observability-api.php → routes/api.php → src/Http/Controllers → src/Contracts (any Probe, MetricPresenter, or HealthCheck interface is your extension point) → the domain package it adapts (check composer.json of the vendor folder for a sibling observability core).curl -s https://app.test/api/observability/health | jq
curl -s https://app.test/api/observability/metrics
Enable it locally first with only the health check on, then widen.
Kubernetes / load-balancer split. Expose two health endpoints — a liveness one that answers without touching DB/cache/queue, and a readiness one that does. Wire liveness to the container probe and readiness to the LB target group. Never let the liveness probe depend on Postgres; a DB blip will restart your whole fleet.
Scrape isolation. Put the metrics route on a separate middleware group and, ideally, a separate hostname or port so it is not reachable from the public internet. Typical config:
// config/observability-api.php
'route' => [
'prefix' => 'observability',
'middleware' => ['api', 'throttle:60,1'],
],
'metrics' => [
'middleware' => ['api', 'auth.observability'], // custom token guard
'enabled' => env('OBSERVABILITY_METRICS', true),
],
Token-gated scraping. A short custom middleware comparing a bearer token against config('observability-api.token') is usually enough for Prometheus and avoids dragging Sanctum into your scrape path:
public function handle($request, Closure $next)
{
abort_unless(hash_equals(config('observability-api.token'), $request->bearerToken()), 401);
return $next($request);
}
Extending probes. If the package exposes a Probe/HealthCheck contract, register your own checks through the config array rather than editing vendor controllers:
'checks' => [
\App\Observability\StripeConnectivityCheck::class,
\App\Observability\HorizonWorkersCheck::class,
],
Each check should return a status + latency budget, never throw. Assert on the aggregate JSON in a feature test so a new check doesn't silently change the payload shape.
Decorating the adapter. Because this is the presentation layer, it should sit behind an interface. If the controllers type-hint a domain service, rebind it in AppServiceProvider to swap the source of truth (e.g. pull metrics from Redis instead of an in-process registry) without touching routes.
CI/CD smoke test. Add a post-deploy step that curls the health endpoint and fails the deploy on non-200 or on any "status": "degraded":
// tests/Feature/ObservabilityTest.php
$this->getJson('/api/observability/health')
->assertOk()
->assertJsonPath('status', 'ok');
Multi-tenant. If you serve several tenants from one app, either scope the metrics endpoint per tenant (label or path segment, populated by a middleware) or expose only the aggregate — mixing tenant IDs into metric labels is the fast road to a cardinality explosion.
Coexistence. This is not a replacement for Telescope or Pulse — those are dev/debug tooling, this is the production read surface. Run them side by side; Telescope off in prod, observability endpoints on.
NOASSERTION. This is effectively unvetted code. Get legal sign-off before shipping — an unresolved license is, by default, all-rights-reserved. Pin an exact version ("liberusoftware/observability-api": "1.0.0") and diff every upgrade; there is no community to catch regressions.dev-main; a moving main on a 0-star package is an unreviewed supply-chain dependency.TargetInterface is not instantiable error at boot. Read its composer.json require block before installing.php artisan optimize:clear && php artisan config:cache && php artisan route:cache
Run these in the deploy pipeline, not just locally — forgetting is the #1 "it works on my machine" for modules.liveness (process alive) from readiness (dependencies reachable) and set aggressive timeouts on each check.curl -s localhost/api/observability/metrics | grep -c '^myapp_requests_total'
A four-figure count on one metric name is a bug, not observability."schema": 1) or the first dependency bump silently breaks all your alerting.api group's SubstituteBindings plus a global auth middleware can turn a monitor's anonymous GET into a 401 with no obvious cause. Verify with a plain curl (no session cookie, no Accept: text/html) exactly as Prometheus will call it — browser success proves nothing.php artisan about (provider booted), php artisan route:list --path=observability (routes registered), php artisan config:show observability-api (config published and values correct), then storage/logs/laravel.log for container resolution errors.How can I help you explore Laravel packages today?