PHP and Laravel
On Laravel, install the package and add your DSN to .env; there is nothing else to register. Any other PHP app, from Symfony to WordPress, calls init() once in its front controller.
Laravel
Install
composer require naijacloud/argus-laravelLaravel 10 to 13, on a patched PHP: 8.2.35, 8.3.36, 8.4.27, 8.5.12 or newer. Those releases fix php2shell (CVE-2026-109618 and CVE-2026-109619), and Composer refuses older ones. The package is discovered automatically: there is no provider to register.
Set up
In your .env file:
ARGUS_DSN=https://<public key>@argus-in.naijacloud.com/<project id>A Naijacloud service gets the DSN from its Send errors to Argus switch,
so there you can leave .env alone. Without a DSN the package does nothing,
so local development and CI need no changes.
Send a test event
php artisan argus:testIt sends one test event and says whether Argus accepted it, or why not. Use
--dsn= to test a different DSN. If your config is cached, run
php artisan config:clear first.
What it captures
With only the DSN set:
- Exceptions, through Laravel's own handler: whatever Laravel reports
reaches Argus, and whatever it doesn't (validation errors, 404s, your
dontReportlist) doesn't.report($e)works too. - Each error's context: the route (
GET /orders/{order}), the signed-in user's id, the URL without its query string, and breadcrumbs of the queries, logs and HTTP calls before it. - Request traces, with a child span for each database query (with
?placeholders, never the bound values) and eachHttp::call. - Queued jobs, each in a span that continues the trace of the request that dispatched it. A failed job is reported with its class, queue and connection.
Under PHP-FPM, everything is sent after the response has reached the visitor, within a 2-second budget. Octane and queue workers send after each request or job, and start each one with a clean scope.
Logs
The argus log channel is defined for you. Add it to your stack in .env:
LOG_STACK=single,argusEvery Log::info(), Log::warning() and so on then also reaches Argus Logs,
with its context as attributes. On Laravel 10, or with your own
config/logging.php, add 'argus' to your stack channel's channels.
ARGUS_LOG_LEVEL sets the lowest level sent (default debug).
Scheduled tasks
Create a cron monitor in Argus, then name its slug on the task:
Schedule::command('invoices:send')->daily()->argusMonitor('nightly-invoices');Argus hears when the task starts, and whether it succeeded or failed, with its exit code.
In your code
The Argus facade covers errors, metrics, traces, cron check-ins and flags:
use NaijaCloud\Argus\Laravel\Facades\Argus;
Argus::captureException($e, ['tags' => ['provider' => 'paystack']]);
Argus::captureMessage('Webhook signature mismatch', 'warning');
Argus::setTag('tenant', $tenant->slug);
Argus::count('orders.placed', 1, ['method' => 'card']);
Argus::distribution('checkout.ms', $elapsedMs, [], 'ms');
Argus::trace('charge card', fn () => $paystack->charge($order));
Argus::withMonitor('import-rates', fn () => $this->importRates());
if (Argus::isOn('new-checkout', (string) $user->id)) {
// …
}Release, environment and privacy
.env | Default |
|---|---|
ARGUS_RELEASE | SENTRY_RELEASE |
ARGUS_ENVIRONMENT | SENTRY_ENVIRONMENT, else APP_ENV |
ARGUS_SERVICE_NAME | APP_NAME |
ARGUS_TRACES_SAMPLE_RATE | 1 |
ARGUS_SEND_DEFAULT_PII | false: only the user's id is sent |
Passwords, tokens, secrets, card numbers, BVNs, Authorization headers and
JWTs become [Filtered]; cookies, request bodies and query strings are never
sent. To change or drop events, publish the config with
php artisan vendor:publish --tag=argus-config and set before_send to a
[class, method] pair, so config:cache still works:
'before_send' => [App\Support\ArgusFilters::class, 'beforeSend'],Already on Sentry
Keep sentry/sentry-laravel. In your .env file, change one line:
SENTRY_LARAVEL_DSN=https://<public key>@argus-in.naijacloud.com/<project id>Any PHP app
Install
composer require naijacloud/argusA patched PHP, as above: 8.2.35, 8.3.36, 8.4.27, 8.5.12 or newer. It uses
ext-curl when it's loaded, and PHP's own
https:// streams when it isn't.
Set up
As early as possible in your front controller, such as public/index.php:
require __DIR__ . '/vendor/autoload.php';
\NaijaCloud\Argus\init([
'dsn' => 'https://<public key>@argus-in.naijacloud.com/<project id>', // or set ARGUS_DSN
'release' => '1.4.2',
]);init() with no dsn reads ARGUS_DSN, then SENTRY_DSN.
Send a test event
\NaijaCloud\Argus\init(['debug' => true]);
\NaijaCloud\Argus\Argus::captureMessage('Argus test event');
var_dump(\NaijaCloud\Argus\Argus::flush()); // true when Argus accepted itWith debug on, a refused key or a rate limit is written to the PHP error
log.
What it captures
- Uncaught exceptions, as
fatal. PHP still prints its usual message and exits as it would without Argus. - PHP warnings and errors, once per file and line. Calls silenced with
@are skipped; deprecations and notices become breadcrumbs. - Fatal errors at shutdown, including running out of memory.
- Your own handlers are kept. Argus calls them after it records the error.
Everything is queued while the request runs and sent at shutdown, after
fastcgi_finish_request() when PHP-FPM provides it, so the visitor never
waits. Long-running workers should call Argus::flush() and
Argus::clearScope() after each job.
Errors, logs, metrics and traces
use NaijaCloud\Argus\Argus;
use NaijaCloud\Argus\Span;
try {
$paystack->charge($order);
} catch (\Throwable $e) {
Argus::captureException($e, ['tags' => ['provider' => 'paystack']]);
}
Argus::setUser(['id' => $user->id]);
Argus::logs()->info('order placed', ['orderId' => 'ord_81', 'total' => 18500]);
Argus::metrics()->count('orders.placed', 1, ['method' => 'card']);
Argus::metrics()->gauge('queue.depth', count($jobs));
Argus::trace('charge card', function (Span $span) use ($order, $paystack) {
$span->setAttribute('provider', 'paystack');
return $paystack->charge($order);
});Using PSR-3 or Monolog? new \NaijaCloud\Argus\Log\PsrLogger() and
new \NaijaCloud\Argus\Log\MonologHandler() write to Argus Logs. To continue
a trace from an incoming request, call
Argus::continueTrace($_SERVER['HTTP_TRACEPARENT'] ?? null), and send
Argus::traceparent() as a traceparent header on outgoing calls.
Cron check-ins and feature flags
// Create the monitor in Argus first.
Argus::cron()->withMonitor('nightly-invoices', fn () => sendInvoices());
// or by hand:
Argus::cron()->checkIn('nightly-invoices', 'start');
Argus::cron()->checkIn('nightly-invoices', 'ok'); // or 'error', or an exit code
if (Argus::flags()->isOn('new-checkout', (string) $user->id)) {
// …
}
$theme = Argus::flags()->variant('theme', (string) $user->id, 'light');Check-ins are sent immediately, not at shutdown. A flag check waits at most
flags_timeout_ms (1 second); answers are cached for 30 seconds per user,
and if Argus can't be reached you get the fallback you passed.
Release, environment and privacy
init() reads ARGUS_RELEASE and ARGUS_ENVIRONMENT, then SENTRY_RELEASE
and SENTRY_ENVIRONMENT; the environment is production when none is set.
The same filtering as on Laravel is on by default, and the user's IP address
is not sent unless you set 'send_default_pii' => true. before_send changes
an event, or drops it when it returns null:
\NaijaCloud\Argus\init([
'before_send' => fn (array $event): ?array =>
str_contains($event['message'] ?? '', 'healthcheck') ? null : $event,
]);Already on Sentry
Keep sentry/sentry. In your \Sentry\init call, change the dsn line:
'dsn' => 'https://<public key>@argus-in.naijacloud.com/<project id>',