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

Formlogger Bundle Laravel Package

shark/formlogger-bundle

A Symfony bundle for logging form submissions. The Shark FormLogger Bundle helps developers capture and store submitted form data for auditing, debugging, and analysis, with straightforward integration into existing Symfony applications and configurable logging behavior.

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing to get straight: shark/formlogger-bundle is not a Laravel package. It is a Symfony 2 bundle (kernel bundle class, DI extension, form-event listener) targeting a framework that went end-of-life in 2019. With 10 stars, zero dependents, and a composite score of 0.11, treat it as a reference implementation to read, not a dependency to install. Day-to-day, your "getting started" is one of two paths:

Path A — you actually maintain a legacy Symfony 2 app (the only place it installs cleanly):

  1. composer require shark/formlogger-bundle (or add a vcs repository entry and clone if the Packagist package has disappeared).
  2. Register in app/AppKernel.php:
    public function registerBundles()
    {
        $bundles = array(
            new Shark\FormLoggerBundle\SharkFormLoggerBundle(), // verify namespace from *Bundle.php
        );
    }
    
  3. Read, in this order, because the README is thin and there is no published config reference:
    • Resources/config/services.xml — real service IDs, tags, and whether it auto-attaches to form events.
    • DependencyInjection/Configuration.php — the actual config root and keys.
    • The event listener/subscriber itself — where FormEvents::POST_SUBMIT (or SUBMIT) is hooked.
  4. First use case: a contact or registration form where support says "it just didn't submit." Enable the bundle, submit an invalid form, confirm a record lands in your Monolog target (app/logs/dev.log by default).

Path B — you're on Laravel (which the brief is): don't install it. Read the listener, note that it serializes $form->getData() and $form->getErrors() into a PSR-3 logger, and reimplement the behaviour in ~40 lines. Your starting points in Laravel are Illuminate\Validation\ValidationException, the FormRequest::failedValidation() hook, and a dedicated channel in config/logging.php. Estimated effort is 1–2 days including redaction and tests — less than the cost of forking and owning a Symfony 2 dependency.

Either way, the "first use case" is identical in spirit: capture the failing payload plus the validation messages for a single, high-value form so you can reproduce user reports without asking for screenshots.

Implementation Patterns

Pattern 1 — automatic event-subscriber logging (Symfony 2 style). If services.xml tags the listener on kernel.event_subscriber, every submitted form is logged with no controller code:

// roughly what the bundle does
public function postSubmit(FormEvent $event)
{
    $form = $event->getForm();
    $this->logger->info('form.submitted', [
        'name'   => $form->getName(),
        'data'   => $form->getData(),
        'errors' => $this->flatten($form->getErrors(true)),
    ]);
}

Convenient, noisy, and dangerous with anything sensitive — you get every field whether you wanted it or not.

Pattern 2 — explicit service call (preferred even in Symfony). Inject the bundle's service (or your own) and log deliberately, controlling level, context, and whether the form validates.

Pattern 3 — the Laravel-native equivalent (what you'll actually run). Mirror the same behaviour with framework primitives:

// app/Http/Middleware/LogFormFailures.php  (or a listener on ValidationException)
public function handle($request, Closure $next)
{
    try {
        return $next($request);
    } catch (ValidationException $e) {
        try {
            Log::channel('form_errors')->info('form.validation_failed', [
                'route'   => $request->route()?->getName(),
                'fields'  => array_keys($e->errors()),
                'errors'  => $e->errors(),
                'payload' => $this->redact($request->except(['_token', 'password', 'password_confirmation'])),
            ]);
        } catch (\Throwable $logFailure) {
            // logging must never change the response
            report($logFailure);
        }
        throw $e;
    }
}

Pair it with a JSON-formatted channel so downstream ingestion can parse it:

// config/logging.php
'form_errors' => [
    'driver' => 'daily',
    'path'   => storage_path('logs/form_errors.log'),
    'level'  => 'info',
    'days'   => 14,
    'formatter' => Monolog\Formatter\JsonFormatter::class,
],

Workflow tips that carry over from the bundle's design:

  • Log the shape of the payload (field names, error keys) plus a redacted subset of values — not the whole request body.
  • Attach a request/session correlation ID so a log line can be joined to the actual request trace.
  • Gate per-form behind a config flag so high-traffic endpoints don't drown the log.
  • When debugging a specific field, bump the channel level to debug and log the raw value for that field only, temporarily.

Integration tip: if a teammate really has already prototyped with this bundle inside a Symfony 2 service, keep it behind a queue or HTTP boundary rather than importing its classes into Laravel. There is no shared contract to bridge against — no service provider, no facade, no publishable config.

Gotchas and Tips

  • It will not install cleanly into Laravel. Pulling it in drags symfony/form, symfony/http-kernel, symfony/dependency-injection, and symfony/event-dispatcher alongside Illuminate. Expect duplicate dispatcher bindings and autoload/version conflicts. There's no package discovery and no service provider to bridge them.
  • PII leakage is the headline risk. The entire point is persisting raw submitted data. Passwords, _token, card numbers, health/financial fields, and free-text messages all land in the log by default. Use an allowlist of fields to capture, never a denylist, and define retention before enabling it on any real form.
  • A listener exception becomes a 500 on a conversion-critical path. If the subscriber throws (bad serialization, a circular reference in getData(), an unwritable log target), the user sees a server error instead of a validation message. Wrap all logging in try/catch and never let it influence the response.
  • Silent failure. A misconfigured handler or full disk means the feature quietly stops. Give it a health signal — a heartbeat log line, or a low-cardinality metric — so you notice when it stops working.
  • Log injection and unbounded records. Unstructured serialized objects break downstream parsers and can be manipulated via crafted input. Use a JSON formatter, cap record size (e.g. truncate payloads at a few KB), and consider sampling on error-heavy endpoints.
  • PHP version friction. Symfony 2-era composer.json files typically declare php >=5.3 with no upper bound or an incompatible one, and predate PSR-4 hygiene. Running it on PHP 8.2+ ranges from untested to broken. Pin components in an isolated namespace if you must.
  • Configuration keys are undocumented. The config root and available options live in DependencyInjection/Configuration.php; verify before assuming a key name from the README. When in doubt, the bundle source is the specification.
  • No upstream support path. No releases, no security process, no issue triage, zero dependents to lean on. If you adopt it, you own the code and its transitive Symfony 2 dependency chain permanently.
  • Extension points are limited to what you wrap around it. The practical extension is a custom Monolog handler or processor that redacts and reshapes the record before it hits storage. Forking to add an allowlist to the listener is often faster than wrapping.
  • Debugging checklist when nothing is logged: (1) is the bundle registered in the kernel, (2) is the service tag/event subscription actually present in services.xml, (3) is the log level high enough for the channel, (4) does the form reach POST_SUBMIT at all — a form that fails early never fires it, (5) is the handler writing somewhere you aren't tailing.

Bottom line for a Laravel developer: you cannot meaningfully leverage this package day-to-day on Laravel. Read it once as a behavioral spec, then implement a native ValidationException listener with a JSON log channel, allowlist redaction, sampling, and a try/catch guard. That gives you the same capability without the EOL framework, the PII exposure, or the maintenance tax.

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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core