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

Stopwatch Laravel Package

symfony/stopwatch

Symfony Stopwatch is a lightweight profiling utility to measure execution time and memory usage in PHP. Start/stop named events, record laps, and group timings into sections (phases) to benchmark code paths and understand performance bottlenecks.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

Install via Composer:

composer require symfony/stopwatch

First Use Case: Profiling a Controller Method

use Symfony\Component\Stopwatch\Stopwatch;

public function index(Stopwatch $stopwatch)
{
    $stopwatch->start('controller_execution');

    // Your controller logic here
    $data = $this->someService->fetchData();

    $event = $stopwatch->stop('controller_execution');

    // Log or display results
    \Log::info("Controller took {$event->getDuration()}ms");

    return view('home', compact('data'));
}

Where to Look First

  1. Stopwatch Class: Core functionality for starting/stopping events.
  2. StopwatchEvent: Contains timing data (duration, memory usage, etc.).
  3. Laravel Integration: Use dependency injection for seamless access in controllers/services.

Implementation Patterns

Common Workflows

1. Middleware Profiling

public function handle($request, Closure $next)
{
    $stopwatch = app(Stopwatch::class);
    $stopwatch->start('middleware_execution');

    $response = $next($request);

    $event = $stopwatch->stop('middleware_execution');
    \Log::debug("Middleware took {$event->getDuration()}ms");

    return $response;
}

2. Service Method Profiling

public function fetchData(Stopwatch $stopwatch)
{
    $stopwatch->start('service_fetch_data');

    // Business logic
    $result = $this->repository->findAll();

    $event = $stopwatch->stop('service_fetch_data');
    \Log::debug("Service method took {$event->getDuration()}ms");

    return $result;
}

3. Database Query Profiling

public function getUser($id)
{
    $stopwatch = app(Stopwatch::class);
    $stopwatch->start('user_query');

    $user = User::find($id);

    $event = $stopwatch->stop('user_query');
    \Log::debug("User query took {$event->getDuration()}ms");

    return $user;
}

4. Section-Based Profiling

public function complexOperation(Stopwatch $stopwatch)
{
    $stopwatch->openSection('data_processing');

    $stopwatch->start('validation');
    // Validation logic
    $stopwatch->stop('validation');

    $stopwatch->start('transformation');
    // Transformation logic
    $stopwatch->stop('transformation');

    $stopwatch->stopSection('data_processing');
}

Integration Tips

Laravel Service Provider Binding

public function register()
{
    $this->app->singleton(Stopwatch::class, function () {
        return new Stopwatch();
    });
}

Logging All Events

$stopwatch = app(Stopwatch::class);
$stopwatch->start('event_name');

// ... code ...

$event = $stopwatch->stop('event_name');
\Log::channel('performance')->info([
    'event' => 'event_name',
    'duration' => $event->getDuration(),
    'memory' => $event->getMemory(),
    'timestamp' => now()->toIso8601String()
]);

CLI Command Profiling

protected function handle()
{
    $stopwatch = app(Stopwatch::class);
    $stopwatch->start('command_execution');

    // Command logic
    $this->processData();

    $event = $stopwatch->stop('command_execution');
    $this->info("Command executed in {$event->getDuration()}ms");
}

Gotchas and Tips

Common Pitfalls

  1. Forgetting to Stop Events

    • Unstopped events will appear as "running" in the stopwatch.
    • Fix: Use try-catch blocks to ensure events are always stopped:
      try {
          $stopwatch->start('event');
          // Code
      } finally {
          $stopwatch->stop('event');
      }
      
  2. Memory Usage Overhead

    • Stopwatch tracks memory usage, which can slightly increase memory consumption.
    • Tip: Disable memory tracking if not needed:
      $stopwatch = new Stopwatch(false); // Disable memory tracking
      
  3. Nested Events with Same Name

    • Stopwatch will only return the last stopped event with the same name.
    • Tip: Use unique names or sections for nested events.
  4. Laravel Dependency Injection

    • Ensure the Stopwatch service is properly bound in the service container.
    • Fix: Register the binding in a service provider if not using Laravel's built-in DI.

Debugging Tips

  1. Check All Events

    foreach ($stopwatch->getEvents() as $event) {
        \Log::debug("{$event->getName()}: {$event->getDuration()}ms");
    }
    
  2. Inspect Sections

    foreach ($stopwatch->getSections() as $section) {
        \Log::debug("Section {$section->getName()} took {$section->getDuration()}ms");
    }
    
  3. Lap Timing

    • Use lap() to measure intermediate steps within an event:
      $stopwatch->start('event');
      $stopwatch->lap('step_1');
      // Code for step 1
      $stopwatch->lap('step_2');
      // Code for step 2
      $event = $stopwatch->stop('event');
      

Extension Points

  1. Custom Event Data

    • Attach metadata to events:
      $event = $stopwatch->stop('event');
      $event->setData(['query' => 'SELECT * FROM users']);
      
  2. Event Listeners

    • Listen for event stops:
      $stopwatch->addListener(function (StopwatchEvent $event) {
          if ($event->getDuration() > 1000) { // 1 second
              \Log::warning("Slow event: {$event->getName()}");
          }
      });
      
  3. Stopwatch Storage

    • Store events in a database for historical analysis:
      $event = $stopwatch->stop('event');
      PerformanceLog::create([
          'event_name' => $event->getName(),
          'duration_ms' => $event->getDuration(),
          'memory_bytes' => $event->getMemory(),
          'created_at' => now()
      ]);
      

Performance Considerations

  1. Minimize Overhead

    • Avoid profiling in production unless absolutely necessary.
    • Use environment checks:
      if (app()->environment('local')) {
          $stopwatch->start('event');
          // Code
          $stopwatch->stop('event');
      }
      
  2. Batch Logging

    • Log events in batches to reduce I/O overhead:
      $events = [];
      $stopwatch->addListener(function (StopwatchEvent $event) use (&$events) {
          $events[] = $event;
      });
      
      // Later, log all events at once
      PerformanceLog::insert(array_map(function ($event) {
          return [
              'event_name' => $event->getName(),
              'duration_ms' => $event->getDuration(),
              'created_at' => now()
          ];
      }, $events));
      
  3. Avoid Blocking

    • For long-running processes, consider asynchronous logging:
      $stopwatch->addListener(function (StopwatchEvent $event) {
          dispatch(new LogPerformanceEvent($event))->onQueue('performance');
      });
      
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi