makfly / beacon-sdk-php
Beacon telemetry SDK for PHP / Symfony 8 — errors, traces, logs. Home-grown, zero external instrumentation dependency.
Package info
github.com/MakFly/beacon-sdk-php
Type:symfony-bundle
pkg:composer/makfly/beacon-sdk-php
Requires
- php: >=8.2
- ext-curl: *
- ext-json: *
- psr/http-client: ^1.0
- psr/http-message: ^1.1 || ^2.0
Requires (Dev)
- doctrine/dbal: ^4.0
- monolog/monolog: ^3.0
- nyholm/psr7: ^1.8
- phpunit/phpunit: ^11.0
- symfony/config: ^7.0 || ^8.0
- symfony/dependency-injection: ^7.0 || ^8.0
- symfony/event-dispatcher: ^7.0 || ^8.0
- symfony/http-client: ^7.0 || ^8.0
- symfony/http-kernel: ^7.0 || ^8.0
- symfony/routing: ^7.0 || ^8.0
Suggests
- doctrine/dbal: To capture db_query spans via the Beacon Doctrine middleware
- monolog/monolog: To capture handled Throwables logged at ERROR+ as Beacon issues
- symfony/http-client: To capture PSR-18 http_client spans automatically
- symfony/http-kernel: For the Symfony bundle integration (exception capture, request spans)
- symfony/messenger: To trace queued message handling as entry points
- symfony/routing: For resolving Symfony route names to HTTP route templates
- symfony/security-core: For pseudonymous affected-user counts from authenticated requests
README
Beacon telemetry SDK for PHP / Symfony 8 — errors, traces, logs. Home-grown,
zero external instrumentation dependency (no open-telemetry/*, no sentry/*).
Ships as a Symfony bundle; the PHP namespace is KevStudios\Beacon\.
Install
composer require makfly/beacon-sdk-php php vendor/makfly/beacon-sdk-php/bin/setup
The setup script auto-configures your Symfony project (idempotent, safe to re-run):
config/bundles.php— registersBeaconBundlefor all environmentsconfig/packages/beacon.yaml— creates the config with safe defaults.env/.env.example— appendsBEACON_ENDPOINTandBEACON_TOKEN
That's it. By default the SDK is a silent no-op — zero network calls, zero overhead. Set the env vars to activate:
# .env.local BEACON_ENDPOINT=https://ingest.pulseview.app BEACON_TOKEN=priv_my_project
The generated configuration uses https://ingest.pulseview.app. Override
BEACON_ENDPOINT for a self-hosted installation or an internal Docker address.
The empty token keeps the SDK disabled until a project credential is provided.
Before the package is on Packagist, add a VCS repository:
"repositories": [{ "type": "vcs", "url": "https://github.com/MakFly/beacon-sdk-php.git" }]
How it works
| Env vars set? | Behavior |
|---|---|
| Both set | Errors, traces and logs are sent to the ingester |
| Empty or absent | Silent no-op — no cURL, no overhead |
Unhandled kernel exceptions are captured automatically via ExceptionSubscriber.
The buffer flushes on kernel.terminate (post-response). The transport swallows
every failure — telemetry never breaks the host app.
Handled exceptions passed to Monolog at ERROR or above are also captured automatically
as issues, including failures logged by long-running Messenger workers. The SDK flushes
that exception immediately and deduplicates it when the same Throwable is already owned
by the kernel exception subscriber. Set capture_monolog_exceptions: false to disable this
integration. Regular application logs must still be written as JSON to stdout/stderr and
collected out of process; the deprecated beacon.monolog_handler is not used by default.
HTTP exceptions are classified from the final response status: 4xx occurrences stay
handled, while 5xx occurrences are unhandled and force retention of their complete
request trace even when normal trace sampling would discard it. Errors carry the active
traceId and spanId, so the dashboard can open the exact failing trace and span.
When Symfony Security is available, authenticated users are counted through a stable
HMAC identifier (usr_…). The raw login/email is never sent. This is enabled by default
and uses %kernel.secret%; set capture_user: false to disable it or user_hash_key to
use a dedicated rotation-controlled key.
Transport attempts time out after 2 seconds and retry network failures, 408, 429
and 5xx with exponential jitter while honoring Retry-After. Failed batches remain
in a bounded in-memory backlog (max_backlog_items, default 500). Trace sampling is
deterministic via traces_sample_rate, and sensitive keys are redacted recursively in
errors, spans and logs.
W3CPropagator injects and extracts traceparent, tracestate and baggage for
cross-service context propagation.
When Doctrine DBAL 4 is installed, the Symfony bundle automatically records queries,
prepared statements and exec() calls as db_query child spans. SQL literals are
replaced with placeholders before capture: the waterfall exposes the real duration
without leaking parameter values.
When Symfony's concrete PSR-18 client is registered, the bundle decorates it automatically
and records external calls as http_client child spans. Names use only the HTTP method and
host to stay low-cardinality. Paths, query strings, headers and request bodies are never
captured.
Configuration
All options in config/packages/beacon.yaml (with defaults):
parameters: # Default to empty STRING when the env var is unset (prod with no ingester yet). # Critical: CurlSender expects a `string` — '' constructs + silently no-ops, whereas # `null` (what `%env(default::...)%` returns) throws a TypeError at boot → 500 → rollback. env(BEACON_ENDPOINT): '' env(BEACON_TOKEN): '' beacon: endpoint: '%env(BEACON_ENDPOINT)%' # ingester URL (empty = disabled) token: '%env(BEACON_TOKEN)%' # project token (empty = disabled) service_name: 'iautos-api' # optional service_version: ~ # optional (null) stage: '%kernel.environment%' # optional application_path: '%kernel.project_dir%' # optional collect_arguments: false # opt-in: may contain sensitive values traces_sample_rate: 1.0 # 0.0–1.0 capture_user: true # pseudonymous affected-user identity capture_monolog_exceptions: true # handled Throwable objects logged at ERROR+ user_hash_key: ~ # defaults to %kernel.secret% max_backlog_items: 500 # bounded in-memory retry backlog censor_keys: # scrubbed from attributes - password - authorization - cookie - token - secret - api_key
Versioning & release
SemVer via git tags (Packagist-driven). See CLAUDE.md. Tags are immutable.
License
MIT. Part of the Beacon telemetry suite.