-
-
Notifications
You must be signed in to change notification settings - Fork 1
Example Performance Analysis
Learn how to use ChronoTrace to identify and resolve application performance bottlenecks across multiple layers - database, cache, HTTP calls, and memory usage.
Your e-commerce checkout process is experiencing performance issues during peak hours, leading to cart abandonment and lost revenue.
- Checkout process taking 8-12 seconds
- High server load during peak traffic
- Users abandoning carts due to slow response
- Payment timeouts occurring frequently
First, let's record checkout traces to understand current performance:
# Enable sampling for checkout routes
CHRONOTRACE_MODE=targeted
# Configure targeted recording for checkout flow
php artisan chronotrace:record --routes="checkout/*,api/checkout/*" --duration=30m --sample-rate=0.5Configuration for checkout monitoring:
// config/chronotrace.php
'targeted_routes' => [
'checkout',
'checkout/*',
'api/checkout/*',
'api/payments/*',
'api/inventory/*',
],Let's examine the checkout traces to identify bottlenecks:
# Find slow checkout requests
php artisan chronotrace:list --route="checkout*" --min-duration=2000 --limit=10
# Example output showing performance issues:
ββββββββββββββ¬ββββββββββββββββββββββ¬βββββββββ¬βββββββββββ¬ββββββββββββββββββββββ¬βββββββββββ
β Trace ID β Timestamp β Method β Status β Route β Duration β
ββββββββββββββΌββββββββββββββββββββββΌβββββββββΌβββββββββββΌββββββββββββββββββββββΌβββββββββββ€
β slow_co1 β 2024-08-06 14:30:15 β POST β 200 β checkout/process β 8,456ms β
β slow_co2 β 2024-08-06 14:32:42 β POST β 200 β checkout/process β 9,891ms β
β slow_co3 β 2024-08-06 14:35:18 β POST β 422 β checkout/process β 12,156ms β
β timeout1 β 2024-08-06 14:37:25 β POST β 500 β checkout/process β 30,000ms β
ββββββββββββββ΄ββββββββββββββββββββββ΄βββββββββ΄βββββββββββ΄ββββββββββββββββββββββ΄βββββββββββLet's analyze a slow checkout trace across all event types:
# Get complete picture of slow checkout
php artisan chronotrace:replay slow_co1ββ REQUEST INFORMATION βββββββββββββββββββββββββββββββββββββββββ
β Trace ID: slow_co1 β
β Method: POST /checkout/process β
β Status: 200 OK β
β Duration: 8,456ms β
β Memory Peak: 128MB β
β User: customer_12345 β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββ DATABASE EVENTS (24 queries, 3,245ms total) ββββββββββββββββ
β [+0ms] SELECT * FROM users WHERE id = ? [12345] (5ms)
β [+15ms] SELECT * FROM carts WHERE user_id = ? [12345] (8ms)
β [+35ms] SELECT * FROM cart_items WHERE cart_id = ? [567] (12ms)
β [+58ms] SELECT * FROM products WHERE id IN (?, ?, ?, ...) [89,90,91...] (245ms) β οΈ
β [+315ms] SELECT * FROM inventory WHERE product_id IN (...) [89,90,91...] (1,890ms) β οΈ
β [+2,225ms] UPDATE inventory SET quantity = quantity - ? WHERE product_id = ? [2, 89] (156ms)
β [+2,395ms] UPDATE inventory SET quantity = quantity - ? WHERE product_id = ? [1, 90] (234ms)
β [+2,645ms] INSERT INTO orders (user_id, total, status) VALUES (?, ?, ?) [12345, 299.99, 'pending'] (45ms)
β [+2,705ms] INSERT INTO order_items (...) VALUES (...) - 5 queries (189ms)
β [+2,915ms] SELECT * FROM shipping_rates WHERE (...) (445ms) β οΈ
β [+3,375ms] UPDATE carts SET status = 'completed' WHERE id = ? [567] (25ms)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββ CACHE EVENTS (8 operations) ββββββββββββββββββββββββββββββββ
β [+125ms] GET product:89:details (MISS)
β [+130ms] GET product:90:details (MISS)
β [+135ms] GET product:91:details (MISS)
β [+3,400ms] GET shipping:zone:rates (MISS) β οΈ
β [+3,420ms] SET product:89:details (TTL: 3600s)
β [+3,425ms] SET product:90:details (TTL: 3600s)
β [+3,430ms] SET product:91:details (TTL: 3600s)
β [+7,890ms] SET shipping:zone:rates (TTL: 1800s)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββ HTTP EVENTS (3 requests) ββββββββββββββββββββββββββββββββββββ
β [+3,455ms] POST https://payment-gateway.com/validate (2,145ms) β οΈ
β Status: 200 OK
β Request: {"amount": 299.99, "card": "****-****-****-1234"}
β Response: {"status": "approved", "transaction_id": "txn_abc123"}
β
β [+5,625ms] POST https://shipping-api.com/calculate (1,890ms) β οΈ
β Status: 200 OK
β Request: {"weight": 2.5, "destination": "90210"}
β Response: {"rates": [{"service": "standard", "cost": 9.99}]}
β
β [+7,545ms] POST https://inventory-sync.com/reserve (1,245ms) β οΈ
β Status: 200 OK
β Request: {"items": [{"product_id": 89, "quantity": 2}]}
β Response: {"status": "reserved", "expires_at": "2024-08-06T15:30:15Z"}
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββ QUEUE EVENTS (2 jobs) βββββββββββββββββββββββββββββββββββββββ
β [+8,125ms] DISPATCH SendOrderConfirmationEmail
β Queue: emails, Delay: 0s
β Payload: {"order_id": 78901, "user_id": 12345}
β
β [+8,145ms] DISPATCH UpdateInventoryMetrics
β Queue: analytics, Delay: 5m
β Payload: {"product_ids": [89, 90, 91]}
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-
Database Bottlenecks (3.2s total):
- Slow inventory queries (1.9s)
- Missing indexes on product lookups
- Sequential inventory updates instead of batch
-
Cache Misses (Multiple misses):
- Product details not cached
- Shipping rates computed every time
- No cache warming strategy
-
External API Delays (5.3s total):
- Payment gateway: 2.1s
- Shipping calculator: 1.9s
- Inventory service: 1.2s
-
Memory Usage (128MB peak):
- Loading full product data unnecessarily
- Large shipping rate calculations
Before:
// Inefficient inventory checking
foreach ($cartItems as $item) {
$inventory = Inventory::where('product_id', $item->product_id)->first();
if ($inventory->quantity < $item->quantity) {
throw new InsufficientInventoryException();
}
}
// Sequential inventory updates
foreach ($cartItems as $item) {
Inventory::where('product_id', $item->product_id)
->decrement('quantity', $item->quantity);
}After:
// Batch inventory checking with proper indexing
$productIds = $cartItems->pluck('product_id');
$inventories = Inventory::whereIn('product_id', $productIds)
->lockForUpdate() // Prevent race conditions
->get()
->keyBy('product_id');
// Validate all items at once
foreach ($cartItems as $item) {
$inventory = $inventories[$item->product_id];
if ($inventory->quantity < $item->quantity) {
throw new InsufficientInventoryException($item->product_id);
}
}
// Batch inventory updates using raw SQL
$updates = $cartItems->map(function ($item) {
return [
'product_id' => $item->product_id,
'quantity' => $item->quantity
];
});
DB::transaction(function () use ($updates) {
foreach ($updates as $update) {
DB::statement(
'UPDATE inventory SET quantity = quantity - ? WHERE product_id = ?',
[$update['quantity'], $update['product_id']]
);
}
});Add Database Indexes:
// Migration: add_checkout_performance_indexes
Schema::table('inventory', function (Blueprint $table) {
$table->index(['product_id', 'quantity']); // For stock checking
});
Schema::table('products', function (Blueprint $table) {
$table->index(['id', 'status', 'price']); // For product lookups
});
Schema::table('shipping_rates', function (Blueprint $table) {
$table->index(['zone_id', 'weight_min', 'weight_max']); // For shipping calc
});Implement Multi-Level Caching:
// Product caching
class ProductService
{
public function getProductDetails($productIds)
{
$cacheKey = 'products:' . implode(',', $productIds);
return Cache::remember($cacheKey, 3600, function () use ($productIds) {
return Product::whereIn('id', $productIds)
->with(['category', 'images'])
->get();
});
}
}
// Shipping rate caching
class ShippingService
{
public function calculateRates($weight, $destination)
{
$cacheKey = "shipping:rates:{$destination}:{$weight}";
return Cache::remember($cacheKey, 1800, function () use ($weight, $destination) {
// Expensive shipping calculation
return $this->callShippingAPI($weight, $destination);
});
}
}
// Inventory caching with cache tags
class InventoryService
{
public function getAvailableQuantity($productIds)
{
return Cache::tags(['inventory'])->remember(
'inventory:' . implode(',', $productIds),
300, // 5 minutes only for inventory
function () use ($productIds) {
return Inventory::whereIn('product_id', $productIds)->get();
}
);
}
public function updateInventory($updates)
{
// Update database
$this->performInventoryUpdate($updates);
// Invalidate related caches
Cache::tags(['inventory'])->flush();
}
}Implement Async HTTP Calls:
use Illuminate\Http\Client\Pool;
class CheckoutService
{
public function processCheckout($cartItems, $paymentData, $shippingData)
{
// Make parallel API calls
$responses = Http::pool(function (Pool $pool) use ($paymentData, $shippingData, $cartItems) {
return [
'payment' => $pool->timeout(10)->post('https://payment-gateway.com/validate', $paymentData),
'shipping' => $pool->timeout(8)->post('https://shipping-api.com/calculate', $shippingData),
'inventory' => $pool->timeout(5)->post('https://inventory-sync.com/reserve', [
'items' => $cartItems->toArray()
]),
];
});
// Process responses
if ($responses['payment']->successful() &&
$responses['shipping']->successful() &&
$responses['inventory']->successful()) {
return $this->completeOrder($responses);
}
throw new CheckoutException('External service failure');
}
}Add Circuit Breaker Pattern:
class CircuitBreakerService
{
public function callWithCircuitBreaker($service, $callback, $fallback = null)
{
$failures = Cache::get("circuit_breaker:{$service}:failures", 0);
if ($failures >= 5) {
if ($fallback) {
return $fallback();
}
throw new ServiceUnavailableException($service);
}
try {
$result = $callback();
Cache::forget("circuit_breaker:{$service}:failures");
return $result;
} catch (Exception $e) {
Cache::increment("circuit_breaker:{$service}:failures");
Cache::put("circuit_breaker:{$service}:failures", $failures + 1, 300);
throw $e;
}
}
}Reduce Memory Usage:
// Before: Loading full models
$products = Product::with(['images', 'reviews', 'variations'])->get();
// After: Select only needed fields
$products = Product::select(['id', 'name', 'price', 'status'])
->whereIn('id', $productIds)
->get();
// Use chunking for large datasets
Product::whereIn('id', $largeProductIdList)
->chunk(100, function ($products) {
$this->processProducts($products);
});After implementing optimizations, let's test the improvements:
# Record new checkout traces
php artisan chronotrace:record --routes="checkout*" --duration=15m
# Compare performance
php artisan chronotrace:list --route="checkout*" --since="15 minutes ago"# After optimization:
ββββββββββββββ¬ββββββββββββββββββββββ¬βββββββββ¬βββββββββββ¬ββββββββββββββββββββββ¬βββββββββββ
β Trace ID β Timestamp β Method β Status β Route β Duration β
ββββββββββββββΌββββββββββββββββββββββΌβββββββββΌβββββββββββΌββββββββββββββββββββββΌβββββββββββ€
β fast_co1 β 2024-08-06 16:30:15 β POST β 200 β checkout/process β 1,245ms β
β fast_co2 β 2024-08-06 16:32:42 β POST β 200 β checkout/process β 1,156ms β
β fast_co3 β 2024-08-06 16:35:18 β POST β 200 β checkout/process β 1,389ms β
ββββββββββββββ΄ββββββββββββββββββββββ΄βββββββββ΄βββββββββββ΄ββββββββββββββββββββββ΄βββββββββββphp artisan chronotrace:replay fast_co1ββ REQUEST INFORMATION βββββββββββββββββββββββββββββββββββββββββ
β Trace ID: fast_co1 β
β Method: POST /checkout/process β
β Status: 200 OK β
β Duration: 1,245ms β
(85% improvement) β
β Memory Peak: 45MB β
(65% reduction) β
β User: customer_12345 β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββ DATABASE EVENTS (8 queries, 456ms total) βββββββββββββββββββ
β [+0ms] SELECT * FROM users WHERE id = ? [12345] (5ms)
β [+15ms] SELECT * FROM carts WHERE user_id = ? [12345] (8ms)
β [+35ms] SELECT id, name, price FROM products WHERE id IN (...) (45ms) β
β [+95ms] SELECT product_id, quantity FROM inventory WHERE product_id IN (...) FOR UPDATE (89ms) β
β [+195ms] UPDATE inventory SET quantity = quantity - CASE ... (234ms) β
Batch update
β [+445ms] INSERT INTO orders (...) VALUES (...) (45ms)
β [+495ms] INSERT INTO order_items (...) - Batch insert (34ms) β
β [+535ms] SELECT shipping_cost FROM shipping_rates_cache WHERE zone = ? (12ms) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββ CACHE EVENTS (6 operations) ββββββββββββββββββββββββββββββββ
β [+85ms] GET products:89,90,91 (HIT) β
β [+90ms] GET shipping:zone:90210:2.5kg (HIT) β
β [+185ms] GET inventory:89,90,91 (HIT) β
β [+1,200ms] SET order:78901:confirmation (TTL: 7200s)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββ HTTP EVENTS (2 requests, parallel) βββββββββββββββββββββββββ
β [+545ms] POST https://payment-gateway.com/validate (456ms) β
Parallel
β POST https://inventory-sync.com/reserve (423ms) β
Parallel
β Status: Both 200 OK
β Total: 456ms (was 5,280ms sequential)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Metric | Before | After | Improvement |
|---|---|---|---|
| Total Duration | 8,456ms | 1,245ms | 85% faster |
| Database Time | 3,245ms | 456ms | 86% faster |
| Cache Hit Rate | 12% | 89% | 77% improvement |
| HTTP Requests | 5,280ms | 456ms | 91% faster |
| Memory Usage | 128MB | 45MB | 65% reduction |
| Query Count | 24 | 8 | 67% fewer |
# Set up ongoing performance monitoring
php artisan chronotrace:record --routes="checkout*" --sample-rate=0.1 --continuous
# Create performance alerts
php artisan chronotrace:alert --route="checkout*" --threshold=2000ms --email=team@company.com// Custom performance tracking
class PerformanceMetrics
{
public function trackCheckoutPerformance($traceId, $duration, $steps)
{
$metrics = [
'trace_id' => $traceId,
'total_duration' => $duration,
'database_time' => $steps['database'] ?? 0,
'cache_hit_rate' => $steps['cache_hit_rate'] ?? 0,
'external_api_time' => $steps['http'] ?? 0,
'memory_peak' => $steps['memory_peak'] ?? 0,
];
// Store metrics for trending analysis
InfluxDB::write('checkout_performance', $metrics);
}
}// Performance regression testing
class CheckoutPerformanceTest extends TestCase
{
public function test_checkout_performance_baseline()
{
// Enable ChronoTrace for test
Config::set('chronotrace.enabled', true);
Config::set('chronotrace.mode', 'always');
$startTime = microtime(true);
// Perform checkout
$response = $this->post('/checkout/process', $this->getCheckoutData());
$duration = (microtime(true) - $startTime) * 1000;
// Assert performance requirements
$this->assertLessThan(2000, $duration, 'Checkout should complete under 2 seconds');
$response->assertStatus(200);
// Analyze trace for detailed assertions
$traces = $this->getLatestTraces();
$this->assertDatabaseQueriesLessThan($traces[0], 10);
$this->assertMemoryUsageLessThan($traces[0], 50 * 1024 * 1024); // 50MB
}
}// Use database query optimization
DB::enableQueryLog();
// Analyze query patterns
$queries = DB::getQueryLog();
foreach ($queries as $query) {
if ($query['time'] > 100) {
Log::warning('Slow query detected', $query);
}
}# Profile memory usage in traces
php artisan chronotrace:replay trace_id --memory-profile# Run load test while monitoring performance
php artisan chronotrace:record --duration=30m &
ab -n 1000 -c 10 http://localhost:8000/checkout/process- Identify slow queries (>100ms)
- Add appropriate indexes
- Implement eager loading
- Use batch operations
- Optimize N+1 queries
- Cache expensive computations
- Implement cache warming
- Use appropriate TTL values
- Monitor cache hit rates
- Implement cache invalidation
- Implement parallel HTTP calls
- Add timeout configurations
- Use circuit breaker pattern
- Cache API responses
- Implement fallback mechanisms
- Select only needed columns
- Use chunking for large datasets
- Implement lazy loading
- Monitor memory usage
- Optimize object creation
- Database Debugging - Specific database optimization techniques
- API Integration Debugging - External API optimization
- Configuration - Performance-related configuration
- Production Monitoring - Ongoing performance monitoring
Result: Checkout performance improved by 85% - from 8.5 seconds to 1.2 seconds, with 65% memory reduction and 91% faster external API calls!
- Getting Started - Install and configure ChronoTrace
- Examples - Real-world debugging scenarios
- Production Guide - Deploy safely in production
- Troubleshooting - Solve common issues
| Section | Page | Description |
|---|---|---|
| π Basics | Your First Trace | Step-by-step beginner guide |
| ποΈ Config | Recording Modes | Choose when to record traces |
| π‘οΈ Security | Security & PII | Protect sensitive data |
| π§ Tools | Commands | Complete command reference |
- π¬ GitHub Discussions - Community support
- π Report Issues - Bug reports & feature requests
- π§ Contact - Direct support
- π‘ Feature Requests - Suggest improvements
ChronoTrace helps Laravel developers debug applications faster with intelligent request tracing.
Made with β€οΈ by Grazulex β’ Documentation updated August 2024