PSR-3: Logger Interface
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
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
17
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 8
Perplexity 2
ChatGPT 2
Ahrefs 1
Google 1
Also referenced
How they use it
crawler 13
crawler_json 1
Related categories
⚡
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