Search by

usekamori / kamori-php

usekamori

PHP SDK for Kamori — self-hosted log ingestion

Package info

github.com/usekamori/kamori-php

pkg:composer/usekamori/kamori-php

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-08-17 08:31 UTC

This package is auto-updated.

Last update: 2026-09-19 06:41:08 UTC


README

PHP 8.1+ SDK for Kamori — self-hosted log ingestion.

Sends structured log events to a Kamori ingest server over HTTP. No curl required — uses PHP's built-in fopen stream context for explicit response header access. Supports batching, automatic retry with exponential back-off, and drop callbacks. The client auto-flushes buffered events in __destruct.

Installation

composer require usekamori/kamori-php

Direct usage

use Kamori\KamoriClient;

$client = new KamoriClient(
    url: 'https://your-kamori-server.com',
    token: 'your-log-token',   // matches INGEST_TOKEN on the server
    batchSize: 50,             // flush automatically every 50 events
);

$client->log([
    'level'   => 'info',
    'message' => 'User signed in',
    'user_id' => 42,
]);

// Always flush at the end of a request or script
$client->flush();

Flush on shutdown (CLI scripts)

register_shutdown_function([$client, 'flush']);

HTTPS is required. A non-https URL throws InvalidArgumentException at construction so the auth token is never sent in cleartext — http is allowed only to localhost, or anywhere with new KamoriClient(..., allowInsecure: true).

Destructor flush is best-effort. __destruct performs a single send with a 2-second timeout and no retries, so a slow or unreachable ingest server cannot hang request teardown. Call flush() explicitly for at-least-once retry semantics.

Monolog 3 handler

composer require monolog/monolog
use Kamori\Monolog\KamoriHandler;
use Monolog\Logger;
use Monolog\Level;

$logger = new Logger('app');
$logger->pushHandler(new KamoriHandler(
    url: 'https://your-kamori-server.com',
    token: 'your-log-token',
    batchSize: 50,
    level: Level::Debug,
));

$logger->info('Hello from Monolog', ['user_id' => 7]);
$logger->error('Something went wrong', ['exception' => 'RuntimeException']);

// Flush when the handler is closed (called automatically by Monolog on __destruct)
// Or flush explicitly:
$logger->getHandlers()[0]->getClient()->flush();

Context and extra fields are forwarded to Kamori as-is so all structured data is full-text-searchable.

Laravel (zero-config)

Auto-discovery is enabled via composer.json. After composer require usekamori/kamori-php, add to your .env:

KAMORI_URL=https://your-kamori-server.com
INGEST_TOKEN=your-log-token

Optionally publish the config file:

php artisan vendor:publish --tag=kamori-config

This creates config/kamori.php where you can adjust batch_size.

The KamoriClient singleton is automatically flushed at the end of every request via app()->terminating(). No additional setup is required.

Resolve the client manually

use Kamori\KamoriClient;

$client = app(KamoriClient::class);
$client->log(['level' => 'debug', 'message' => 'Manual log entry']);

Configuration reference

Option Default Description
url Base URL of your Kamori server (required)
token null Auth token (sent as Authorization: Bearer). Leave null to skip auth.
batchSize 50 Number of events buffered before auto-flush
maxBuffer 0 Max events in the in-memory buffer. 0 = unlimited. New events are passed to onDrop and discarded when the limit is reached.
onDrop null Callable invoked with the batch when all retries fail

Scoped clients

Add default fields to every log call without repeating them:

class ScopedKamoriClient
{
    public function __construct(
        private KamoriClient $client,
        private array $defaults = [],
    ) {}

    public function log(array $event): void
    {
        $this->client->log(array_merge($this->defaults, $event));
    }

    public function flush(): void
    {
        $this->client->flush();
    }
}

$requestLog = new ScopedKamoriClient($client, [
    'service'    => 'api',
    'request_id' => 'abc-123',
    'user_id'    => 42,
]);

$requestLog->log(['level' => 'info', 'message' => 'Request started']);
$requestLog->log(['level' => 'error', 'message' => 'Validation failed', 'field' => 'email']);

Retry behaviour

Failed requests are retried up to three times with exponential back-off. PHP has no async I/O, so retries block the current process with usleep():

Attempt Delay
1st retry 0.25 s
2nd retry 1 s
3rd retry 4 s

4xx responses are not retried (client error — bad token, oversized batch). After all retries fail the batch is passed to onDrop (if configured) and discarded. The client never throws.

onDrop callback

$client = new KamoriClient(
    url: 'https://your-kamori-server.com',
    token: 'your-log-token',
    onDrop: function (array $events): void {
        error_log('Kamori dropped ' . count($events) . ' events');
    },
);

Trace correlation

Kamori attaches a trace_id (and span_id) to every event so logs across services join into one chain — query it with the trace_logs MCP tool. An explicit trace_id on the event always wins.

use Kamori\TraceContext;

// Reuse an inbound W3C traceparent so the id is shared across services, else generate one.
$traceId = TraceContext::parseTraceparent($_SERVER['HTTP_TRACEPARENT'] ?? null)
    ?? TraceContext::generate();
TraceContext::set($traceId);

// ... every Kamori log during this request now carries $traceId ...

TraceContext::clear();   // at end of request

In Laravel, set the id in a middleware; the Monolog handler picks it up automatically.

OpenTelemetry (optional)

If the OpenTelemetry PHP API is installed, the active span's trace_id/span_id are attached automatically — no code change and no hard dependency:

// Inside an active OTel span, this log carries the span's trace_id + span_id:
$logger->info('charging card');

Requirements

  • PHP 8.1+
  • openssl extension (enabled by default) for HTTPS
  • OpenTelemetry trace correlation is optional (composer require open-telemetry/api)
  • Monolog 3.x (optional, only needed for KamoriHandler)
  • Laravel 10+ (optional, only needed for KamoriServiceProvider)

License

MIT