PSR-3 Logger Interface

มาตรฐาน Logger Interface — เขียน Log ยังไงให้เปลี่ยน library ได้โดยไม่ต้องแก้โค้ด

📌 PSR-3 เป็นมาตรฐานที่ Laravel ใช้อยู่เบื้องหลังผ่าน Monolog — ถ้าคุณเคยเขียน Log::info() หรือ Log::error() นั่นแหละ PSR-3

ปัญหาที่ PSR-3 มาแก้

สมมติเราเขียน log ใน project แบบนี้ครับ

// ใช้ Monolog ตรงๆ
$logger = new \Monolog\Logger('app');
$logger->pushHandler(new StreamHandler('app.log'));

$logger->info('User logged in', ['user_id' => 1]);
$logger->error('Payment failed', ['order_id' => 123]);

ดูก็ปกตินะ แต่วันนึง boss บอกว่า "เปลี่ยนไปใช้ Sentry แทน Monolog ได้ไหม"

ถ้าเราเรียก Monolog ตรงๆ ทั่ว project... ก็ต้องไล่แก้ทุกไฟล์เลยครับ 💀

PSR-3 แก้ปัญหานี้โดยกำหนด interface กลาง ว่า logger ต้องมี method อะไรบ้าง ไม่ว่าจะใช้ library ไหนอยู่เบื้องหลัง


1. LoggerInterface — หัวใจของ PSR-3

PSR-3 กำหนด interface ไว้แบบนี้ครับ

<?php

namespace Psr\Log;

interface LoggerInterface
{
    public function emergency(string|\Stringable $message, array $context = []): void;
    public function alert(string|\Stringable $message, array $context = []): void;
    public function critical(string|\Stringable $message, array $context = []): void;
    public function error(string|\Stringable $message, array $context = []): void;
    public function warning(string|\Stringable $message, array $context = []): void;
    public function notice(string|\Stringable $message, array $context = []): void;
    public function info(string|\Stringable $message, array $context = []): void;
    public function debug(string|\Stringable $message, array $context = []): void;
    public function log($level, string|\Stringable $message, array $context = []): void;
}

มี 8 levels ตามมาตรฐาน RFC 5424 เรียงจากรุนแรงที่สุดไปน้อยที่สุด


2. Log Levels — ใช้ตัวไหนเมื่อไหร่

อันนี้สำคัญมากครับ เพราะหลายคนใช้แต่ info กับ error ทั้งที่มันมีตั้ง 8 ระดับ

emergency

ระบบพัง ใช้งานไม่ได้เลย

💡 ใช้เมื่อ: ระบบทั้งหมดใช้ไม่ได้ ต้องปลุกคนมาแก้ตอนตี 3

alert

ต้องแก้ไขทันที

💡 ใช้เมื่อ: ยังไม่พัง แต่กำลังจะพัง

critical

ระบบบางส่วนพัง

💡 ใช้เมื่อ: feature สำคัญใช้ไม่ได้ แต่ระบบอื่นยังปกติ

error

เกิด error แต่ระบบยังทำงานต่อได้

💡 ใช้เมื่อ: มี error แต่ไม่กระทบ flow หลัก

warning

เตือนว่ามีอะไรผิดปกติ

💡 ใช้เมื่อ: ยังไม่ error แต่ถ้าไม่ดูแลจะเป็น error

notice

เหตุการณ์ปกติ แต่สำคัญพอจะบันทึกไว้

info

ข้อมูลทั่วไป

debug

ข้อมูลสำหรับ debug เท่านั้น

💡 Best Practice: อย่าเปิด debug ใน production นะครับ log จะเยอะมากจนหา error จริงๆ ไม่เจอ


3. Context Array — ข้อมูลเพิ่มเติม

สังเกตว่าทุก method มี parameter $context ครับ ตัวนี้สำคัญมาก อย่า log แค่ข้อความเปล่าๆ

💡 Best Practice: ใส่ context ทุกครั้งครับ เวลาไปไล่ดู log ใน production จะขอบคุณตัวเองมาก

Message Placeholder

PSR-3 support placeholder ใน message ด้วย:

ใช้ {key} แล้วส่ง key เดียวกันใน context array ครับ


4. ใช้กับ Laravel ยังไง

Laravel implement PSR-3 ให้หมดแล้วครับ เราใช้ผ่าน Facade ได้เลย

สังเกตนะครับ constructor รับ Psr\Log\LoggerInterface ไม่ใช่ Monolog ตรงๆ ทำให้เปลี่ยน logger ได้ง่ายโดยไม่ต้องแก้ class นี้

💡 Best Practice: ใช้ dependency injection แทน Log:: Facade ครับ จะ test ง่ายกว่ามาก


5. เขียน Logger ของเราเอง

ลองเขียน logger ง่ายๆ ที่ implement PSR-3 กันครับ

สังเกตว่าเรา extend AbstractLogger แทน implement LoggerInterface ตรงๆ ครับ เพราะ AbstractLogger implement method ทั้ง 8 ตัวให้แล้ว เราแค่เขียน log() ตัวเดียวก็พอ


6. Config Log Channel ใน Laravel

Laravel ใช้ระบบ channel ในการจัดการ log ตั้งค่าที่ config/logging.php:

ตัวอย่างนี้จะ log ทุกอย่างลง file แต่ส่ง Slack เฉพาะ error ขึ้นไป

💡 Best Practice: ใช้ stack channel เสมอครับ จะได้ส่ง log ไปหลายที่พร้อมกัน และตั้ง days สำหรับ daily driver ด้วย ไม่งั้น log จะกินพื้นที่ server ไม่หยุด


สรุป

  • PSR-3 กำหนด interface กลาง สำหรับ logger ทุกตัว

  • มี 8 log levels — ใช้ให้ถูกระดับ ไม่ใช่ยัด info กับ error อย่างเดียว

  • ใส่ context ทุกครั้ง — อย่า log แค่ข้อความเปล่า

  • ใน Laravel ใช้ Psr\Log\LoggerInterface inject เข้ามา ดีกว่าใช้ Facade ตรงๆ

  • เปลี่ยน logger ได้ง่ายโดยไม่ต้องแก้ business logic เลย

ถ้าอ่านบทความ วิธีการเก็บ Log Request และ Response ใน Laravel ด้วยจะเห็นภาพมากขึ้นครับ ว่าทำไม interface ถึงสำคัญ

Last updated