← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

PSR-3: Logger Interface

Style PHP 5.3+ Beginner
debt(d5/e5/b5/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). phpstan/phpcs/semgrep (from detection_hints) can flag error_log() calls or concrete Monolog type-hints, but only when configured with rules; default linter won't catch it.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor' (e5). Quick_fix says type-hint LoggerInterface in all classes and inject — that's a sweep across every service constructor, not a one-line change, especially when replacing static facades or error_log() calls.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Logger is reached across web/cli/queue contexts (applies_to); the interface choice shapes constructor signatures everywhere but is a well-known standard so doesn't define system shape.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap most devs eventually learn' (t5). Misconception cites that accepting any logger isn't PSR-3 — the eight severity methods and context array convention are documented gotchas, and the context-array-vs-string-interpolation mistake is the classic learned lesson.

About DEBT scoring →

Also Known As

PSR-3 PSR-3 logger LoggerInterface

TL;DR

A common LoggerInterface with eight RFC 5424 severity methods (emergency, alert, critical, error, warning, notice, info, debug).

Explanation

PSR-3 defines a standard LoggerInterface that any logging library can implement, allowing application code to type-hint LoggerInterface rather than a specific library. Methods map to RFC 5424 severity levels: emergency, alert, critical, error, warning, notice, info, debug. Each accepts a message string and optional context array (interpolated as {key} placeholders). Monolog is the most widely used PSR-3 implementation — it supports structured logging, multiple handlers (file, Slack, Datadog, Sentry), and formatters. Libraries and frameworks that accept a LoggerInterface become logger-agnostic.

Common Misconception

PSR-3 compliance just means accepting a logger as a constructor argument. PSR-3 defines a specific interface with eight severity methods (emergency through debug) and a context array convention — a class that accepts any logger but calls non-standard methods is not PSR-3 compliant.

Why It Matters

PSR-3 defines a common logger interface — code that depends on LoggerInterface works with any PSR-3 compliant logger (Monolog, Syslog, NullLogger) without modification.

Common Mistakes

  • Type-hinting against a concrete logger class instead of LoggerInterface — locks the codebase to one library.
  • Not using the context array parameter — embedding variables in the message string prevents structured log parsing.
  • Using the wrong log level — debug for production-visible events, or error for expected business conditions.
  • Not injecting the logger — using a static logger facade prevents swapping for a NullLogger in tests.

Code Examples

✗ Vulnerable
// Concrete dependency — cannot swap logger:
public function __construct(private Monolog\Logger $logger) {}

// Not using context array — unstructured log:
$this->logger->info('User ' . $userId . ' logged in from ' . $ip);

// Correct:
public function __construct(private Psr\Log\LoggerInterface $logger) {}
$this->logger->info('User logged in', ['user_id' => $userId, 'ip' => $ip]);
✓ Fixed
// PSR-3 Logger — always inject the interface, not a concrete logger
use Psr\Log\LoggerInterface;

class OrderService {
    public function __construct(private LoggerInterface $logger) {}

    public function place(Cart $cart): Order {
        $this->logger->info('Placing order', ['cart_id' => $cart->id]);
        try {
            $order = $this->createOrder($cart);
            $this->logger->info('Order placed', ['order_id' => $order->id]);
            return $order;
        } catch (\Throwable $e) {
            $this->logger->error('Order failed', [
                'cart_id'   => $cart->id,
                'exception' => $e->getMessage(),
            ]);
            throw $e;
        }
    }
}
// Levels: emergency, alert, critical, error, warning, notice, info, debug

Added 15 Mar 2026
Edited 22 Mar 2026
Views 84
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 1 ping T 2 pings F 2 pings S 0 pings S 1 ping M
Amazonbot 1
No pings yesterday
Amazonbot 14 ChatGPT 7 Ahrefs 7 SEMrush 6 Bing 5 PetalBot 5 Perplexity 4 Applebot 2 Google 1 Claude 1 Meta AI 1 Scrapy 1 Twitter/X 1 Brave Search 1
crawler 51 crawler_json 5
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Type-hint against Psr\Log\LoggerInterface in all your classes — inject Monolog in production and a NullLogger in tests; never use error_log() or echo in application code
📦 Applies To
PHP 5.3+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
error_log() or var_dump() in application code; tightly coupled to Monolog concrete class; no logger interface in service constructors
Auto-detectable: ✓ Yes phpstan phpcs semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Low ✗ Manual fix Fix: Low Context: File


✓ schema.org compliant