PHP MDCLogger: Enhance Your PHP Logging with Mapped Diagnostic Context

Gabriel Anhaia
Dev Warlocks
Published in
5 min readJul 13, 2024

--

In the realm of software development, logging plays a crucial role in monitoring, debugging, and maintaining applications. Today, I’m excited to introduce MDCLogger, a PHP library designed to elevate your logging capabilities using Mapped Diagnostic Context (MDC). This post will guide you through what MDC is, how MDCLogger works, and how you can seamlessly integrate it into your PHP applications, whether you’re using Symfony, Laravel, or any other framework.

What is MDCLogger?

MDCLogger is a PHP library that extends the PSR-3 LoggerInterface, enabling you to add global context to your log messages. This global context, known as Mapped Diagnostic Context (MDC), allows you to track and correlate log entries across different parts of your application. It’s particularly useful for adding contextual information such as user IDs, request IDs, and more.

Package

The Problem Without MDC Logger

Tracking and correlating log entries can become challenging in complex PHP applications, especially those with multiple layers such as controllers, services, and repositories. Without a unified context, log messages from different application parts may lack the necessary information to understand the full picture. Here are some common issues faced when not using MDC Logger:

1. Inconsistent Context Information: Logs from different parts of the application might not include the same contextual information, making it difficult to trace the flow of a request or identify the source of an issue.
2. Debugging Difficulties: When an error occurs, developers must manually correlate logs by searching for related information scattered across multiple log entries.
3. Increased Time to Resolution: The lack of a consistent context in logs can significantly increase the time required to identify and resolve issues.
4. Lack of Structured Logging: Without a structured way to add context, log messages can become messy and hard to parse, leading to missed insights.

The Solution: MDCLogger

MDCLogger addresses these issues by providing a structured way to add and manage global context in your log messages. Here’s how MDCLogger solves the common logging problems:

1. Unified Context Across All Logs: By using MDCLogger, you can add global context that is automatically included in all log messages, ensuring consistency and completeness.
2. Enhanced Debugging: With contextual information such as user IDs, request IDs, and other relevant data included in every log entry, tracing the flow of a request becomes straightforward.
3. Reduced Time to Resolution: The structured logging approach of MDCLogger allows for quicker identification of issues, as all necessary context is readily available in the logs.
4. Clean and Structured Logs: MDCLogger ensures that your logs are well-structured, making them easier to read, parse, and analyze.

Here’s an example of how MDCLogger improves the logging process:

Without MDCLogger

A typical log entry without MDCLogger might look like this:

[2024–07–13T12:00:00+00:00] app.ERROR: An error occurred {"exception":"Exception message"} []

While this log entry provides some information, it lacks critical context, such as the user ID or request ID, making it harder to trace and debug the issue.

With MDCLogger

With MDCLogger, the same error log entry would include all the necessary context:

{
"message": "An error occurred.",
"context": {
"mdc_context": {
"user_id": "12345",
"request_id": "abcde",
"entity_id": "entity123"
},
"local_context": {
"exception": "Exception message"
}
},
"level": "error",
"channel": "app",
"datetime": "2024–07–13T12:00:00+00:00",
"extra": []
}

This log entry now contains comprehensive information, making it much easier to understand the context of the error and trace it back to its source.

Key Features

- Global Context Management: Add, retrieve, and clear global context for log messages.
- PSR-3 Compatible: Extends the PSR-3 LoggerInterface for seamless integration.
- Framework Agnostic: Symfony, Laravel, or any other PHP framework can be used.

Installation

To install MDCLogger, use Composer:

composer require gabrielanhaia/mdc-logger

Requirements

- PHP 7.4 or higher
- psr/log ^3.0

How to Use MDCLogger

Autowiring with Symfony

If you use Symfony, the `MDCLoggerInterface` will automatically be added to your services. Ensure your service container is correctly configured.

Manual Setup

For frameworks that do not support auto wiring, you must manually set up MDCLogger. Here’s how:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use MDCLogger\MDCLogger;
use MDCLogger\MDCLoggerInterface;
// Create a Monolog logger instance
$monolog = new Logger('app');
$monolog->pushHandler(new StreamHandler('path/to/your.log', Logger::DEBUG));
// Wrap the Monolog logger with MDCLogger
$mdcLogger = new MDCLogger($monolog);

Adding Global Context

$mdcLogger->addGlobalContext('user_id', '12345');
$mdcLogger->addGlobalContext('request_id', 'abcde');

Logging Messages

$mdcLogger->info('User logged in.');
$mdcLogger->error('An error occurred.', ['exception' => $exception]);

Clearing Global Context

$mdcLogger->clearGlobalContext();

Complete Example

Here’s a complete example showcasing how to use MDCLogger in a Symfony controller:

<?php
namespace App\Controller;
use MDCLogger\MDCLoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class SampleController extends AbstractController
{
private MDCLoggerInterface $mdcLogger;
public function __construct(MDCLoggerInterface $mdcLogger)
{
$this->mdcLogger = $mdcLogger;
}
public function sampleAction(): Response
{
// Add context at the controller level
$this->mdcLogger->addGlobalContext('entity_id', 'entity123');
// Log in the controller
$this->mdcLogger->info('Controller action started.');
// Call service layer
$this->serviceLayerMethod();
// Clear context at the end
$this->mdcLogger->clearGlobalContext();
return new Response('Action completed');
}
private function serviceLayerMethod(): void
{
// Log in the service layer
$this->mdcLogger->info('Service layer processing.');
// Call repository layer
$this->repositoryLayerMethod();
}
private function repositoryLayerMethod(): void
{
// Log in the repository layer
$this->mdcLogger->info('Repository layer accessed.');
}
}

Example Log Output

When using MDCLogger with multiple global contexts, the log output will include the global context and any additional context provided at the log message level. Here is an example of how a log entry might look in JSON format:

{
"message": "An error occurred.",
"context": {
"mdc_context": {
"user_id": "12345",
"request_id": "abcde",
"entity_id": "entity123"
},
"local_context": {
"additional_info": "Some local context data"
}
},
"level": "error",
"channel": "app",
"datetime": "2024–07–13T12:00:00+00:00",
"extra": []
}

This output shows the following:

- message: The log message.
- context: The combined context information.
— mdc_context: The global context, including `user_id`, `request_id`, and `entity_id`.
— local_context: Additional context specific to this log entry.
- level: The log level (e.g., error, info).
- channel: The logging channel (e.g., app).
- datetime: The timestamp of the log entry.
- extra: Any additional metadata (empty in this case).

Diagram

Below is a diagram showing the flow of adding global context in a controller, logging in different layers, and clearing the context at the end.

Conclusion

MDCLogger provides a powerful way to manage and enhance your logging with global context in PHP applications. Whether you’re using Symfony, Laravel, or another framework, MDCLogger can be easily integrated to provide detailed and contextual log messages. This not only helps in better debugging and monitoring but also ensures that your logs are rich with information that can be crucial for understanding the application’s behavior.

--

--

Gabriel Anhaia
Dev Warlocks

Software Engineer (Billie GmbH), Freelancer, and Author. Germany/Brazil. Book Design Patterns em PHP: https://goo.gl/NNDZqe