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

Sentry Symfony Laravel Package

sentry/sentry-symfony

The official Sentry SDK for Symfony. Install via Composer, add your SENTRY_DSN to .env, and capture exceptions from anywhere in your app. Get real-time error tracking and performance monitoring with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require sentry/sentry-symfony
    

    Add to .env:

    ###> sentry/sentry-symfony ###
    SENTRY_DSN="https://<key>@<project>.ingest.sentry.io/<id>"
    ###< sentry/sentry-symfony ###
    
  2. First Use Case: Capture an exception in a controller:

    use function Sentry\captureException;
    
    try {
        $result = $this->riskyOperation();
    } catch (\Throwable $e) {
        captureException($e);
        throw $e; // Re-throw if needed
    }
    
  3. Auto-Instrumentation: The bundle automatically captures:

    • HTTP requests (status, headers, body)
    • Database queries (Doctrine, DBAL)
    • Cache operations (Symfony Cache)
    • CLI commands (exit codes, arguments)
  4. Scrub Sensitive Data Up Front (v5.14+): Before you send your first event, decide what data is allowed to leave the app:

    # config/packages/sentry.yaml
    sentry:
        options:
            data_collection:
                user_info: true
                http_headers:
                    mode: allowList
                    terms:
                        - x-request-id
                http_bodies: []
                database_query_data: false
    

Where to Look First

  • Configuration: config/packages/sentry.yaml (auto-generated)
  • Documentation: Sentry Symfony Docs
  • Key Classes:
    • Sentry\SentryBundle\SentryBundle (main bundle)
    • Sentry\SentryBundle\EventListener\ExceptionListener (exception handling)
    • Sentry\SentryBundle\EventListener\RequestListener (HTTP instrumentation)
    • Sentry\SentryBundle\EventListener\UserContextListener (user/IP context, now runs pre-routing)

Implementation Patterns

Core Workflows

1. Exception Handling

// Manual capture (recommended for business logic errors)
use function Sentry\captureException;
use function Sentry\captureMessage;

try {
    $user = User::findOrFail($id);
} catch (\InvalidArgumentException $e) {
    captureMessage('Invalid user ID format', ['user_id' => $id]);
    throw $e;
}

// Auto-capture (for framework exceptions)
public function __invoke(Request $request, $id)
{
    // No try-catch needed; exceptions bubble up to Sentry
    return $this->userService->get($id);
}

2. Transaction Tracing

use function Sentry\trace;

trace('user.profile', function () use ($userId) {
    $user = User::find($userId);
    $orders = $user->orders()->limit(10)->get();
    return ['user' => $user, 'orders' => $orders];
});

3. Metrics Collection

use function Sentry\trace_metrics;

trace_metrics()->count('api.calls', 1, ['endpoint' => 'users']);
trace_metrics()->gauge('queue.size', $queue->count(), ['queue' => 'orders']);
trace_metrics()->distribution('response.time', $durationMs, ['unit' => 'ms']);

4. Data Collection Policy (v5.14+)

Centralize PII/secret handling instead of hand-scrubbing every event:

# config/packages/sentry.yaml
sentry:
    options:
        data_collection:
            user_info: true          # bool — attach id/username/email/ip
            http_headers:
                mode: allowList      # or denyList
                terms:
                    - x-request-id
                    - traceparent
            http_bodies: []          # empty = never attach request/response bodies
            database_query_data: false

Typical patterns:

# Strict production posture: no bodies, no query params, headers by allow-list only
data_collection:
    user_info: true
    http_headers: { mode: allowList, terms: [x-request-id] }
    http_bodies: []
    database_query_data: false
# Deny-list posture for internal/staging environments
data_collection:
    user_info: true
    http_headers:
        mode: denyList
        terms: [authorization, cookie, x-api-key]
    http_bodies: ['application/json']
    database_query_data: true

5. Structured Logging

# config/packages/monolog.yaml
monolog:
    handlers:
        sentry:
            type: service
            id: Sentry\SentryBundle\Monolog\LogsHandler
            arguments:
                - !php/const Monolog\Logger::DEBUG
$this->logger->info('User logged in', [
    'user_id' => $user->id,
    'ip' => $request->getClientIp(),
    'metadata' => ['device' => $deviceType]
]);

Integration Patterns

Doctrine DBAL

# config/packages/sentry.yaml
sentry:
    options:
        integrations:
            - Sentry\Integration\Doctrine\DoctrineIntegration

Pair DoctrineIntegration with data_collection.database_query_data: false to keep SQL text/parameters out of spans while retaining timing.

Symfony Messenger

sentry:
    messenger:
        isolate_context_by_message: true  # Prevents scope leakage

Custom Integrations

services:
    App\Sentry\CustomIntegration:
        tags: ['sentry.integration']

sentry:
    options:
        integrations: ['App\Sentry\CustomIntegration']

Middleware for API Requests

use Sentry\State\Scope;

public function __invoke(Request $request, Response $response, callable $next): Response
{
    $scope = Scope::getCurrentScope();
    $scope->setTag('api_version', $request->headers->get('X-API-Version'));

    return $next($request, $response);
}

Error Pages / Unmatched Routes (v5.14+)

User context is now set before the router runs, so 404/405 events include the client IP. If you maintain a custom kernel.exception listener that overwrites the user scope, run it after UserContextListener (default priority) or you will lose the IP on unmatched routes.


Configuration Patterns

Environment-Specific DSN

# config/packages/sentry.yaml
sentry:
    dsn: "%env(SENTRY_DSN)%"
    options:
        traces_sample_rate: "%env(float::SENTRY_TRACES_SAMPLE_RATE)%"

Environment-Specific Data Collection

# config/packages/sentry.yaml
sentry:
    options:
        data_collection:
            user_info: true
            http_headers:
                mode: allowList
                terms: ['x-request-id']
            http_bodies: []
            database_query_data: "%kernel.debug%"

Conditional Instrumentation

sentry:
    options:
        integrations:
            %kernel.debug% ? [] : ['Sentry\Integration\Doctrine\DoctrineIntegration']

Custom Error Ignoring

sentry:
    options:
        ignore_exceptions:
            - Symfony\Component\HttpKernel\Exception\HttpExceptionInterface
            - App\Exception\ValidationException

Gotchas and Tips

Common Pitfalls

  1. DSN Validation:

    • Gotcha: Forgetting to set SENTRY_DSN in .env causes silent failures.
    • Fix: Use SENTRY_DSN="https://invalid@localhost" in dev to test error handling.
  2. Performance Overhead:

    • Gotcha: Tracing every request in high-traffic apps can slow down responses.
    • Fix: Adjust traces_sample_rate (default: 1.0):
      sentry:
          options:
              traces_sample_rate: 0.1  # 10% sampling
      
  3. Sensitive Data in Errors:

    • Gotcha: Accidentally sending passwords, tokens, or request bodies in error payloads.
    • Fix (preferred, v5.14+): Configure data_collection once and stop writing regex scrubbers:
      sentry:
          options:
              data_collection:
                  user_info: true
                  http_headers: { mode: allowList, terms: [x-request-id] }
                  http_bodies: []
                  database_query_data: false
      
    • Fix (legacy / last-mile): Still use before_send for app-specific keys the SDK can't know about:
      Sentry\configureScope(function (Scope $scope) {
          $scope->setBeforeSendCallback(function ($event) {
              unset($event['extra']['password']);
              return $event;
          });
      });
      
  4. Messenger Context Leakage:

    • Gotcha: Breadcrumbs/logs from one message appearing in another.
    • Fix: Enable isolation:
      sentry:
          messenger:
              isolate_context_by_message: true
      
  5. Cache Instrumentation:

    • Gotcha: NamespacedPoolInterface caches breaking instrumentation.
    • Fix: Use TraceableCacheAdapterForV3 (v5.3+):
      $cache = new TraceableCacheAdapterForV3($pool);
      
  6. Over-Restrictive data_collection:

    • Gotcha: Setting http_bodies: [] and an empty header allow-list makes 4xx/5xx issues hard to triage ("what payload caused this 422?").
    • Fix: Keep bodies off in production but enable in staging via %kernel.debug%, and mirror the config in your staging Sentry project so it's obvious which posture produced an event.

Debugging Tips

  1. Local Testing:

    • Use SENTRY_DSN="http://localhost:3000" with Sentry Mock Server.
    • Enable debug logs:
      sentry:
          options:
              logger: 'sentry.logger'
      services:
          sentry.logger:
              class: 'Sentry\Logger\DebugFileLogger'
              arguments:
                  $filePath: '%kernel.logs_dir%/sentry.log'
      
  2. Event Inspection:

    • Capture events to a file for debugging:
      Sentry\configureScope(function (Scope $scope) {
          $scope->setBeforeSendCallback(function ($event) {
              file_put_contents(
                  __DIR__.'/sentry_event.json',
                  json_encode($event, JSON_PRETTY_PRINT)
              );
              return null; // Prevent sending
          });
      });
      
    • Use this to verify data_collection actually redacted the fields you expect before shipping the config.
  3. Performance Profiling:

    • Check sentry-performance metrics in Sentry dashboard.
    • Use X-Sentry-Trace header to correlate requests:
      $scope->setTag('sentry.trace_id', $request->headers->get('X-Sentry-Trace'));
      
  4. Missing IP on 404s:

    • Pre-v5.14 this was expected; on 5.14+ an event without user.ip_address on an unmatched route means a custom listener is clobbering the scope after UserContextListener. Check listener priorities first, not config.

Configuration Quirks

  1. max_breadcrumbs:

    • Default: 100 (no upper limit in v5.6+).
    • Tip: Increase for long-running processes:
      sentry:
          options:
              max_breadcrumbs: 500
      
  2. ignore_errors vs ignore_exceptions:

    • ignore_errors: Catches set_error_handler errors (legacy).
    • ignore_exceptions: Uses is_a() for type matching (recommended).
  3. Monolog Levels:

    • Accepts strings ('info'), PSR constants (Psr\Log\LogLevel::INFO), or Monolog constants (Monolog\Level::INFO).
  4. data_collection Structure:

    • Only user_info and database_query_data are plain booleans; http_headers is a {mode, terms} map and http_bodies is a list of content types.
    • http_headers.mode is case-sensitive (allowList / denyList); a typo silently falls back to the SDK default rather than erroring.
    • Requires sentry-php >= 4.34.0 — pin accordingly if you constrain the SDK transitively.
    • It gates attachment, it is not a replacement for before_send; anything you put into extra yourself is still sent verbatim.
  5. OTLP Integration:

    • Requires sentry-php v4.23+:
      sentry:
          options:
              integrations:
                  - Sentry\Integration\OTLPIntegration
      

Extension Points

  1. Custom Integrations:

    • Implement Sentry\IntegrationInterface:
      class MyIntegration implements IntegrationInterface {
          public function setupOnce(): void {
              // One-time setup (e.g., register error handler)
          }
      
          public function setup(): void {
              // Per-request setup (e.g., add breadcrumbs)
          }
      }
      
  2. before_send for App-Specific Redaction:

    • Layer on top of data_collection for anything the SDK can't classify:
      $scope->setBeforeSendCallback(function ($event) {
          if (isset($event['extra']['card_number'])) {
              unset($event['extra']['card_number']);
          }
          return $event;
      });
      
  3. User Context:

    • Set it once (login listener, LoginSuccessEvent); as of v5.14 the SDK seeds it before routing, so events raised during routing/404 handling inherit it.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource