Weave Code
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

Log Laravel Package

draw/log

Lightweight Laravel logging helper package providing a simple API to write structured log entries and streamline application debugging. Integrates with Laravel’s logger, supports common log levels, and keeps logging consistent across your services.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require draw/log
    
    • Requires PHP 8.5+ and Laravel 10+ (or Symfony 6.4+).
    • Ensure psr/log is installed (included by default in Laravel).
  2. First Use Case: Structured Logging Replace basic Log::debug() with structured logs:

    use Draw\Log\Logger;
    
    // Inject via Laravel's DI or manually
    $logger = new Logger();
    $logger->info('User action', [
        'user_id' => 123,
        'action' => 'login',
        'metadata' => ['ip' => $request->ip(), 'user_agent' => $request->userAgent()]
    ]);
    
    • Outputs JSON-structured logs (e.g., for ELK or custom parsers).
  3. Quick Win: Event-Driven Logging Attach logging to Symfony events (e.g., KernelEvents::REQUEST):

    use Draw\Log\Event\LogEvent;
    use Symfony\Component\HttpKernel\Event\RequestEvent;
    use Symfony\Component\HttpKernel\KernelEvents;
    use Symfony\Component\EventDispatcher\EventDispatcher;
    
    $dispatcher = new EventDispatcher();
    $dispatcher->addListener(KernelEvents::REQUEST, function (RequestEvent $event) {
        $logger = new Logger();
        $logger->dispatch(new LogEvent('Request started', [
            'method' => $event->getRequest()->getMethod(),
            'path' => $event->getRequest()->getPathInfo()
        ]));
    });
    
  4. Leverage Laravel’s Service Provider Bind the logger in AppServiceProvider:

    public function register()
    {
        $this->app->singleton(Logger::class, function ($app) {
            return new Logger($app['log']); // Extend Laravel's logger
        });
    }
    

Implementation Patterns

Core Workflows

  1. Contextual Logging

    • Pattern: Attach metadata to logs dynamically.
    • Example:
      $logger->withContext(['user_id' => auth()->id()])
             ->error('Payment failed', ['amount' => $request->amount]);
      
    • Use Case: Audit trails, user-specific debugging.
  2. Event-Driven Logging

    • Pattern: Log business events via Symfony’s EventDispatcher.
    • Example:
      // In a controller
      $logger->dispatch(new LogEvent('Order created', ['order_id' => $order->id]));
      
      // In a subscriber
      $dispatcher->addListener(LogEvent::class, function (LogEvent $event) {
          // Process log entry (e.g., send to external API)
      });
      
    • Use Case: Decouple logging from business logic (e.g., log after OrderCreated event).
  3. Handler Chaining

    • Pattern: Extend Monolog handlers with custom logic.
    • Example:
      use Draw\Log\Handler\EnrichHandler;
      
      $handler = new EnrichHandler(new StreamHandler(storage_path('logs/app.log')));
      $handler->setEnricher(function ($record) {
          $record['custom_field'] = 'value';
          return $record;
      });
      $logger->pushHandler($handler);
      
    • Use Case: Add request IDs, tenant IDs, or security flags to logs.
  4. Dependency Injection (DI)

    • Pattern: Use draw/dependency-injection to manage loggers.
    • Example:
      // config/draw.php
      'loggers' => [
          'app' => [
              'class' => \Draw\Log\Logger::class,
              'arguments' => ['@logger'], // Laravel's logger
          ],
      ];
      
    • Use Case: Centralize logger configuration in a monolith or microservices.

Integration Tips

  • Laravel-Specific:

    • Override Log::getMonolog() to inject custom handlers:
      use Illuminate\Log\LogManager;
      
      LogManager::extend('custom', function () {
          $monolog = new Monolog\Logger('custom');
          $monolog->pushHandler(new \Draw\Log\Handler\CustomHandler());
          return $monolog;
      });
      
    • Use Log::channel('custom')->info(...) in controllers.
  • Symfony Integration:

    • Replace Laravel’s Log facade with Symfony’s LoggerInterface:
      use Psr\Log\LoggerInterface;
      
      public function __construct(private LoggerInterface $logger) {}
      
    • Inject draw/log's logger via Symfony’s DI container.
  • Testing:

    • Mock LoggerInterface in PHPUnit:
      $mockLogger = $this->createMock(LoggerInterface::class);
      $mockLogger->expects($this->once())
                 ->method('info')
                 ->with('Test log', ['key' => 'value']);
      $this->app->instance(LoggerInterface::class, $mockLogger);
      

Gotchas and Tips

Pitfalls

  1. PHP 8.5+ Requirement

    • Issue: Laravel 9.x or older will fail to install.
    • Fix: Upgrade PHP or fork the package (target PHP 8.1).
  2. Draw Ecosystem Lock-in

    • Issue: Dependencies on draw/dependency-injection and draw/user-bundle may complicate maintenance.
    • Fix: Use only PSR-3/PSR-11 interfaces (avoid draw/* bundles):
      // Avoid this if not using draw/ecosystem
      $logger = new \Draw\Log\Logger($this->app['draw.di.container']);
      
  3. Monolog Handler Conflicts

    • Issue: Custom handlers may override Laravel’s default handlers (e.g., SingleHandler).
    • Fix: Push handlers instead of replacing:
      $logger->pushHandler(new \Draw\Log\Handler\CustomHandler());
      
  4. EventDispatcher Overhead

    • Issue: Dispatching events for every log entry adds latency.
    • Fix: Use async logging or batch events:
      $dispatcher->dispatch(new LogEvent($record), LogEvent::PRIORITY_LOW);
      
  5. Structured Log Parsing

    • Issue: JSON logs may break if not parsed correctly by consumers (e.g., ELK, Datadog).
    • Fix: Validate output format:
      $logger->setFormatter(new \Monolog\Formatter\JsonFormatter());
      

Debugging Tips

  1. Log Not Appearing?

    • Check handler configuration:
      $logger->getHandlers(); // Verify handlers are attached
      
    • Ensure Monolog’s processors are not filtering records:
      $logger->pushProcessor(function ($record) {
          return $record; // Ensure no silent drops
      });
      
  2. Circular References in Logs

    • Issue: Logging objects with circular references (e.g., Eloquent models) may crash.
    • Fix: Use var_export or custom serializers:
      $logger->info('User', [
          'data' => json_decode(json_encode($user), true)
      ]);
      
  3. Performance Bottlenecks

    • Issue: High-volume logging slows down requests.
    • Fix: Use async handlers or batch processing:
      $handler = new \Monolog\Handler\AsyncHandler(new StreamHandler('app.log'));
      $logger->pushHandler($handler);
      

Extension Points

  1. Custom Handlers

    • Extend \Draw\Log\Handler\AbstractHandler to create reusable handlers:
      class DatabaseHandler extends AbstractHandler
      {
          public function write(array $record): void
          {
              DB::table('logs')->insert([
                  'message' => $record['message'],
                  'context' => json_encode($record['context']),
                  'level' => $record['level'],
              ]);
          }
      }
      
  2. Log Formatters

    • Override \Monolog\Formatter\FormatterInterface for custom output:
      class CustomJsonFormatter extends JsonFormatter
      {
          public function format(array $record): string
          {
              $record['extra']['custom_field'] = 'value';
              return parent::format($record);
          }
      }
      
  3. Event Listeners

    • Subscribe to LogEvent for post-processing:
      $dispatcher->addListener(LogEvent::class, function (LogEvent $event) {
          if ($event->getLevel() === LogLevel::ERROR) {
              // Send alert to Slack/PagerDuty
          }
      });
      
  4. Logger Middleware

    • Add logging to Laravel’s middleware stack:
      namespace App\Http\Middleware;
      
      use Draw\Log\Logger;
      use Closure;
      
      class LogMiddleware
      {
          public function __construct(private
      
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor