How to change laravel logs format?

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

How to Change Laravel Logs Format to JSON: Mastering Monolog Formatting

As developers building robust applications on the Laravel framework, effective logging is not just a convenience—it's a necessity for debugging, monitoring, and security. When you need structured logs, such as JSON, it allows external systems (like ELK stack, Splunk, or custom log analysis tools) to easily parse and index your data.

This guide will walk you through the process of customizing Laravel’s logging output to JSON format using Monolog, addressing the exact structure you are aiming for.

Understanding Logging in Laravel: The Role of Monolog

Laravel leverages the powerful Monolog library under the hood for all its logging operations. Monolog acts as the logging abstraction layer, allowing Laravel developers to write logs without worrying about the underlying file system or specific output format. To change how those logs are written—from plain text to a structured JSON object—we need to configure a Formatter.

A Formatter takes the raw log record generated by Monolog and transforms it into a desired string or array structure. The JsonFormatter is the perfect tool for achieving your goal of JSON logging.

Implementing JSON Formatting in Laravel

Your initial attempt using $app->configureMonologUsing() is the correct architectural approach within a Laravel application. This method allows you to hook into the service container and customize how Monolog services are instantiated.

Here is the refined, comprehensive way to implement JSON formatting:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\JsonFormatter;
use Illuminate\Support\ServiceProvider;

class LogServiceProvider extends ServiceProvider
{
    /**
     * Register any service providers.
     */
    public function register(): void
    {
        $this->app->configureMonologUsing(function ($monolog) {
            // 1. Define the log file path
            $logPath = storage_path('logs/app.json'); // Use a specific file name

            // 2. Set the log level
            $logLevel = Logger::DEBUG;

            // 3. Create the Stream Handler (where the logs are sent)
            $logStreamHandler = new StreamHandler($logPath, $logLevel);

            // 4. Instantiate the JSON Formatter
            $formatter = new JsonFormatter();
            
            // 5. Apply the formatter to the handler
            $logStreamHandler->setFormatter($formatter);
            
            // 6. Push the configured handler onto the Monolog logger instance
            $monolog->pushHandler($logStreamHandler);
        });
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        //
    }
}

Analysis of the Implementation

The key to achieving structured JSON logs lies in steps 4 and 5: creating an instance of JsonFormatter and setting it on the $logStreamHandler. When Monolog processes a log record, the formatter handles serializing all the relevant data (timestamps, channel, level, and context) into a valid JSON string.

Why your initial output looked different:
The structure you initially provided ("time":"...", "host":"...") often requires that the data being passed into the handler contains those specific keys. The JsonFormatter serializes whatever data is present in the log record's context and extra fields. To get detailed network information like host or remote-addrress, you might need to ensure these details are added either through custom Monolog Processors or by injecting them into the $context array before logging.

Advanced Customization: Adding Contextual Data

While the above implementation achieves JSON output, if you require specific fields like IP addresses directly in the final JSON object (as shown in your example), you need to ensure that data is available when the log event occurs. You can achieve this by leveraging Monolog’s extra array or using custom processors.

For instance, if you want to manually inject host information:

// Inside your controller or service where logging happens
$logger->warning('An error occurred', [
    'ip_address' => request()->ip(), // Injecting dynamic data into context
    'user' => auth()->user()->id ?? 'guest' 
]);

When the JsonFormatter runs, it will automatically include these keys within the log record structure. This practice aligns perfectly with building scalable, observable applications, which is a core philosophy behind modern framework development like that found in laravelcompany.com.

Conclusion

Changing your Laravel logs to JSON format is straightforward once you understand the Monolog pipeline: Logger $\rightarrow$ Handler $\rightarrow$ Formatter. By correctly configuring a StreamHandler with a JsonFormatter, you gain full control over the output structure. Remember that while the formatter handles the serialization, ensuring your application code provides rich context (using arrays and custom processors) is what makes the resulting JSON logs truly valuable for advanced analysis.