Skip to content

Logging

lpachecob edited this page Mar 24, 2026 · 1 revision

📝 Structured Logging

BOUNDLY v0.9.0 includes comprehensive structured logging for production environments.


📍 Location

Infrastructure\FrameworkCore\Services\Logging\
Infrastructure\FrameworkCore\Http\Middleware\RequestLoggerMiddleware.php

🏗️ Logger Services

StructuredLogger

Fluent logging with contextual builders:

$logger = app(StructuredLogger::class);

// Basic logging
$logger->info('User logged in');
$logger->error('Payment failed', ['amount' => 100]);

// With request context
$logger->withRequest($request)->info('API request processed');

// With user context
$logger->withUser($userId)->info('Profile updated');

// With custom context
$logger->withContext(['order_id' => 123])->info('Order processed');

RequestLoggerMiddleware

Automatically logs all HTTP requests with correlation IDs:

// Response includes
X-Request-ID: req_abc123
X-Response-Time: 45.2ms

Logged Data:

{
  "request_id": "req_abc123",
  "app": "BOUNDLY",
  "timestamp": "2026-03-24T12:00:00Z",
  "request": {
    "method": "GET",
    "path": "/api/users",
    "ip": "192.168.1.1",
    "user_agent": "Mozilla/5.0..."
  },
  "response": {
    "status": 200,
    "duration_ms": 45.2
  },
  "user": {
    "id": "user_123"
  }
}

AuditLogger

Track data changes for compliance:

$audit = app(AuditLogger::class);

// Log entity creation
$audit->logCreated('orders', $orderId, $userId, [
    'total' => 99.99,
    'items' => 3
]);

// Log entity update (with change tracking)
$audit->logUpdated('orders', $orderId, $userId, [
    'total' => 99.99
], [
    'total' => 149.99
]);

// Log entity deletion
$audit->logDeleted('orders', $orderId, $userId, [
    'order_number' => 'ORD-123'
]);

// Log data access
$audit->logAccessed('orders', $orderId, $userId, 'read');

⚙️ Configuration

// config/boundly.php
'logging' => [
    'version' => '1.0.0',
    'channel' => 'single',  // or 'daily', 'slack', etc.

    'request_logger' => [
        'enabled' => true,
        'channel' => 'single',
        'exclude_paths' => ['health', 'up'],
    ],

    'audit' => [
        'enabled' => true,
        'channel' => 'single',
        'events' => ['created', 'updated', 'deleted', 'accessed'],
    ],
],

📋 Log Levels

Level Use Case
emergency System is unusable
alert Immediate action needed
critical Critical conditions
error Error conditions
warning Warning conditions
notice Normal but significant
info Informational
debug Debug-level messages

🔧 Usage Examples

Logging with Context

// StructuredLogger with fluent API
app(StructuredLogger::class)
    ->withContext([
        'order_id' => $order->id,
        'customer_id' => $order->customer_id,
        'total' => $order->total,
    ])
    ->info('Order created');

// User-specific logging
app(StructuredLogger::class)
    ->withUser(auth()->id())
    ->withContext(['action' => 'login'])
    ->info('User action performed');

// Request-aware logging
app(StructuredLogger::class)
    ->withRequest($request)
    ->error('Request processing failed');

Integrating with Actions

#[Action(resource: 'orders', method: 'POST', middleware: ['auth'])]
class CreateOrderAction
{
    public function execute(CreateOrderRequest $request): JsonResponse
    {
        $order = $this->orderService->create($request->validated());

        app(AuditLogger::class)->logCreated(
            'orders',
            $order->id,
            auth()->id(),
            $request->validated()
        );

        return response()->json($order);
    }
}

Request Logging in Middleware

class PaymentProcessingMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        $startTime = microtime(true);

        $response = $next($request);

        $duration = (microtime(true) - $startTime) * 1000;

        app(StructuredLogger::class)
            ->withRequest($request)
            ->withContext([
                'payment_status' => $response->getStatusCode(),
                'processing_time_ms' => round($duration, 2),
            ])
            ->info('Payment processed');

        return $response;
    }
}

🚫 Excluding Paths

Health and status endpoints are automatically excluded from request logging:

'exclude_paths' => ['health', 'up']

📦 Log Output Format

{
  "message": "GET /api/users",
  "context": {
    "request_id": "req_abc123",
    "app": "BOUNDLY",
    "env": "production",
    "version": "0.9.0",
    "level": "info",
    "timestamp": "2026-03-24T12:00:00Z",
    "request": {
      "method": "GET",
      "path": "/api/users",
      "ip": "192.168.1.1",
      "user_agent": "Mozilla/5.0..."
    },
    "response": {
      "status": 200,
      "duration_ms": 45.2
    },
    "user": {
      "id": "user_123"
    }
  },
  "level": "info",
  "channel": "single",
  "datetime": "2026-03-24T12:00:00Z"
}

🔐 Security Logging

Security events are automatically logged by SecurityLogger:

Event Severity Description
auth.login.success INFO Successful login
auth.login.failed WARNING Failed login attempt
security.rate_limit.exceeded WARNING Rate limit hit
security.brute_force.detected ALERT Brute force attack
security.brute_force.blocked ALERT Attack blocked
security.suspicious_input CRITICAL Suspicious input detected

Next Step: Cache 🚀

Clone this wiki locally