apirelio/php-core
Framework-independent PHP 8.2+ core for Apirelio API monitoring SDKs. Provides the stable privacy-safe event contract, customer and application value objects, metadata privacy rules, error-code extraction, HTTP retry orchestration and a locked local file buffer for fail-safe delivery.
What v1.0.0 actually is: the shared, framework-agnostic telemetry core, not a Laravel-specific package. Treat it as a dependency you compose into your app rather than something you artisan your way through. The 1.0.0 tag mostly buys you API stability and a wider PHP floor/ceiling (8.2–8.5).
php -v before anything else. If you're on 8.1 you're locked out; if you're on 8.5 you're on the newest supported version, which is exactly the kind of thing to smoke-test rather than assume — 8.5 is recent enough that transitive dependencies may lag even though the core claims support.composer require <vendor>/apirelio-telemetry-core:^1.0. Pin with ^1.0 now that it's stable; during 0.x you'd have wanted ~0.x.y.composer.json before the README. Look for two things: a laravel key under extra (auto-discovery of a service provider = zero-config) and whether a psr/* or framework adapter is a require or a suggest. A "core" that suggests an adapter is telling you the wiring is your job.src/ for the public entrypoints — typically a tracer/meter factory, an exporter interface, a context/scope object, and a sampler. Those four are the whole surface area you'll actually touch.If a Laravel adapter package exists alongside the core, install it and read its service provider instead — that's where config keys and container bindings will be documented.
Hide the core behind one small internal service. You will not want Apirelio\...\Tracer::startSpan() calls scattered through controllers. Wrap it:
final class Telemetry
{
public function __construct(private readonly TracerInterface $tracer) {}
public function span(string $name, array $attrs = [], Closure $fn): mixed
{
$span = $this->tracer->startSpan($name, $attrs);
try { return $fn($span); }
finally { $span->end(); }
}
}
Bind the core's concrete tracer to this in a provider. When the core's API shifts in 1.1, you edit one file.
Propagate context at the framework boundaries, nowhere else. Three places matter in a Laravel app:
traceparent-style headers into the core's scope and starts a root span.JobProcessing listener) that serialises the current context into the payload on dispatch and restores it on handle(). Without this every queued job starts a fresh orphan trace — the single most common integration failure.schedule:run children aren't invisible.Sampling belongs in config, and it belongs to be environment-aware. 100% in local, parentbased_traceidratio in production. Read the ratio from config() at boot, not per-request — you want it fixed per worker.
Make tests quiet by default. Bind a no-op exporter in phpunit.xml's env block so the suite doesn't emit network calls, then write a handful of tests against an in-memory exporter that assert span names and attributes. Assert on names and counts, not on timings.
Octane and long-running workers: confirm the core resets its active scope between requests. If there's no documented reset hook, add terminating middleware that clears the scope explicitly. Leaked spans across requests produce absurd parent-child graphs and are miserable to diagnose.
extra.laravel is absent, nothing happens until you write a provider. Don't file a bug — read the install docs for the adapter.composer.lock so a 1.0.1 doesn't land on a Friday.user_id, order_id, request IDs → fine. Full URLs, query strings, exception messages with interpolated values → your telemetry bill and your query performance. Sanitise at the wrapper layer, not at each call site.app.user.id, http.route) on day one. Renaming later invalidates every dashboard you built.try/finally above ends the span; it does not mark it errored. Call the core's recordException() in a catch and rethrow. Silent error spans are worse than no spans.How can I help you explore Laravel packages today?