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

Command Logger Bundle Laravel Package

ayaou/command-logger-bundle

Symfony bundle that logs executed console commands with arguments, execution time, exit codes, and errors. Configure via attributes or wildcard patterns, view and filter logs with the command-logger:show command.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require ayaou/command-logger-bundle
    
  2. Enable the bundle in config/bundles.php:

    Ayaou\CommandLoggerBundle\AyaouCommandLoggerBundle::class => ['all' => true],
    
  3. Configure logging in config/packages/command_logger.yaml:

    command_logger:
      enabled: true
    
  4. Run migrations to create the command_log table:

    php bin/console doctrine:migrations:diff
    php bin/console doctrine:migrations:migrate
    

    Upgrading to v1.11.0+: output capture adds a column to command_log. Re-run doctrine:migrations:diff + migrate after bumping the bundle, even if you never enable output capture.

  5. (Optional, v1.11.0+) Enable output capture — off by default:

    command_logger:
      enabled: true
      capture_output: true   # opt-in flag; confirm exact key in the bundle README
    

First Use Case

Annotate a command to log its execution:

use Ayaou\CommandLoggerBundle\Attribute\CommandLogger;
use Symfony\Component\Console\Attribute\AsCommand;

#[AsCommand(name: 'app:test-command')]
#[CommandLogger]
class TestCommand extends Command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $output->writeln('Test command executed!');
        return Command::SUCCESS;
    }
}

Run the command:

php bin/console app:test-command

Verify logs:

php bin/console command-logger:show

With capture_output: true (v1.11.0+), the same command also records the Test command executed! line and command-logger:show renders it alongside the exit code — no more re-running a cron job just to see what it printed.


Implementation Patterns

1. Selective Logging via Configuration

Use the commands array in command_logger.yaml to log specific commands without annotations:

command_logger:
  commands:
    - app:cron-job:*
    - make:migration
    - make:model
  • Wildcards (*) support partial command names (e.g., app:cron-job:* logs all app:cron-job-* commands).
  • Third-party commands: Log commands from other bundles (e.g., doctrine:migrations:migrate).

2. Logging All Commands

Disable selective logging and enable global logging:

command_logger:
  enabled: true
  commands: []  # Empty array logs all commands

3. Integrating with Existing Commands

For commands without annotations, ensure they’re listed in the commands config. For new commands, prefer the #[CommandLogger] attribute:

#[AsCommand(name: 'app:deploy')]
#[CommandLogger]
class DeployCommand extends Command { ... }

4. Capturing Command Output (v1.11.0+)

Output capture is opt-in and applies to commands that are already being watched (attribute or config list) — it is not a second, independent selection mechanism.

# config/packages/command_logger.yaml
command_logger:
  enabled: true
  capture_output: true
  commands:
    - app:cron-job:*

Typical workflows this unlocks:

  • Nightly cron triage: open the failure record and read the stack trace / error line without SSH-ing to re-run it.
  • Deploy auditing: keep the app:deploy summary output as evidence of what shipped.
  • Batch import debugging: see the per-row warnings a app:import run emitted the night before.

Where output is captured, view it per record:

php bin/console command-logger:show --id=123

Enable it narrowly. Point capture_output at a small commands list (cron jobs, deploys, imports) rather than globally — see the storage and secrets pitfalls below.

5. Querying Logs Programmatically

Use the CommandLoggerRepository service to fetch logs in custom logic:

use Ayaou\CommandLoggerBundle\Repository\CommandLoggerRepository;

class MyService {
    public function __construct(
        private CommandLoggerRepository $loggerRepo
    ) {}

    public function getFailedDeployments(): array {
        return $this->loggerRepo->findBy([
            'commandName' => 'app:deploy',
            'exitCode' => Command::FAILURE
        ]);
    }
}

Failures now carry the captured output too, so you can build a "last error output" widget for an admin dashboard straight from the repository result.

6. Automated Log Purging

  • Scheduled purging: Add a cron job to run command-logger:purge periodically (e.g., weekly):
    0 0 * * 0 php bin/console command-logger:purge --threshold=30
    
  • Manual purging: Run ad-hoc cleanup:
    php bin/console command-logger:purge --threshold=90
    
  • After enabling output capture, consider a shorter threshold: rows are now materially larger, so the same retention window costs more disk.

7. Error Handling and Debugging

  • Filter errors in logs:
    php bin/console command-logger:show --error
    
  • Inspect specific failures by ID — this is the view that includes captured output:
    php bin/console command-logger:show --id=123
    

Gotchas and Tips

1. Attribute vs. Configuration Conflicts

  • Issue: Commands annotated with #[CommandLogger] override config-based logging.
  • Fix: Use either annotations or config lists, not both for the same command.
  • Workaround: Exclude annotated commands from the commands config to avoid duplicates.

2. Wildcard Matching Quirks

  • Behavior: Wildcards (*) match suffixes only (e.g., app:cron-job:* matches app:cron-job:daily but not app:cron-job-backup).
  • Tip: Use multiple entries for broader matching:
    commands:
      - app:cron-job:*
      - app:cron-*
    

3. Doctrine ORM Version Compatibility

  • Symfony 6/7: Uses Doctrine ORM 2 by default.
  • Symfony 8: Requires Doctrine ORM 3 (supported since v1.4.0).
  • Fix: Update composer.json if using Symfony 8:
    composer require doctrine/orm:^3.0
    

4. Run Migrations Before Enabling Output Capture

  • Issue: v1.11.0 persists output on the existing log record, which means a schema change. Enabling capture_output: true against an un-migrated database will fail writes (or silently drop output, depending on your Doctrine setup).
  • Fix: Always doctrine:migrations:diff + migrate as part of the bundle upgrade, then flip the flag. In CI, deploy the migration and the config change in that order.

5. Captured Output Can Contain Secrets

  • Issue: Commands routinely print tokens, connection strings, API responses, or PII — anything that lands in $output->writeln() is now at rest in the database, readable by anyone with DB access or the command-logger:show CLI.
  • Mitigation:
    • Keep capture_output scoped to a handful of commands, never global.
    • Redact at the source — don't print secrets, or wrap output with a sanitising decorator before the bundle sees it.
    • Treat the command_log table as sensitive data in your retention/GDPR policy, and shorten purge thresholds accordingly.

6. Only Watched Commands Produce Output

  • Issue: capture_output: true does not opt commands in. If a command isn't in commands and isn't annotated #[CommandLogger], no row exists and therefore no output exists.
  • Debugging order: confirm enabled: true → confirm the command is watched (attribute or exact config name) → confirm capture_output: true → confirm the record was written after the upgrade.

7. Output Capture Can Fail on Failure

  • Issue: Output is what the command emitted, so a command that dies before flushing its buffered output (fatal error, exit(), killed process) may log a short or empty output even though the failure is recorded. The exit code is still the reliable signal.
  • Tip: Don't treat empty captured output as "the command printed nothing of interest" — check exitCode first. For hard fatals, keep your normal Monolog/Sentry pipeline alongside this bundle rather than replacing it.

8. Output Volume vs. Log Accuracy

  • Issue: Verbose runs (-v/-vvv, progress bars, table rendering) can balloon a single row to megabytes, bloating the table and slowing command-logger:show.
  • Tip: Log a compact summary instead of the full stream for noisy commands; keep -v off in cron definitions where output capture is on.

9. Performance Impact

  • Base overhead: Logging adds ~5–10ms per execution.
  • With output capture: additional buffering and a larger write per run; negligible for cron jobs, noticeable for commands invoked in tight loops (e.g. one dispatch per item).
  • Mitigation:
    • Disable logging for non-critical commands (e.g., make:test).
    • Enable capture_output only where the output is genuinely diagnostic.
    • Increase the purge frequency to reduce database bloat.

10. Purging Edge Cases

  • Manual override: The --threshold flag in command-logger:purge ignores the config value.
  • Safety: Test purging in a staging environment first to avoid data loss.

11. Missing Logs Checklist

  • Check enabled status: Verify enabled: true in config.
  • Validate command names: Ensure names match exactly (case-sensitive, e.g., app:deploy vs. APP:DEPLOY).
  • Symfony 7.3+ Compatibility: If using Symfony 7.3+, ensure the bundle is updated to v1.6.0+ (see #22).
  • Symfony 8+ Command Style: #[AsCommand] is supported natively since v1.6.0+; legacy setName() still works but may need updates for full compatibility.

12. Extending Log Storage

  • Custom fields: Extend the CommandLog entity to add metadata (e.g., userId, environment):
    // src/Entity/CommandLog.php
    #[ORM\Entity]
    class CommandLog extends BaseCommandLog {
        #[ORM\Column(type: 'string', nullable: true)]
        private ?string $environment = null;
    }
    
  • Hook into logging: Override the CommandLogger service to inject custom logic:
    # config/services.yaml
    Ayaou\CommandLoggerBundle\Service\CommandLogger:
      arguments:
        $environment: '%kernel.environment%'
    
  • Upgrade check: since v1.11.0 touches the schema, verify your extended entity/mapping still resolves after pulling the release.
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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator