daemon8 / php
Daemon8 SDK for PHP — framework-agnostic runtime observation primitives
Requires
- php: ^8.4
- ext-json: *
- spatie/backtrace: ^1.6
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
- rector/rector: ^2.0
- rector/swiss-knife: ^2.3
- slevomat/coding-standard: ^8.15
- squizlabs/php_codesniffer: ^3.10
Suggests
- ext-curl: For fire-and-forget HTTP transport (curl_multi). Falls back to fsockopen.
- ext-sockets: For UDP transport (UdpTransport).
This package is auto-updated.
Last update: 2026-04-22 13:45:50 UTC
README
Framework-agnostic runtime observation primitives for Daemon8.
Ship logs, queries, exceptions, and custom events into a local observation stream your AI coding agent can query.
Website · Docs · Daemon · SDKs · Demo · Contact
Free and open source. No tiers, no license keys, no phone-home.
Active development. This package is in public alpha. Tracked work for this SDK lives as GitHub Issues; the broader roadmap is maintained on the primary daemon8 repo.
Daemon8 SDK for PHP
PHP 8.4+. Zero framework dependencies. Safe to leave on in production. When the daemon is unreachable, SDK calls are silent no-ops — your application keeps running.
Getting Started
Install the SDK:
composer require daemon8/php
Start the local daemon (if you haven't already):
daemon8 install # one-time setup + start as a system service
Emit an observation from anywhere in your app:
use Daemon8\Daemon8; Daemon8::log('checkout completed', severity: 'info'); Daemon8::warn('rate limit near threshold'); Daemon8::exception(new \RuntimeException('pay gateway timeout')); Daemon8::query('SELECT * FROM users WHERE active = ?', durationMs: 42.1);
Query from your terminal or agent:
daemon8 tail --kinds log,exception --severity warn
Or from code, against the local daemon's HTTP API:
curl 'http://127.0.0.1:9077/api/observe?kinds=log,exception&severity_min=warn&limit=20'
Facade vs. instance client
The Daemon8 facade is a static entry point backed by a lazily-configured singleton. Use it when global access is simplest:
use Daemon8\Daemon8; use Daemon8\Config; Daemon8::configure(Config::create( ingestUrl: 'http://127.0.0.1:9077/ingest', appName: 'checkout-api', debug: true, )); Daemon8::log('user signed in', severity: 'info');
For DI-friendly, testable, multi-tenant code, construct Daemon8Client directly:
use Daemon8\Config; use Daemon8\Daemon8Client; $client = new Daemon8Client(Config::create( ingestUrl: 'http://127.0.0.1:9077/ingest', appName: 'workers', )); $client->log('job dispatched'); $client->send( ['user_id' => 42, 'action' => 'checkout'], severity: 'info', kind: 'custom', channel: 'audit', );
Daemon8Client is the real implementation. The Daemon8 facade forwards every call to a lazily-configured singleton client — use whichever style fits your host.
Configuration
Config is an immutable, validated DTO. Build it once at bootstrap and pass it everywhere.
use Daemon8\Config; $config = Config::create( ingestUrl: 'http://127.0.0.1:9077/ingest', baseUrl: 'http://127.0.0.1:9077', udpHost: '127.0.0.1', udpPort: 9078, timeoutMs: 50, batchSize: 100, appName: 'my-app', debug: false, );
Every argument is optional. Omitted fields take package defaults.
Environment
DAEMON8_URL=http://127.0.0.1:9077/ingest DAEMON8_BASE_URL=http://127.0.0.1:9077 DAEMON8_UDP_URL=127.0.0.1:9078 DAEMON8_TIMEOUT_MS=50 DAEMON8_BATCH_SIZE=100 DAEMON8_APP=my-app DAEMON8_DEBUG=1
Config::fromEnv() reads these. The SDK never touches $_ENV anywhere else.
Observations
Every helper on Daemon8 / Daemon8Client eventually becomes an Observation. For advanced cases build one directly:
use Daemon8\Observation; use Daemon8\Kind; use Daemon8\Severity; $client->push(new Observation( kind: Kind::HttpExchange, severity: Severity::Warn, data: ['method' => 'POST', 'url' => '/checkout', 'status' => 502, 'duration_ms' => 1200], channel: 'http.outbound', app: 'checkout-api', ));
Kinds
Kind::Log · Kind::Query · Kind::HttpExchange · Kind::Exception · Kind::JsException · Kind::Metric · Kind::StateSnapshot · Kind::Lifecycle · Kind::Custom
Severities
Severity::Trace · Severity::Debug · Severity::Info · Severity::Warn · Severity::Error
Severity::fromStatusCode(int) maps HTTP status codes (5xx → Error, 4xx → Warn, else → Info).
Sensitive data
Redaction has three complementary lanes. Configure once on SensitiveRules, wire it into Config.
use Daemon8\Sanitization\SensitiveRules; use Daemon8\Sanitization\Sensitive; $rules = new SensitiveRules( fields: ['password', 'api_key', 'authorization'], patterns: ['/\bsk-[a-z0-9]{24,}\b/i'], ); $config = Config::create(sensitiveRules: $rules); // Or wrap specific values at call sites: $client->send(['token' => Sensitive::wrap($token)], severity: 'debug');
- Field names — case-insensitive key match anywhere in the data tree, redacted to
[masked]. - Value wrapping —
Sensitive::wrap()forces redaction regardless of key. - Regex patterns — run against scalar values to catch structural leaks (JWTs, API keys, PANs).
Live subscription
Long-running processes can subscribe to the daemon's SSE stream and react to new observations:
use Daemon8\Observation\SseStream; use Daemon8\Observation\StreamEndpoint; use Daemon8\Filter; use Daemon8\Severity; $stream = new SseStream(StreamEndpoint::fromUrl('http://127.0.0.1:9077/api/stream')); $filter = new Filter( kinds: ['log', 'exception'], severityMin: Severity::Warn, ); foreach ($stream->subscribe($filter) as $observation) { handleAlert($observation); }
The stream reconnects with exponential backoff (1s → 2s → 4s → max 30s) and resumes from the last seen id via Last-Event-ID.
Transports
Default: ChainTransport([CurlMultiTransport, FsockopenTransport]). curl is preferred, raw sockets is the fallback when ext-curl is missing. UDP is available for ultra-low-overhead fire-and-forget (Daemon8::sendUdp() or UdpTransport).
Every transport implements Daemon8\Contracts\Transport. Supply your own via Daemon8Client construction if you need queue-backed or bespoke wire semantics.
Requirements
- PHP 8.4+
ext-jsonext-curl(optional — falls back to fsockopen)ext-sockets(optional — required for UDP transport)
Development
composer install composer check # phpstan + rector dry-run + phpcs + phpunit composer test composer analyse composer cs:fix
Level 8 phpstan. Rector with phpunit + php84 sets. Slevomat coding standard.
License
MIT. See LICENSE.