PHPackages                             dennisvanbeersel/symfony-logger-client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. dennisvanbeersel/symfony-logger-client

Abandoned → [applogger/symfony-bundle](/?search=applogger%2Fsymfony-bundle)Symfony-bundle[Logging &amp; Monitoring](/categories/logging)

dennisvanbeersel/symfony-logger-client
======================================

Symfony bundle for Application Logger error tracking platform

v2.1.0(1mo ago)0477MITJavaScriptPHP &gt;=8.3CI passing

Since Oct 27Pushed 1mo agoCompare

[ Source](https://github.com/dennisvanbeersel/symfony-logger-client)[ Packagist](https://packagist.org/packages/dennisvanbeersel/symfony-logger-client)[ Docs](https://applogger.eu)[ RSS](/packages/dennisvanbeersel-symfony-logger-client/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (10)Dependencies (31)Versions (11)Used By (0)

AppLogger Symfony Client
========================

[](#applogger-symfony-client)

> Symfony bundle for the [AppLogger](https://applogger.eu) error tracking and application monitoring platform — automatic exception capture, log aggregation, a frontend JavaScript SDK, and non-blocking, resilient delivery.

[![Packagist Version](https://camo.githubusercontent.com/9c02e9586b679e42bcd920e2ae65514636f24c22ca76a4cd9d7919c3cce5eb15/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6170706c6f676765722f73796d666f6e792d62756e646c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/applogger/symfony-bundle)[![Total Downloads](https://camo.githubusercontent.com/98c86b35d4cccf59fbc3ccc98214b5512c05e4deab1125ef9f16eda766312183/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6170706c6f676765722f73796d666f6e792d62756e646c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/applogger/symfony-bundle)[![PHP Version](https://camo.githubusercontent.com/91fba9611df6b694566e475994a90547bb7086db31fee471cc180f70289c272e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6170706c6f676765722f73796d666f6e792d62756e646c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/applogger/symfony-bundle)[![License](https://camo.githubusercontent.com/2dcaaea48c1365363c68fd7cb8e965839caad5379a2deb84a0a6d71d2c8e75a0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6170706c6f676765722f73796d666f6e792d62756e646c652e7376673f7374796c653d666c61742d737175617265)](https://github.com/dennisvanbeersel/symfony-logger-client/blob/master/LICENSE)

---

What is this?
-------------

[](#what-is-this)

This package is the Symfony client bundle for **[AppLogger](https://applogger.eu)** (`applogger.eu`), an EU-hosted, privacy-first error tracking and application/log monitoring SaaS built for Symfony and PHP applications.

Once installed and enabled, the bundle wires itself into your application and ships telemetry to the AppLogger platform through three channels:

- **Error tracking** — uncaught exceptions and exception-bearing Monolog records are sent to the platform, where they are grouped and fingerprinted into error groups (backed by PostgreSQL).
- **Log aggregation** — non-exception Monolog records at or above your configured capture level are batched and forwarded to the AppLogger log collector (backed by ClickHouse).
- **Frontend errors** — a bundled JavaScript SDK captures browser exceptions, unhandled promise rejections, and failed requests, with optional error-triggered session replay.

A central design goal of the bundle is that **telemetry delivery never delays or breaks the host application**. Sending is asynchronous and fire-and-forget by default, completes after the HTTP response has already been flushed to the user, and is guarded end-to-end so that no transport, encoding, or configuration failure propagates into your application's request handling.

The platform provides EU data residency, IP anonymization, PII scrubbing, and session-id hashing to support GDPR-conscious deployments.

---

Features
--------

[](#features)

- **Automatic exception capture** — uncaught exceptions are captured via an event subscriber (no manual instrumentation required).
- **Automatic Monolog capture** — any Monolog record carrying a `\Throwable` in its context is routed to error tracking; other records at or above your capture level are routed to log aggregation. Wiring is done automatically — you do not edit `monolog.yaml`.
- **Non-blocking, resilient delivery** — asynchronous transport with a per-pipeline circuit breaker; delivery is completed on `kernel.terminate` (after the response is sent), with a bounded fallback for CLI and Messenger workers.
- **Never throws into the host** — the dispatch path is wrapped so transport, encoding, and configuration failures are recorded internally rather than surfaced to your code.
- **Log aggregation** — buffered, batched log shipping to the AppLogger log collector with memory-bounded buffers.
- **Bundled JavaScript SDK** — frontend error capture with its own client-side circuit breaker, offline queue, rate limiting, and deduplication. Optional automatic injection via Twig.
- **Error-triggered session replay (opt-in)** — captures DOM snapshots and interactions around an error; sent together with the error payload.
- **GDPR-oriented data scrubbing** — key-based redaction of sensitive fields, query-string and URL credential redaction, and IP anonymization, all performed before data leaves your host.
- **Inert-by-default install** — auto-registers via Symfony Flex and ships disabled until you opt in; installs cleanly even in API-only apps without Twig.

---

Requirements
------------

[](#requirements)

The Composer-enforced runtime requirements are:

RequirementConstraintPHP`>=8.3``symfony/framework-bundle``^6.4 || ^7.0 || ^8.0``symfony/http-kernel``^6.4 || ^7.0 || ^8.0``symfony/monolog-bundle``^3.0 || ^4.0``symfony/http-client``^6.4 || ^7.0 || ^8.0``symfony/uid``^6.4 || ^7.0 || ^8.0`> **Note:** The JavaScript SDK is shipped pre-built in `assets/dist/`, so a Node.js toolchain is **not** required to use it. `symfony/asset-mapper`, `symfony/twig-bundle`, and `twig/twig` are development dependencies of this package — their absence in your application is tolerated, and the bundle remains fully functional. AssetMapper integration is wired automatically when AssetMapper is present; the Twig-based JS auto-injection is simply removed when Twig is not installed.

---

Installation
------------

[](#installation)

Install with Composer:

```
composer require applogger/symfony-bundle
```

### With Symfony Flex (recommended)

[](#with-symfony-flex-recommended)

If your application uses Symfony Flex, the bundle is registered automatically and a Flex recipe is applied. The recipe:

- registers `ApplicationLogger\Bundle\ApplicationLoggerBundle` for all environments,
- installs a `config/packages/application_logger.yaml` configuration file,
- appends environment-variable placeholders to your `.env`:

```
APPLICATION_LOGGER_DSN=https://your-logger-host.com/your-project-id
APPLICATION_LOGGER_API_KEY=your-api-key-here
APPLICATION_LOGGER_PUBLISHABLE_KEY=
APPLICATION_LOGGER_ENABLED=false
```

**The bundle ships inert after installation.** Both PHP error tracking and the JavaScript SDK are gated on `APPLICATION_LOGGER_ENABLED`, which the recipe sets to `false`. To start sending telemetry, set your real credentials (preferably in `.env.local`) and flip the flag:

```
# .env.local
APPLICATION_LOGGER_DSN=https:///
APPLICATION_LOGGER_API_KEY=              # server-side only — keep secret
APPLICATION_LOGGER_PUBLISHABLE_KEY=pk_live_       # browser JS errors — safe to embed
APPLICATION_LOGGER_ENABLED=true
```

> **Two credentials, two purposes.** The `api_key` (format: any string) is your **server-side secret** — it is sent from PHP via `X-Api-Key` and must never appear in browser-facing HTML. The `publishable_key` (format: `pk_live_…`) is a **write-only, browser-safe key** — it is embedded in the auto-injected JS SDK and used exclusively for browser JS error ingest at `/api/v1/js-errors` via `X-Publishable-Key`. Obtain the publishable key from your project's **Settings &gt; Publishable Keys** page on AppLogger.

The recipe also defaults `release` to `%env(default::APP_VERSION)%`, `environment` to `%kernel.environment%`, and `debug` to `%kernel.debug%`.

### Without Flex (manual setup)

[](#without-flex-manual-setup)

1. Register the bundle in `config/bundles.php`:

    ```
    return [
        // ...
        ApplicationLogger\Bundle\ApplicationLoggerBundle::class => ['all' => true],
    ];
    ```
2. Create `config/packages/application_logger.yaml`. A minimal configuration needs a DSN, a server-side API key, and — to enable browser JS error tracking — a publishable key:

    ```
    application_logger:
        dsn: '%env(APPLICATION_LOGGER_DSN)%'
        api_key: '%env(APPLICATION_LOGGER_API_KEY)%'         # server-side secret; sent as X-Api-Key
        publishable_key: '%env(APPLICATION_LOGGER_PUBLISHABLE_KEY)%'  # browser JS; safe to embed
        enabled: '%env(bool:APPLICATION_LOGGER_ENABLED)%'
        environment: '%kernel.environment%'
    ```
3. Add the corresponding environment variables to `.env` / `.env.local` and clear the cache:

    ```
    php bin/console cache:clear
    ```

> The bundle does **not** require a Monolog handler to be declared by hand. It prepends its own `service`-type Monolog handler automatically on the channels `!event`, `!request`, and `!php` (those framework channels are excluded to avoid double-recording uncaught exceptions, which are already handled by the exception subscriber).

---

Configuration
-------------

[](#configuration)

The configuration root key is `application_logger`. The DSN and API key are the only values required to start sending; everything else has a sensible default.

> **v2.0 note:** The bundle is now a thin Symfony adapter over [`applogger/sdk-core`](https://packagist.org/packages/applogger/sdk-core). Error capture routes through the SDK Hub; log aggregation routes through LogClient. Several configuration keys that were previously active (`endpoint_path`, `log_path`, `log_batch_size`, `max_log_buffer`, `retry_attempts`, `async`, `circuit_breaker.enabled`) are now **deprecated no-ops** — they are accepted without error but have no effect, and will be removed in a future major version. Remove them from your config to silence deprecation notices.

### DSN and authentication

[](#dsn-and-authentication)

The DSN identifies your project endpoint and has the form:

```
https:///

```

The client-internal parser validates that a project-id path segment exists. **The API key is not embedded in the DSN** — it is sent separately in the `X-Api-Key` request header.

Authentication summary:

ChannelCredentialHeaderDestinationError &amp; session tracking (server-side PHP)`api_key` — secret, server only`X-Api-Key: `Platform API host (from the DSN)Log aggregation (server-side PHP)`log_token` (`sk_log_…`) — secret, server only`X-Api-Key: ``log_endpoint` (the AppLogger log collector)Browser JS error ingest`publishable_key` (`pk_live_…`) — write-only, safe to embed`X-Publishable-Key: ``/api/v1/js-errors` on the platform API hostInertness rules:

- An **empty** DSN or API key makes the corresponding feature short-circuit silently (no requests, no errors).
- A **non-empty but malformed** DSN is treated as active misconfiguration and raises `InvalidArgumentException` (so genuine misconfiguration surfaces early rather than silently dropping telemetry).
- If `log_endpoint` or `log_token` is empty/null, log aggregation silently no-ops.

### Core options

[](#core-options)

OptionTypeDefaultDescription`dsn`string`''`Project endpoint URL `https://host/project-id`. Contains no credentials — safe to appear in browser JS config (the JS SDK also receives it as the `dsn` prop). Empty = inert. Deliberately not required, so a skipped Flex recipe never breaks `cache:clear`.`api_key`string`''`**Server-side secret.** Sent as `X-Api-Key` from PHP. Empty = inert. Never expose to the browser.`publishable_key`string`''`**Browser-safe write-only key** (`pk_live_…`). Embedded in the auto-injected JS SDK; sent as `X-Publishable-Key` for browser JS error ingest at `/api/v1/js-errors`. Obtain from your project's Settings &gt; Publishable Keys page. Empty = JS SDK not injected.`enabled`bool`true`Global error-tracking enable.`release`string`null`Version / release identifier.`environment`string`'production'`Environment name reported with telemetry.`error_tracking_enabled`bool`true`Capture and ship exceptions/errors. Set `false` to run log-aggregation only.`log_aggregation_enabled`bool`true`Buffer and ship non-exception log records. Set `false` to run error-tracking only.`endpoint_path`string`/api/v1/errors`*(Deprecated in v2.0 — no-op; the SDK core owns this.)*### Log aggregation

[](#log-aggregation)

OptionTypeDefaultDescription`log_endpoint`string`null`Collector base URL, e.g. `https://.logs.applogger.eu`. `null` = aggregation off.`log_token`string`null`Log token (`sk_log_…`), sent as `X-Api-Key` to the collector.`excluded_channels`array`['http_client','console','deprecation','doctrine']`Monolog channels excluded from log aggregation (beyond the always-excluded framework channels). Set to `[]` to aggregate all channels.`log_path`string`/v1/logs`*(Deprecated in v2.0 — no-op; the SDK core owns this.)*`log_batch_size`int`50`*(Deprecated in v2.0 — no-op; the SDK core owns this.)*`max_log_buffer`int`1000`*(Deprecated in v2.0 — no-op; the SDK core owns this.)*### Performance &amp; resilience

[](#performance--resilience)

OptionTypeDefaultDescription`timeout`float`2.0`Request timeout in seconds (min 0.5, max 5.0).`flush_budget`float`2.0`Wall-clock cap (s) on the post-response telemetry drain. Effective cap = `min(timeout, flush_budget)`. Lower to `0.5` to harden FrankenPHP worker pools against a slow collector.`debug`bool`false`Internal PHP debug logging.`retry_attempts`int`0`*(Deprecated in v2.0 — no-op; the SDK core owns this.)*`async`bool`true`*(Deprecated in v2.0 — no-op; the SDK core owns this.)*### Circuit breaker (`circuit_breaker`)

[](#circuit-breaker-circuit_breaker)

The circuit breaker is owned by `applogger/sdk-core` in v2.0 and is always-on. The `enabled` key is accepted but has no effect.

OptionTypeDefaultDescription`enabled`bool`true`*(Deprecated in v2.0 — no-op; the SDK core's circuit breaker is always-on.)*`failure_threshold`int`5`Failures before the circuit opens (min 1).`timeout`int`60`Seconds the circuit stays open (min 10, max 300).`half_open_attempts`int`1`Trial requests allowed while half-open (min 1).### Capture

[](#capture)

OptionTypeDefaultDescription`capture_level`string`error`Minimum Monolog level routed by the handler (`debug`–`emergency`). An invalid literal falls back to `error` at runtime rather than throwing.`scrub_fields`arraysee belowField names redacted before sending (kept in sync with the JS list).`max_breadcrumbs`int`50`Maximum breadcrumbs retained (min 10, max 100).### JavaScript (`javascript`)

[](#javascript-javascript)

OptionTypeDefaultDescription`enabled`bool`true`Enable the frontend SDK.`auto_inject`bool`true`Automatically inject the SDK into HTML responses.`debug`bool`false`SDK debug logging.`environment`string`null`Falls back to the root `environment`.`release`string`null`Falls back to the root `release`.`scrub_fields`array`[]`Merged (deduplicated) with the root `scrub_fields`.### Session tracking (`session_tracking`)

[](#session-tracking-session_tracking)

OptionTypeDefaultDescription`enabled`bool`true`Required for session replay.`track_page_views`bool`true`Record page-view events.`idle_timeout`int`1800`Idle timeout in seconds (min 300, max 7200).`ignored_routes`array`['_profiler', '_wdt']`Routes excluded from tracking.`ignored_paths`array`['/api/', '/_fragment']`Path prefixes excluded from tracking.### Session replay (`session_replay`)

[](#session-replay-session_replay)

These values are forwarded to the JavaScript SDK. Replay is **error-triggered only** (never continuous). See [Session replay](#session-replay-opt-in) for the important note on default state.

OptionTypeDefaultDescription`enabled`bool`true`Error-triggered replay enable (see note below).`buffer_before_error_seconds`int`30`Seconds buffered before an error (min 5, max 60).`buffer_before_error_clicks`int`10`Clicks buffered before an error (min 1, max 15).`buffer_after_error_seconds`int`30`Seconds buffered after an error (min 5, max 60).`buffer_after_error_clicks`int`10`Clicks buffered after an error (min 1, max 15).`snapshot_throttle_ms`int`1000`DOM snapshot throttle (min 500, max 5000).`click_debounce_ms`int`1000`Click debounce (min 100, max 5000).`max_snapshot_size`int`1048576`Max snapshot size in bytes (min 102400, max 5242880).`session_timeout_minutes`int`30`Replay session timeout (min 5, max 120).`max_buffer_size_mb`int`5`Max replay buffer size in MB (min 1, max 20).`expose_api`bool`true`Expose the JS enable/disable/isEnabled runtime API.### Realistic example

[](#realistic-example)

```
# config/packages/application_logger.yaml
application_logger:
    dsn: '%env(APPLICATION_LOGGER_DSN)%'
    api_key: '%env(APPLICATION_LOGGER_API_KEY)%'             # server-side secret
    publishable_key: '%env(APPLICATION_LOGGER_PUBLISHABLE_KEY)%'  # browser JS — safe to embed
    enabled: '%env(bool:APPLICATION_LOGGER_ENABLED)%'
    environment: '%kernel.environment%'
    release: '%env(default::APP_VERSION)%'

    # Resilience (timeout and flush_budget; async/retry_attempts are v2.0 no-ops)
    timeout: 2.0
    # flush_budget: 0.5  # Uncomment to harden FrankenPHP worker pools

    circuit_breaker:
        failure_threshold: 5
        timeout: 60

    # Capture
    capture_level: error
    max_breadcrumbs: 50

    # Log aggregation (optional — omit log_endpoint/log_token to disable)
    log_endpoint: '%env(default::APPLICATION_LOGGER_LOG_ENDPOINT)%'
    log_token: '%env(default::APPLICATION_LOGGER_LOG_TOKEN)%'

    # Frontend SDK
    javascript:
        enabled: '%env(bool:APPLICATION_LOGGER_ENABLED)%'
        auto_inject: true

    session_replay:
        enabled: true
```

---

Usage
-----

[](#usage)

### Automatic exception capture (zero-config)

[](#automatic-exception-capture-zero-config)

Once the bundle is enabled with a valid DSN and API key, uncaught exceptions are captured automatically. The exception subscriber listens on `kernel.exception` at a low priority (`-100`, after the framework's own handlers), extracts the HTTP status code (the status of an `HttpExceptionInterface`, otherwise `500`), attaches `exception_class` and `exception_code` tags plus a breadcrumb, and sends the error payload. The subscriber is wrapped in its own try/catch and never interferes with your application's exception handling.

No code changes are needed for this.

### Manual capture via Monolog

[](#manual-capture-via-monolog)

Because the bundle auto-registers a Monolog handler, the most natural way to record events from your own code is to log through Monolog. The handler routes records by content:

- a record whose `context['exception']` is a `\Throwable` is sent to **error tracking**;
- any other record at or above `capture_level` is sent to **log aggregation**.

```
use Psr\Log\LoggerInterface;

final class CheckoutService
{
    public function __construct(private readonly LoggerInterface $logger)
    {
    }

    public function process(Order $order): void
    {
        try {
            // ... domain logic ...
        } catch (\Throwable $e) {
            // Routed to error tracking (carries a Throwable in context).
            $this->logger->error('Checkout failed', [
                'exception' => $e,
                'order_id'  => $order->getId(),
            ]);

            throw $e;
        }
    }
}
```

### Log aggregation via Monolog

[](#log-aggregation-via-monolog)

Records without an exception that meet the `capture_level` threshold are buffered and shipped to the log collector in batches:

```
$this->logger->warning('Payment gateway latency elevated', [
    'gateway' => 'acme-pay',
    'latency_ms' => 812,
]);
```

Each record is converted into a log entry with an RFC3339 timestamp, an RFC5424 severity keyword (`debug`, `info`, `notice`, `warning`, `error`, `critical`, `alert`, `emergency`), the Monolog channel as the application name, the environment, and a scrubbed, flattened context map. Entries are sent to `POST ` (or the `/batch` variant for batches); a successful ingestion returns `HTTP 202 Accepted`. If no `log_endpoint` / `log_token` is configured, log aggregation is silently skipped.

### Smoke-test the log channel

[](#smoke-test-the-log-channel)

Verify collector credentials without booting Symfony:

```
# Single LogEntry
curl -i -X POST "$LOG_ENDPOINT/v1/logs" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $LOG_TOKEN" \
  -d '{"timestamp":"2026-06-22T10:00:00Z","severity":"info","message":"ping","app_name":"smoke-test","environment":"prod","context":{"source":"curl"}}'
# → 202 {"accepted":1,"dropped":0}   (400 {"error":"invalid_json"} on a bad body)

# Batch
curl -i -X POST "$LOG_ENDPOINT/v1/logs/batch" \
  -H "Content-Type: application/json" -H "X-Api-Key: $LOG_TOKEN" \
  -d '{"logs":[{"timestamp":"2026-06-22T10:00:00Z","severity":"info","message":"ping","app_name":"smoke-test","environment":"prod","context":{}}]}'
```

Or, with the bundle installed: `php bin/console application-logger:test`.

`LogEntry` fields: `timestamp` (RFC3339), `severity` (syslog keyword), `message`(≤8000), `app_name` (≤255), `environment`, `context` (map of string→string).

### JavaScript SDK

[](#javascript-sdk)

The bundled SDK uses the **publishable key** (`pk_live_…`) for browser error ingest — never the secret `api_key`. The publishable key is write-only and safe to embed in HTML. Obtain it from your project's **Settings &gt; Publishable Keys** page on AppLogger, then set it in `.env.local`:

```
# .env.local
APPLICATION_LOGGER_PUBLISHABLE_KEY=pk_live_
```

and declare it in `config/packages/application_logger.yaml`:

```
application_logger:
    publishable_key: '%env(APPLICATION_LOGGER_PUBLISHABLE_KEY)%'
```

When `publishable_key` is non-empty and `javascript.enabled` is `true` (the default), the bundle auto-injects the SDK into eligible HTML responses. The SDK sends browser errors to `/api/v1/js-errors` via `X-Publishable-Key`.

With `javascript.auto_inject` enabled (the default), injection is automatic for main requests with a `text/html` content type, a status below 400, a `` tag, and a body under 1 MiB. Error pages (4xx/5xx) are deliberately skipped.

If you prefer to place the SDK yourself (and Twig is available), disable `auto_inject` and call the Twig function just before ``:

```
{# templates/base.html.twig #}
    {{ application_logger_init() }}

```

At runtime the SDK is exposed as `window.appLogger`. It automatically captures `window` `error` events, unhandled promise rejections, failed fetch/HTTP requests, and `console.error()` breadcrumbs. When `expose_api` is enabled (the default), you can also report manually:

```
// Capture an exception
window.appLogger.captureException(new Error('Manual report'), {
  tags: { feature: 'checkout' },
});

// Capture a message
window.appLogger.captureMessage('User completed onboarding', 'info');

// Enrich context
window.appLogger.setUser({ id: '123' });
window.appLogger.setTags({ plan: 'pro' });
window.appLogger.addBreadcrumb({ category: 'ui', message: 'Opened modal' });
```

The SDK is resilient on the client side too: a sessionStorage-backed circuit breaker (default threshold 5, 60s open window), a localStorage offline queue (default 50 events, 24h max age), token-bucket rate limiting (default burst of 10, refilling at ~10/minute — 0.167 tokens/second), and deduplication (default 5s window). On page close it uses the Beacon API to flush queued events. Breadcrumbs are capped at 50 by default.

### Session replay (opt-in)

[](#session-replay-opt-in)

Session replay is **error-triggered only** — it never records continuously. When enabled, the SDK buffers a window of DOM snapshots and interactions before and after an error and sends that data **together with the error payload** (not as a separate request). Cross-page continuity is maintained via localStorage.

Session tracking (`session_tracking.enabled`) must be on for replay to function.

> **Important — default state:** Replay is an opt-in feature. The JavaScript SDK itself defaults `sessionReplayEnabled` to `false`, while the bundle's PHP `session_replay.enabled` config node defaults to `true`; the effective value forwarded to the SDK is whatever the PHP configuration / Twig integration provides. Treat replay as **opt-in and error-triggered**, and explicitly confirm `session_replay.enabled` in your configuration to match your intended behavior. When `expose_api` is `true`, replay can also be toggled at runtime:

```
window.appLogger.sessionReplay.enable();
window.appLogger.sessionReplay.disable();
window.appLogger.sessionReplay.isEnabled();
```

### The non-blocking, never-throws guarantee

[](#the-non-blocking-never-throws-guarantee)

By default (`async: true`) telemetry is dispatched fire-and-forget and completed **after** the HTTP response has been flushed to the client:

- On the web, a `kernel.terminate` subscriber (priority `-1024`, runs last) flushes buffered logs and then completes any in-flight error requests, so the user is never delayed by telemetry. This also makes **same-host self-monitoring safe** — the send finishes after the response is sent.
- For CLI commands and Messenger workers (which have no `kernel.terminate`), a bounded destructor-based fallback completes outstanding requests within a short time budget.
- Post-response completion is capped (at `min(timeout, 2.0)` seconds) so a slow backend cannot stall worker recycling.

The single dispatch envelope is guarded throughout: the global kill-switch, JSON encoding, the circuit breaker, and the transport itself are all wrapped so failures are recorded internally and **never thrown into your application**. The only intentional exceptions are at construction time (an out-of-range `timeout`, or a non-empty but malformed DSN), which surface genuine misconfiguration early.

---

Privacy &amp; GDPR
------------------

[](#privacy--gdpr)

The bundle is designed to scrub sensitive data **on your host, before anything is transmitted**:

- **Key-based field redaction.** Values whose key name (case-insensitive substring match) contains a configured scrub fragment are replaced with `[REDACTED]`, recursively (depth-limited). The default PHP scrub fields are:

    ```
    password, token, api_key, secret, authorization,
    credit_card, creditcard, card_number, cvv, ssn, iban

    ```

    > This redaction is key-based: values stored under non-matching keys are not inspected, so secrets embedded in free-form text under an innocuous key are not caught. Add your own field names via `scrub_fields` as needed. The JavaScript SDK maintains its own (broader) default scrub list — the two lists are kept in parallel rather than shared, so configure both if you add custom fields.
- **URL and query-string redaction.** Query-string values whose name matches a scrub fragment are redacted, and embedded userinfo credentials (`user:pass@host`) are always redacted, while scheme, host, port, path, and fragment are preserved.
- **IP anonymization.** IPv4 addresses have their last octet masked (e.g. `192.168.1.100` → `192.168.1.0`); IPv6 addresses keep the first 48 bits and zero the remaining 80 bits. Invalid or null inputs return `null` — a raw IP is never echoed.
- **Session-id hashing.** Session identifiers are SHA-256 hashed before leaving the host.

The AppLogger platform itself is EU-hosted with EU data residency. As with any monitoring tool, review what your application logs and adjust `scrub_fields` to match your data-protection obligations.

---

The AppLogger.eu platform
-------------------------

[](#the-apploggereu-platform)

[AppLogger](https://applogger.eu) is an EU-hosted, privacy-first error tracking and application/log monitoring SaaS built on a Symfony stack:

- **Error tracking** — errors are grouped and fingerprinted into error groups, backed by PostgreSQL.
- **Log aggregation** — high-volume logs are stored in ClickHouse, ingested through a dedicated log collector.
- **Privacy by design** — EU data residency, IP anonymization, PII scrubbing, and session-id hashing.

### Getting a DSN and tokens

[](#getting-a-dsn-and-tokens)

1. Sign up at **[applogger.eu](https://applogger.eu)**.
2. Create a project to obtain its **DSN** and **API key** (server-side; used for error and session tracking from PHP).
3. For browser JS error tracking, obtain the project's **Publishable Key** (`pk_live_…`) from **Settings &gt; Publishable Keys**. This is safe to embed in HTML.
4. For log aggregation, obtain the project's **log endpoint** and **log token** (`sk_log_…`).
5. Put these values in your `.env.local` and set `APPLICATION_LOGGER_ENABLED=true`.

---

Links
-----

[](#links)

- **Website &amp; sign-up:**
- **Package repository &amp; issues:**
- **Documentation &amp; guides** (API, setup, security):

---

Contributing
------------

[](#contributing)

Contributions are welcome. Please open issues and pull requests on the [package repository](https://github.com/dennisvanbeersel/symfony-logger-client).

The project follows PSR-12 with `declare(strict_types=1)` and is checked at PHPStan level 6. Convenience Composer scripts are provided:

```
composer test       # Run the PHPUnit test suite
composer cs-check   # Check coding style (PHP-CS-Fixer)
composer cs-fix     # Apply coding-style fixes
composer phpstan    # Run static analysis
composer lint       # cs-check + phpstan
```

Please ensure `composer lint` and `composer test` pass before submitting a pull request.

---

Security
--------

[](#security)

If you discover a security vulnerability, please report it responsibly rather than opening a public issue. Use the security advisory channel on the [package repository](https://github.com/dennisvanbeersel/symfony-logger-client/security) so it can be addressed before public disclosure.

---

License
-------

[](#license)

Released under the [MIT License](https://github.com/dennisvanbeersel/symfony-logger-client/blob/master/LICENSE).

Authored by Dennis Van Beersel — [applogger.eu](https://applogger.eu).

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance90

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~27 days

Recently: every ~5 days

Total

10

Last Release

52d ago

Major Versions

v0.3.2 → v2.0.02026-06-25

PHP version history (2 changes)v0.1PHP &gt;=8.2

v2.0.0PHP &gt;=8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/3aa4a8338c83cf0e75d2ac8f6bca5804837f668e49f6fdacf5fc6a957429db45?d=identicon)[Kibbab](/maintainers/Kibbab)

---

Top Contributors

[![actions-user](https://avatars.githubusercontent.com/u/65916846?v=4)](https://github.com/actions-user "actions-user (35 commits)")

---

Tags

symfonyloggingmonitoringsentryerror-tracking

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/dennisvanbeersel-symfony-logger-client/health.svg)

```
[![Health](https://phpackages.com/badges/dennisvanbeersel-symfony-logger-client/health.svg)](https://phpackages.com/packages/dennisvanbeersel-symfony-logger-client)
```

###  Alternatives

[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.8M672](/packages/shopware-core)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k6.0M777](/packages/sylius-sylius)[pimcore/pimcore

Content &amp; Product Management Framework (CMS/PIM/E-Commerce)

3.8k3.9M535](/packages/pimcore-pimcore)[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k18.3M430](/packages/easycorp-easyadmin-bundle)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[chameleon-system/chameleon-base

The Chameleon System core.

1029.4k6](/packages/chameleon-system-chameleon-base)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
