Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Symfony Laravel Package

apirelio/symfony

Apirelio Symfony SDK links API errors, latency, and releases to affected customers without capturing request or response payloads. It records normalized endpoint metrics and customer context with fail-safe delivery, excluding credentials, cookies, query strings, IPs, and personal data. Supports PHP...

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package — if you're actually on Laravel, this repo isn't the one you want (Apirelio publishes a separate Laravel integration, and the concepts below — resolvers, error codes, release tagging, transport choice — port over nearly 1:1). For a Symfony API, the floor is about ten minutes:

composer require apirelio/symfony
# then confirm what you actually got, since README and release notes disagree on the version line
composer show apirelio/symfony
  1. Register the bundle in config/bundles.php (Apirelio\Symfony\ApirelioBundle::class => ['all' => true]). The subscriber auto-registers, so there is no event wiring to do.
  2. Set env vars — APIRELIO_API_KEY is the only one that must be real; give APIRELIO_ENABLED a default of false in .env so %env(bool:APIRELIO_ENABLED)% never fails to resolve on a fresh checkout.
  3. Add config/packages/apirelio.yaml with transport: messenger and a paths glob covering your API surface (- /api/*). Nothing outside paths is recorded.
  4. Route the message to a real async transport in messenger.yaml and start php bin/console messenger:consume async. Skipping this step is the single most common "it doesn't work" case (see Gotchas).
  5. First use case: attribute every failing /api/* request to the customer who made it, then read the dashboard filtered by release. That's the whole value proposition — "which accounts did the 2026.07.29.1 regression hit."

Validation loop before you write any resolver: set transport: sync, APIRELIO_ENDPOINT to your dashboard, hit one endpoint with curl, and confirm an event lands with the right route template (/api/invoices/{invoice}, not the concrete URL). Only then move to messenger. Where to look first: the config block in the README, Apirelio\Symfony\ApirelioManager (the per-request override surface), and the two contracts under Apirelio\Symfony\Contracts.

Implementation Patterns

Resolve identity from request attributes set by your auth layer, not from a DB call in the resolver. The documented pattern is the right one: an earlier listener (API-key/tenant middleware) does $request->attributes->set('api_client', $client), and CustomerResolver::resolve() just maps that object to ApirelioCustomer. The resolver runs inside the request boundary on every matched request — keep it allocation-only, and return null for unauthenticated traffic rather than fabricating a customer, or your 401s will pollute account-level error rates.

Populate plan deliberately. ApirelioCustomer(id, name, plan) is what lets you say "only the Enterprise accounts are seeing 504s from the invoices endpoint." If you don't have a plan concept, still pass your closest analogue (tier, contract size, internal flag) — it's the cheapest grouping dimension you get.

Error codes: prefer the convention over the override. If your API already returns {"error":{"code":"INVALID_CURRENCY"}}, error_code_json_path: error.code picks it up for free and you change nothing. Reserve ApirelioManager::setErrorCode() for endpoints whose errors aren't JSON-shaped — it's per-request mutable state, so set it inside a controller or a kernel.exception listener, not in a shared service.

public function __invoke(ApirelioManager $apirelio): Response
{
    $apirelio->addMetadata([
        'integration_type' => $this->client->integration,
        'region' => $this->client->region,
    ]);
    // metadata_keys: [integration_type, region] in apirelio.yaml, or it's dropped
}

Treat metadata_keys as a schema, not a suggestion. Anything not allow-listed, or any non-scalar value, is silently discarded. Agree on four to six keys with your team up front (integration type, region, API version class, endpoint category) and add them to config in the same PR that starts emitting them.

Drive release from CI, not from a human. APIRELIO_RELEASE=$(git describe --tags --always) or your deploy tag, set at container build/deploy time. The release dimension is the feature that makes regressions legible, and it's worthless if it's stale or hand-edited.

Pick the transport by operational reality:

Situation Transport Notes
You already run Messenger workers (most Symfony APIs) messenger Default; lowest request-path cost
No workers, shared hosting, or you want a hard guarantee of no in-request I/O file_buffer Schedule apirelio:flush via cron
Local dev, first integration, debugging a resolver sync Delivers inline; expect a couple hundred ms

Keep capture_headers minimal. x-api-version, x-sdk-version, user-agent are fine. Never add authorization, cookie, x-forwarded-for, or anything tenant-identifying beyond what the resolver already reports — the whole selling point is that payloads and personal data never leave the process, and you're one careless allowlist entry from breaking that promise yourself.

Correlate with your APM by key, not by duplication. Apirelio won't give you stack traces or request bodies. Join on release + route template + customer id to answer "which customers," and keep Sentry/OpenTelemetry for "why." If you need per-request linkage, emit a request id as an allow-listed metadata key and log it.

Split test/local traffic by config, not by branching in code: APIRELIO_ENABLED=false in .env.test, and distinct APIRELIO_ENVIRONMENT values per deploy target so staging latency never blends into production dashboards.

Gotchas and Tips

  • The default messenger transport does not mean async by itself. Without the BufferApirelioEvents → async routing rule, the message goes to Messenger's default transport (usually sync) and you get in-request delivery you thought you'd deferred. Verify with debug:messenger after installing.
  • Fail-safe means silent loss. Resolver, transport and logger failures are swallowed at the request boundary — by design, and correctly so, but the practical consequence is that a broken resolver looks exactly like "no traffic." Watch the logger output on the apirelio channel during rollout, and treat an empty dashboard after a deploy as a bug, not as quiet traffic.
  • Worker failures throw, unlike request-bound failures. A failed ingestion inside messenger:consume will retry and eventually hit your failure transport. Configure that transport, or a bad API key becomes a poisoned queue rather than a missing event.
  • buffer_path defaults to %kernel.cache_dir%, which cache:clear wipes. If you run file_buffer in production, point it at %kernel.project_dir%/var/apirelio/events.ndjson and ensure the web user can write it (the buffer uses locking, so NFS-shared paths are a bad idea).
  • apirelio:flush needs to be a cron, not a memory. Low-traffic services otherwise leave a partial batch sitting on disk indefinitely — and the gap only shows up as missing data during an incident.
  • Allow-listed metadata is discarded without a warning. When a metadata key doesn't show up in the dashboard, the cause is almost always a missing metadata_keys entry or a non-scalar value (an enum object, a DTO, an array) — not the transport.
  • Version drift is real. The README says composer require apirelio/symfony:^0.2; the release notes describe a stable v1.0.0. Pin whatever composer show confirms, and read both the 0.2.0 changelog entry and the release notes before upgrading — 0.2.0 renamed the namespace and moved the config key from tracium to apirelio, so any guide or snippet referencing tracium is stale.
  • Requirements bite at the edges: Symfony 8 requires PHP 8.4, so a PHP 8.2 shop is really choosing between Symfony 6.4 and 7.4. Add the bundle to your existing CI matrix rather than assuming the declared range is exercised.
  • Only main, matched requests are recorded. Sub-requests, console commands, and Messenger consumers themselves are out of scope — if most of your business logic runs async, coverage will look thin and that's expected, not broken.
  • Adoption risk is genuinely non-trivial: zero stars, zero dependents, one release line. Wrap access behind your own thin service or a NullApirelioManager-style no-op in dev so that ripping it out is a config and one class, not a codebase-wide search. Ship it behind APIRELIO_ENABLED from day one.
  • It's analytics, not alerting. Don't wire paging to it; latency and error attribution here is retrospective. Keep your existing SLO alerting on your own metrics and use Apirelio to answer "which customers" after the page fires.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge