การกำหนด Handler ใน Monolog
ในบทที่แล้ว เราได้เรียนรู้วิธีการสร้าง Logger object ด้วย Monolog และการใช้งาน Logger ใน Class ต่างๆ ผ่าน Dependency Injection ในบทนี้ เราจะมาเรียนรู้เกี่ยวกับการกำหนด Handler ซึ่งเป็นส่วนประกอบสำคัญในการจัดการกับ Log ที่ถูกสร้างขึ้น Handler จะเป็นตัวกำหนดว่า Log ที่ถูกสร้างขึ้นจะถูกส่งไปที่ไหน เช่น ไฟล์, ฐานข้อมูล, หรือบริการอื่นๆ
Handler คืออะไร?
Handler คือส่วนประกอบที่รับผิดชอบในการจัดการกับ Log records ที่ถูกสร้างขึ้น โดย Handler จะทำการประมวลผล Log record และส่งไปยังปลายทางที่กำหนด เช่น:
- เขียน Log ลงในไฟล์
- ส่ง Log ไปยังฐานข้อมูล
- ส่ง Log ไปยังบริการแจ้งเตือน (เช่น Slack, Email)
- แสดง Log บนหน้าจอ Console
Monolog มี Handler ให้เลือกใช้งานมากมาย แต่ในบทนี้เราจะเน้นที่ Handler ที่ใช้งานบ่อยที่สุด 2 ตัว คือ StreamHandler และ RotatingFileHandler
StreamHandler
StreamHandler เป็น Handler ที่ง่ายที่สุดในการใช้งาน โดยจะทำการเขียน Log ลงใน Stream resource เช่น ไฟล์ หรือ php://stdout (Standard Output)
ตัวอย่าง: การเขียน Log ลงในไฟล์
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// สร้าง Logger
$logger = new Logger('my_app');
// สร้าง StreamHandler เพื่อเขียน Log ลงในไฟล์
$streamHandler = new StreamHandler('path/to/your/log/file.log', Logger::WARNING); // กำหนด level เป็น WARNING
// เพิ่ม Handler ให้กับ Logger
$logger->pushHandler($streamHandler);
// บันทึก Log
$logger->warning('This is a warning message.');
$logger->error('This is an error message.');
ในตัวอย่างข้างต้น เราได้สร้าง StreamHandler โดยกำหนดพารามิเตอร์แรกเป็น path ของไฟล์ Log (path/to/your/log/file.log) และพารามิเตอร์ที่สองเป็น Log level (Logger::WARNING) หมายความว่า Handler นี้จะทำการบันทึก Log ที่มี level ตั้งแต่ WARNING ขึ้นไป (WARNING, ERROR, CRITICAL, ALERT, EMERGENCY) เท่านั้น
กรณีใช้งานจริง:
สมมติว่าคุณต้องการบันทึก Log ของระบบลงในไฟล์ app.log ใน directory /var/log/my_app/ คุณสามารถทำได้ดังนี้:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// กำหนด path ของไฟล์ Log
$logPath = '/var/log/my_app/app.log';
// สร้าง Logger
$logger = new Logger('my_app');
// สร้าง StreamHandler เพื่อเขียน Log ลงในไฟล์
$streamHandler = new StreamHandler($logPath, Logger::INFO); // กำหนด level เป็น INFO
// เพิ่ม Handler ให้กับ Logger
$logger->pushHandler($streamHandler);
// บันทึก Log
$logger->info('Application started.');
$logger->warning('A user tried to access a restricted resource.');
$logger->error('An unexpected error occurred.');
ข้อผิดพลาดที่พบบ่อย:
- Permission denied: หาก PHP process ไม่มีสิทธิ์ในการเขียนไฟล์ใน directory ที่กำหนด คุณจะพบข้อผิดพลาด Permission denied แก้ไขได้โดยการเปลี่ยน ownership หรือ permission ของ directory นั้นๆ
- File not found: หากไฟล์ Log ที่กำหนดไม่มีอยู่ ระบบจะไม่สามารถสร้างไฟล์ได้ (ในบางกรณี) ตรวจสอบให้แน่ใจว่า directory ที่จะสร้างไฟล์นั้นมีอยู่
RotatingFileHandler
RotatingFileHandler เป็น Handler ที่มีความสามารถในการหมุนเวียนไฟล์ Log โดยจะทำการสร้างไฟล์ Log ใหม่เมื่อไฟล์ Log ปัจจุบันมีขนาดใหญ่เกินกว่าที่กำหนด หรือเมื่อถึงวันที่กำหนด Handler นี้มีประโยชน์ในการจัดการกับไฟล์ Log ที่มีขนาดใหญ่ และช่วยให้ง่ายต่อการค้นหา Log ในช่วงเวลาที่ต้องการ
ตัวอย่าง: การใช้งาน RotatingFileHandler
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
// สร้าง Logger
$logger = new Logger('my_app');
// สร้าง RotatingFileHandler เพื่อเขียน Log ลงในไฟล์ และหมุนเวียนไฟล์ทุกวัน
$rotatingFileHandler = new RotatingFileHandler('path/to/your/log/file.log', 7, Logger::DEBUG, true, true, null); // เก็บ Log ไว้ 7 วัน, level เป็น DEBUG
// เพิ่ม Handler ให้กับ Logger
$logger->pushHandler($rotatingFileHandler);
// บันทึก Log
$logger->debug('This is a debug message.');
$logger->info('This is an info message.');
$logger->warning('This is a warning message.');
ในตัวอย่างข้างต้น เราได้สร้าง RotatingFileHandler โดยกำหนดพารามิเตอร์ดังนี้:
- path: path ของไฟล์ Log หลัก (
path/to/your/log/file.log) - maxFiles: จำนวนไฟล์ Log ที่จะเก็บไว้ (ในตัวอย่างนี้คือ 7 ไฟล์) เมื่อมีไฟล์ Log เกินจำนวนนี้ ไฟล์ที่เก่าที่สุดจะถูกลบ
- level: Log level (
Logger::DEBUG) - bubble: กำหนดว่าจะให้ Log record ส่งต่อไปยัง Handler อื่นๆ หรือไม่ (
trueในที่นี้คือส่งต่อ) - filePermission: กำหนด permission ของไฟล์ Log ที่สร้าง (
trueในที่นี้คือใช้ default permission) - useLocking: กำหนดว่าจะใช้ file locking หรือไม่ (
nullในที่นี้คือใช้ default behavior)
เมื่อรันโค้ดนี้ RotatingFileHandler จะสร้างไฟล์ path/to/your/log/file.log และเมื่อถึงวันใหม่ หรือเมื่อไฟล์ path/to/your/log/file.log มีขนาดใหญ่เกินไป Handler จะทำการสร้างไฟล์ใหม่ เช่น path/to/your/log/file.log.1, path/to/your/log/file.log.2, ..., path/to/your/log/file.log.6
กรณีใช้งานจริง:
สมมติว่าคุณต้องการบันทึก Log ของระบบลงในไฟล์ app.log ใน directory /var/log/my_app/ และต้องการเก็บ Log ไว้ 30 วัน คุณสามารถทำได้ดังนี้:
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
// กำหนด path ของไฟล์ Log
$logPath = '/var/log/my_app/app.log';
// สร้าง Logger
$logger = new Logger('my_app');
// สร้าง RotatingFileHandler เพื่อเขียน Log ลงในไฟล์ และหมุนเวียนไฟล์ทุกวัน เก็บไว้ 30 วัน
$rotatingFileHandler = new RotatingFileHandler($logPath, 30, Logger::INFO);
// เพิ่ม Handler ให้กับ Logger
$logger->pushHandler($rotatingFileHandler);
// บันทึก Log
$logger->info('Application started.');
$logger->warning('A user tried to access a restricted resource.');
$logger->error('An unexpected error occurred.');
ข้อผิดพลาดที่พบบ่อย:
- Disk space full: หาก disk space เต็ม
RotatingFileHandlerจะไม่สามารถสร้างไฟล์ Log ใหม่ได้ ตรวจสอบให้แน่ใจว่ามี disk space เพียงพอ - Configuration error: ตรวจสอบให้แน่ใจว่าพารามิเตอร์ที่กำหนดให้กับ
RotatingFileHandlerถูกต้อง เช่นmaxFilesต้องเป็น integer ที่มีค่ามากกว่า 0
การใช้งานหลาย Handler
Monolog อนุญาตให้คุณกำหนด Handler หลายตัวให้กับ Logger object ซึ่งหมายความว่า Log record ที่ถูกสร้างขึ้นจะถูกส่งไปยัง Handler ทุกตัวที่ถูกกำหนดไว้
ตัวอย่าง: การใช้งานหลาย Handler
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
// สร้าง Logger
$logger = new Logger('my_app');
// สร้าง StreamHandler เพื่อเขียน Log ลงใน Console
$consoleHandler = new StreamHandler('php://stdout', Logger::WARNING);
// สร้าง RotatingFileHandler เพื่อเขียน Log ลงในไฟล์ และหมุนเวียนไฟล์ทุกวัน
$rotatingFileHandler = new RotatingFileHandler('path/to/your/log/file.log', 7, Logger::DEBUG);
// เพิ่ม Handler ให้กับ Logger
$logger->pushHandler($consoleHandler);
$logger->pushHandler($rotatingFileHandler);
// บันทึก Log
$logger->debug('This is a debug message.'); // จะถูกบันทึกลงในไฟล์เท่านั้น
$logger->warning('This is a warning message.'); // จะถูกบันทึกลงในไฟล์และแสดงใน Console
$logger->error('This is an error message.'); // จะถูกบันทึกลงในไฟล์และแสดงใน Console
ในตัวอย่างข้างต้น เราได้กำหนด Handler 2 ตัวให้กับ Logger object คือ StreamHandler (เขียน Log ลงใน Console) และ RotatingFileHandler (เขียน Log ลงในไฟล์) เมื่อเราบันทึก Log ด้วย level DEBUG จะถูกบันทึกลงในไฟล์เท่านั้น (เนื่องจาก StreamHandler ถูกกำหนด level เป็น WARNING) แต่เมื่อเราบันทึก Log ด้วย level WARNING หรือ ERROR จะถูกบันทึกลงในไฟล์และแสดงใน Console
การใช้งานหลาย Handler มีประโยชน์ในการจัดการกับ Log ในรูปแบบต่างๆ เช่น:
- บันทึก Log ทั้งหมดลงในไฟล์ และส่งเฉพาะ Error Log ไปยังบริการแจ้งเตือน
- แสดง Log บนหน้าจอ Console ในระหว่างการพัฒนา และบันทึก Log ลงในไฟล์ใน Production
ในบทต่อไป เราจะมาเรียนรู้เกี่ยวกับการกำหนด Formatter ซึ่งเป็นส่วนประกอบที่ใช้ในการจัดรูปแบบ Log record ก่อนที่จะถูกส่งไปยัง Handler