Logo

dev-resources.site

for different kinds of informations.

PSR-3: Logger Interface in PHP

Published at
1/11/2025
Categories
php
standards
phpfig
Author
jonesrussell
Categories
3 categories in total
php
open
standards
open
phpfig
open
Author
12 person written this
jonesrussell
open
PSR-3: Logger Interface in PHP

Ahnii!

Recently, I was helping a team migrate from Monolog to a custom logging solution, and guess what? They had to change code in dozens of files because their logging wasn’t standardized. That’s exactly the problem PSR-3 solves. Let me show you how!

Understanding PSR-3 (5 minutes)

Think of PSR-3 as a contract for logging in PHP. Just like how every car has a steering wheel and pedals in roughly the same place (making it easy to switch between cars), PSR-3 ensures all logging libraries work in a similar way.

1. The Logger Interface

Here’s what this contract looks like:

<?php

namespace Psr\Log;

interface LoggerInterface
{
    public function emergency($message, array $context = array());
    public function alert($message, array $context = array());
    public function critical($message, array $context = array());
    public function error($message, array $context = array());
    public function warning($message, array $context = array());
    public function notice($message, array $context = array());
    public function info($message, array $context = array());
    public function debug($message, array $context = array());
    public function log($level, $message, array $context = array());
}

Enter fullscreen mode Exit fullscreen mode

2. Log Levels (3 minutes)

Think of these levels as a severity scale, from “everything’s on fire” to “just FYI”:

  1. Emergency : 🔥 The house is burning down (system is completely broken)
  2. Alert : 🚨 Wake up, we need to fix this now!
  3. Critical : ⚠️ Major component is broken
  4. Error : ❌ Something failed, but the app is still running
  5. Warning : ⚡ Heads up, something’s not right
  6. Notice : 📢 Something normal but noteworthy happened
  7. Info : ℹ️ Just keeping you in the loop
  8. Debug : 🔍 For the curious developers

Real-World Implementation (10 minutes)

Let’s build something practical - a logger that writes to files and sends critical errors to Slack:

<?php

namespace App\Logging;

use Psr\Log\AbstractLogger;
use Psr\Log\LogLevel;

class SmartLogger extends AbstractLogger
{
    private $logFile;
    private $slackWebhook;

    public function __construct(string $logFile, string $slackWebhook)
    {
        $this->logFile = $logFile;
        $this->slackWebhook = $slackWebhook;
    }

    public function log($level, $message, array $context = array())
    {
        // Format the message
        $timestamp = date('Y-m-d H:i:s');
        $message = $this->interpolate($message, $context);
        $logLine = "[$timestamp] [$level] $message" . PHP_EOL;

        // Always write to file
        file_put_contents($this->logFile, $logLine, FILE_APPEND);

        // Send critical and emergency messages to Slack
        if (in_array($level, [LogLevel::CRITICAL, LogLevel::EMERGENCY])) {
            $this->notifySlack($level, $message);
        }
    }

    private function notifySlack($level, $message)
    {
        $emoji = $level === LogLevel::EMERGENCY ? '🔥' : '⚠️';
        $payload = json_encode([
            'text' => "$emoji *$level*: $message"
        ]);

        // Send to Slack (simplified for example)
        $ch = curl_init($this->slackWebhook);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_exec($ch);
        curl_close($ch);
    }

    private function interpolate($message, array $context = array())
    {
        $replace = array();
        foreach ($context as $key => $val) {
            $replace['{' . $key . '}'] = $val;
        }
        return strtr($message, $replace);
    }
}

Enter fullscreen mode Exit fullscreen mode

Using It In Your Project (5 minutes)

Here’s how I use this in my projects:

$logger = new SmartLogger(
    '/var/log/app.log',
    'https://hooks.slack.com/services/YOUR/WEBHOOK/HERE'
);

// Regular info logging
$logger->info('User {user} logged in from {ip}', [
    'user' => 'jonesrussell',
    'ip' => '192.168.1.1'
]);

// Critical error - this will go to both file and Slack
$logger->critical('Payment gateway {gateway} is down!', [
    'gateway' => 'Stripe',
    'error_code' => 500
]);

Enter fullscreen mode Exit fullscreen mode

Framework Integration (5 minutes)

If you’re using Laravel or Symfony, they’ve already done the heavy lifting:

Laravel

// In a service
public function processOrder($orderId)
{
    try {
        // Process order
        Log::info('Order processed', ['order_id' => $orderId]);
    } catch (\Exception $e) {
        Log::error('Order failed', [
            'order_id' => $orderId,
            'error' => $e->getMessage()
        ]);
        throw $e;
    }
}

Enter fullscreen mode Exit fullscreen mode

Symfony

class OrderController extends AbstractController
{
    public function process(LoggerInterface $logger, string $orderId)
    {
        $logger->info('Starting order process', ['order_id' => $orderId]);
        // Your code here
    }
}

Enter fullscreen mode Exit fullscreen mode

Quick Tips (2 minutes)

  1. 🎯 Be Specific : Include relevant context in your logs
// Instead of this
$logger->error('Database error');

// Do this
$logger->error('Database connection failed', [
    'host' => $dbHost,
    'error' => $e->getMessage(),
    'retry_attempt' => $attempt
]);

Enter fullscreen mode Exit fullscreen mode
  1. 🎨 Use the Right Level : Don’t cry wolf!
// Don't do this
$logger->emergency('User not found');

// Do this
$logger->notice('User not found', ['username' => $username]);

Enter fullscreen mode Exit fullscreen mode

Next Steps

Tomorrow, we’ll dive into PSR-4 and see how it makes autoloading a breeze. This post is part of our PSR Standards in PHP series.

Resources

standards Article's
30 articles in total
Favicon
PSR-6: Caching Interface in PHP
Favicon
PSR-4: Autoloading Standard in PHP
Favicon
PSR-3: Logger Interface in PHP
Favicon
PSR Standards in PHP: A Practical Guide for Developers
Favicon
PSR-1: Basic Coding Standard in PHP
Favicon
Anvil: An attempt of saving time
Favicon
Wednesday Links - Edition 2024-03-27
Favicon
The TAG, and Responsible Innovation on the Web
Favicon
2023 Industry Trends in Mobile Application User Interface
Favicon
Becoming W3C Games Community Group co-chair
Favicon
Jim's Guide to CockroachDB Naming Standards
Favicon
Writing Code with Standards and generate report on PreCommit : PHP / Laravel Project
Favicon
Creating a code style guide
Favicon
Call for Mentors for the Web Mapping Code Sprint: 29/11 - 01/12 2022 🎓
Favicon
Apeleg join the W3C
Favicon
2. Green Mode Design: Implementation Strategies
Favicon
Call for Mentors for the Vector Data Code Sprint: 12-14 July 2022 🎓
Favicon
Re-evaluating technology
Favicon
Web development is like assembling IKEA furniture
Favicon
Introducing the Email Markup Consortium (EMC)
Favicon
Pizza Code
Favicon
Estilo de código no PHP: as recomendações da PSR-1 e PSR-12
Favicon
Today, the distant future
Favicon
PHPArkitect: Put your architectural rules under test!
Favicon
Cross browser speech synthesis - the hard way and the easy way
Favicon
Foundations
Favicon
XML, making everything just a little bit harder.
Favicon
Coding Standards and Naming Conventions
Favicon
Portals and giant carousels
Favicon
Continuous partial browser support

Featured ones: