Search by

meyercomputerinc / log-client

knuge

Buffered, batch-shipping Monolog handler for Axiom. One HTTP request per execution; can never slow down or break the host application.

Package info

bitbucket.org/meyercomputerinc/log-client

pkg:composer/meyercomputerinc/log-client

Statistics

Installs: 21

Dependents: 0

Suggesters: 0

v0.1.1 2026-09-10 20:44 UTC

This package is auto-updated.

Last update: 2026-09-10 20:49:20 UTC


README

Buffered, batch-shipping Monolog handler for Axiom. Log records are collected in memory during one execution (HTTP request, artisan command, queued job, scheduled task) and POSTed to Axiom as a single NDJSON batch when that execution ends.

It is built so that logging can never slow down or break the host application:

  • one HTTP call per execution, hard-capped at 1 s connect + 2 s total (AXIOM_CONNECT_TIMEOUT_MS / AXIOM_TIMEOUT_MS; a TLS handshake to Axiom from far away can take 400–700 ms);
  • a circuit breaker skips shipping for 60 s after 3 consecutive failures;
  • every code path catches Throwable; failures are reported once per process via error_log(), never through Laravel's logger;
  • a bounded 500-record buffer that drops the oldest records under pressure;
  • inert during unit tests unless explicitly allowed.

Install

composer require meyercomputerinc/log-client

The service provider is auto-discovered and registers an axiom log channel. Add it to your stack:

LOG_STACK=stderr,axiom      # or single,axiom locally

AXIOM_ENABLED=true
AXIOM_TOKEN=xaat-...
AXIOM_DATASET=my-app

Axiom setup

  1. Create a dataset (one per app is a good default, e.g. my-app and my-app-dev). Datasets are not auto-created on ingest.
  2. Create an API token with ingest permission on that dataset.
  3. Optional: run php artisan vendor:publish --tag=log-client-config to tune the defaults.

Verify

php artisan log-client:test --dry-run   # prints the NDJSON that would be sent
php artisan log-client:test             # sends sample records, prints status / ingested / failed / breaker

Then in Axiom: ["my-app"] | where execution_id == "<id printed by the command>".

What gets shipped

Every event carries _time (UTC), level, message, channel, app, environment, host, and execution metadata: execution (request | job | command | schedule), execution_name (route name, job class, command, task), execution_id (one per execution), trace_id (shared with jobs dispatched from the same request; uses Nightwatch's trace id when Nightwatch is installed), and user_id when someone is authenticated.

Context keys listed in promote (default association, source, client_id) become top-level fields. Everything else in context — and Laravel Context data, which Laravel places in extra — is shipped according to context_mode:

  • json (default): one string field. Always safe; the Axiom free plan caps a dataset at 256 field names, and nested keys would otherwise sprawl. Query it with parse_json(context).
  • map: a nested object. Create context and extra as map fields in Axiom first so each counts as one field.
  • drop: omit it.

Exceptions in context (['exception' => $e], as Laravel's handler sends them) become exactly exception.class, exception.message, exception.file and a trace capped at exception.trace_frames lines.

When the buffer flushes

ExecutionFlush point
HTTP requestend of the kernel's terminate(), after terminable middleware
Artisan commandend of the console kernel's terminate()
Queue worker (incl. Horizon)Looping (before the next job) and WorkerStopping — never on the job events, which fire before the worker logs a failed job's exception
Scheduled taskafter each task
Any long-running processwhen the oldest buffered record is flush_after_seconds old (default 10), or the buffer hits buffer_limit

Configuration

See config/log-client.php. Everything is env-driven; the keys you are most likely to touch are AXIOM_LOG_LEVEL, context_mode, promote, and flush_after_seconds.

Testing your app

The package is forced off while app()->runningUnitTests() is true unless log-client.allow_in_tests is set, so application test suites never ship logs. To make that explicit, add <env name="AXIOM_ENABLED" value="false"/> to phpunit.xml.

License

MIT