# Enhancing Default Contextual Information in Laravel Logs

> Author: [Oussama Ghaieb](https://oussama.ghaieb.com/about-me)
> Canonical: https://oussama.ghaieb.com/posts/enhancing-default-contextual-information-in-laravel-logs

# <span class="hover:bg-yellow-100">Enhancing Default Contextual Information in Laravel Logs</span>

Laravel's logging system is robust and easy to configure. However, by default, logs lack certain contextual information, such as the full URL of the request, the currently authenticated user, or request data. In this article, we'll explore how to enhance your log entries by adding these contextual details, making your logs more informative and useful for debugging and monitoring.

## Why Enhance Logs?

Detailed logs provide crucial insights into your application's behavior. They can help you:

- Trace issues more effectively.
- Monitor user actions.
- Provide richer debugging information.

## Adding Custom Context to Logs with a Custom Formatter

Instead of using middleware, you can leverage a custom log formatter to enhance your logs. A custom formatter gives you full control over how log messages are structured and allows you to include additional contextual information like the request URL, user details, and more.

### Step 1: Create a Custom Formatter Class

To create a custom formatter, extend `Monolog\Formatter\FormatterInterface` or one of Monolog's built-in formatters, such as `JsonFormatter`.

#### Code Example:

```php
namespace App\Logging;

use Monolog\Formatter\JsonFormatter;

class CustomFormatter extends JsonFormatter
{
    public function format(array $record): string
    {
        // Add custom context to the log entry
        $record['context']['url'] = request()->fullUrl();
        $record['context']['method'] = request()->method();
        $record['context']['ip'] = request()->ip();
        $record['context']['user_id'] = optional(request()->user())->id;
        $record['context']['request_data'] = request()->except(['password', 'password_confirmation']);

        return parent::format($record);
    }
}
```

In this example, we extend `JsonFormatter` to include request details in the `context` array.

### Step 2: Register the Custom Formatter in the Logging Configuration

Update your `config/logging.php` file to use the custom formatter for a specific channel.

#### Code Example:

```php
'channels' => [
    'custom' => [
        'driver' => 'single',
        'path' => storage_path('logs/custom.log'),
        'level' => 'debug',
        'formatter' => App\Logging\CustomFormatter::class,
    ],
],
```

This ensures that all logs written to the `custom` channel will use your `CustomFormatter`.

### Step 3: Use the Custom Channel in Your Application

Whenever you need to log something with the custom context, specify the `custom` channel.

#### Code Example:

```php
use Illuminate\Support\Facades\Log;

Log::channel('custom')->info('A custom log message.');
```
OR:
```php
logger()->channel('custom')->info('A custom log message.');
```

### Example Log Output

If you use a JSON formatter, a log entry might look like this:

```json
{
    "message": "A custom log message.",
    "context": {
        "url": "https://example.com/resource",
        "method": "POST",
        "ip": "192.168.1.1",
        "user_id": 1,
        "request_data": {
            "field1": "value1",
            "field2": "value2"
        }
    },
    "level": "info",
    "timestamp": "2024-12-29T10:00:00Z"
}
```

## Why Use a Custom Formatter?

- **Fine-Grained Control**: Formatters allow you to modify the structure of log entries directly.
- **Reusable Across Channels**: You can apply the custom formatter to multiple log channels if needed.
- **Centralized Customization**: Keeps your logging logic in one place, making it easier to maintain.

<!-- ## Comparison with Middleware

| Feature                        | Middleware                                                          | Custom Formatter                                               |
|--------------------------------|---------------------------------------------------------------------|----------------------------------------------------------------|
| Scope                          | Adds context globally for all log calls during a request lifecycle. | Applies formatting and context at the log entry level.         |
| Use Case                       | Best for enriching logs with request-wide data.                     | Best for customizing the structure and content of log entries. |
| Flexibility                    | Limited to context; formatting depends on log channels.             | Full control over formatting and structure.                    |
| Complexity                     | Simple to implement.                                                | Slightly more complex but highly customizable.                 | -->

## Additional Enhancements

- **Filter Sensitive Data**: Ensure sensitive data, such as passwords or credit card details, is excluded from the logs using `except()` or a custom filter.
- **Dynamic Context**: You can add more context dynamically within your application where needed using `Log::withContext()`.
- **Event-Specific Logs**: For certain actions, like user logins or API calls, consider logging additional metadata specific to the event.

## Conclusion

Using a custom formatter is a powerful way to tailor your logs to your specific needs. It allows for greater flexibility and control over log content and structure, making debugging and monitoring more efficient. Start enhancing your logs today with a custom formatter and experience the difference!
