A futuristic developer desk visualizing Error Handling and Logging mechanisms

1. 🎯 ชื่อตอน (Title): ตอนที่ 33: Error Handling & Logging กล่องดำนักสืบ และศิลปะการซ่อนบั๊กไม่ให้ลูกค้าตกใจ

2. 📖 เปิดฉาก (The Hook):

มาครับน้องๆ ลากเก้าอี้มานั่งจิบกาแฟกัน… เคยไหมครับ? ตอนเขียนโค้ดอยู่ที่เครื่องตัวเอง (Local) ทุกอย่างทำงานได้สมบูรณ์แบบไร้ที่ติ แต่พอเอาขึ้นเซิร์ฟเวอร์จริง (Production) ปุ๊บ ลูกค้าโทรมาด่าว่า “น้อง! เว็บพัง กดจ่ายเงินไม่ได้ หน้าจอขาวจั๊วะเลย!”

พอเราเข้าไปดูก็พบกับความสยองขวัญ 2 เด้ง: เด้งที่ 1: หน้าเว็บแสดง Error Stack Trace ยาวเป็นหางว่าว โชว์ให้ลูกค้าเห็นหมดเลยว่าเราใช้ Database รหัสผ่านอะไร โฟลเดอร์อยู่ที่ไหน (นี่มันช่องโหว่ความปลอดภัยชัดๆ!) เด้งที่ 2: พอเราปิดการแสดง Error ปุ๊บ ลูกค้าเห็นแค่คำว่า “500 Server Error” แต่คราวนี้ตัวเราเองกลับตาบอด ไม่รู้เลยว่าบั๊กมันเกิดที่บรรทัดไหน เพราะไม่ได้จดบันทึกอะไรไว้เลย!

การปล่อยระบบขึ้น Production โดยไม่มีระบบจัดการ Error และไม่มีการเก็บ Log ก็เหมือนกับการ “ขับรถหลับตา” ครับ วันนี้พี่จะพาไปดูวิธีรับมือกับสถานการณ์ฉุกเฉินเหล่านี้ ทั้งการสร้างหน้าต่าง Error สวยๆ ปลอบใจลูกค้า และการฝัง “กล่องดำ (Black Box)” เพื่อบันทึกทุกฝีก้าวของระบบกันครับ!

3. 🧠 แก่นวิชา (Core Concepts):

สถาปัตยกรรมของ Laravel เตรียมเครื่องมือสำหรับจัดการเรื่องปวดหัวเหล่านี้ไว้ให้อย่างครบครันครับ:

  • 🚦 สวิตช์พระเจ้า (The APP_DEBUG Switch): ในไฟล์ .env จะมีตัวแปรที่ชื่อว่า APP_DEBUG กฎเหล็กข้อแรกของวงการคือ “บน Production ค่านี้ต้องเป็น false เสมอ” หากเป็น false เวลาระบบพัง มันจะไม่คายความลับออกมา แต่จะโชว์หน้าจอ Error พื้นฐานแทน
  • 🎨 Custom HTTP Error Pages: HTTP Status Codes ยอดฮิตอย่าง 404 (Not Found) หรือ 500 (Internal Server Error) มีหน้าตาเริ่มต้นที่ดูจืดชืด Laravel อนุญาตให้เราสร้างไฟล์ View (Blade) ขึ้นมาสวมทับหน้าตาเหล่านี้ได้ เพื่อรักษาภาพลักษณ์ (Branding) ของแอปพลิเคชันเราเอาไว้
  • 📝 ระบบกล่องดำ (Laravel Logging): Laravel ใช้ไลบรารีที่ชื่อว่า Monolog อยู่เบื้องหลัง มันมีระดับความรุนแรงของ Log ตามมาตรฐานสากล (RFC 5424) ถึง 8 ระดับ แต่ที่เราใช้กันบ่อยๆ ในชีวิตประจำวันมี 2 ตัวคือ:
    • info(): เอาไว้จดบันทึก “เหตุการณ์ปกติที่สำคัญ” (เช่น ลูกค้า A โอนเงินสำเร็จแล้ว)
    • error(): เอาไว้จดบันทึก “ตอนระบบพัง หรือจับ Exception ได้” เพื่อให้เราตามรอยได้ง่ายๆ
System flow diagram splitting an Exception into a Custom UI and a Log File

4. 💻 ร่ายมนต์โค้ด (Show me the Code):

พาร์ท A: การตกแต่งหน้า Error ให้สวยงาม (Custom Error Pages)

สมมติว่ามีคนพยายามเข้า URL ที่ไม่มีอยู่จริง ระบบจะโยน Error 404 ออกมา เรามาสร้างหน้าเพจปลอบใจลูกค้ากันครับ

สเต็ปที่ 1: สั่งให้ Artisan คายไฟล์ Template หน้า Error พื้นฐานออกมาให้เราแก้

# รันคำสั่งนี้ใน Terminal
php artisan vendor:publish --tag=laravel-errors

สเต็ปที่ 2: เข้าไปที่โฟลเดอร์ resources/views/errors/ น้องจะเห็นไฟล์เช่น 404.blade.php, 500.blade.php โผล่ขึ้นมา เราสามารถเปิดเข้าไปแก้ HTML ให้เป็นดีไซน์ของเว็บเราได้เลยครับ

<!-- resources/views/errors/404.blade.php -->
@extends('layouts.app')

@section('content')
    <div class="text-center mt-20">
        <img src="/images/crying-cat.png" alt="Not Found">
        <h1 class="text-4xl font-bold">404 - ขออภัย ไม่พบหน้าที่คุณตามหา</h1>
        <p>ดูเหมือนว่าคุณจะหลงทาง... กลับหน้าแรกกันเถอะ</p>
        
        <!-- เราสามารถดึงข้อความ Error ที่ระบบส่งมาให้ด้วยตัวแปร $exception ได้ -->
        <p class="text-gray-500">{{ $exception->getMessage() }}</p>
        
        <a href="/" class="btn btn-primary">กลับหน้าแรก</a>
    </div>
@endsection

ทริคเพิ่มเติม: เวลาน้องเขียน Controller ถ้าน้องอยาก “ถีบ” ผู้ใช้ออกไปหน้า 404 น้องสามารถใช้ Helper function โยนออกไปตรงๆ ได้เลยครับ:

// โยนไปหน้า 404 ทันที พร้อมฝากข้อความไปด้วย
abort(404, 'สินค้านี้ถูกลบออกจากระบบไปแล้วครับ'); 

พาร์ท B: การเขียน Log เพื่อสืบสวนคดี

เรามาดูวิธีการใช้ info() และ error() ภายใน Controller กันครับ

<?php
namespace App\Http\Controllers;

use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; // ดึง Facade มาใช้งาน
use Throwable;

class PaymentController extends Controller
{
    public function process(Request $request, $orderId)
    {
        // 1. บันทึก "ข้อมูลทั่วไป" เพื่อให้รู้ว่า Process เริ่มทำงานแล้ว (ใช้ Helper function ก็ได้)
        info('เริ่มกระบวนการชำระเงิน', ['order_id' => $orderId, 'user' => $request->user()->id]);
        
        try {
            // ดึงข้อมูลออเดอร์
            $order = Order::findOrFail($orderId);
            
            // ... สมมติว่ามี Logic ตัดบัตรเครดิตที่นี่ ...
            
            // 2. ถ้าสำเร็จ บันทึกไว้เป็นหลักฐาน
            Log::info('ตัดบัตรเครดิตสำเร็จ', ['order_id' => $orderId]);
            
            return view('payment.success');

        } catch (Throwable $e) {
            // 3. ถ้าระบบพัง (เช่น ต่อ API ธนาคารไม่ได้) ให้จับ Exception ไว้
            // และใช้ Log::error() บันทึกข้อความ พร้อมโยน Object Exception ยัดเข้าไปใน Context ด้วย
            Log::error('ระบบตัดบัตรพังจ้า!', [
                'order_id' => $orderId,
                'error_message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine()
            ]);
            
            // 4. โยนหน้า 500 กลับไปให้ลูกค้าดู
            abort(500, 'ขออภัย ระบบชำระเงินขัดข้องชั่วคราว ทีมงานกำลังแก้ไขครับ');
        }
    }
}

ผลลัพธ์: เมื่อเกิดเหตุการณ์ขึ้น ให้เราเปิดไฟล์ storage/logs/laravel.log ดูครับ เราจะเห็นข้อมูลสืบสวนคดีเรียงกันอย่างสวยงาม ทำให้แก้บั๊กได้ตรงจุด ไม่ต้องงมเข็มในมหาสมุทร

5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips):

ในฐานะ Senior Dev พี่มีทริคเด็ดๆ เกี่ยวกับการจัดการ Logs มาฝากครับ:

  • 🗂️ เปลี่ยนไปใช้ Log แบบรายวัน (Daily Channel): ตามค่าเริ่มต้น Laravel จะเก็บ Log ยัดลงในไฟล์ laravel.log ไฟล์เดียว ถ้าเว็บคนเข้าเยอะ ไฟล์นี้อาจจะใหญ่ถึง 10GB! เปิดอ่านทีคอมค้าง พี่แนะนำให้เข้าไปแก้ไฟล์ .env เปลี่ยนค่า LOG_CHANNEL=stack (หรือ single) ให้กลายเป็น LOG_CHANNEL=daily ครับ ระบบจะสร้างไฟล์ใหม่ให้ทุกวัน (เช่น laravel-2026-03-11.log) และจะลบไฟล์ที่เก่ากว่า 14 วันทิ้งให้อัตโนมัติ สบายเซิร์ฟเวอร์สุดๆ
  • 📣 การรายงาน Error โดยไม่หยุดการทำงาน (report()): บางครั้งเกิด Error ขึ้น เราอยาก “จดลง Log” แต่ “ไม่อยากให้หน้าเว็บพัง (ไม่อยาก abort)” เราสามารถใช้ฟังก์ชัน report($e); ได้ครับ มันจะแอบเอา Exception ไปจดลง Log ให้เบื้องหลัง แล้วปล่อยให้โค้ดบรรทัดต่อไปทำงานต่อได้อย่างเนียนๆ
  • Slack / Discord Alerts: รู้ไหมว่า Log ของ Laravel ทรงพลังขนาดที่ว่าเราตั้งค่า config/logging.php ให้มันโยน Log ระดับ critical ยิงเข้าห้องแชท Slack หรือ Discord ของทีม Developer ให้เด้งเตือนในมือถือทันทีได้เลยนะ! (ลองไปเล่นดูใน Channel Slack ครับ)

6. 🏁 บทสรุป (To be continued…):

จะเห็นได้ว่า Error Handling และ Logging เป็นสองสิ่งที่คู่กันเหมือนหยินหยางครับ ฝั่งหนึ่งเอาไว้ปกป้องหน้าตาของแบรนด์ (Custom Views) ไม่ให้ลูกค้าเห็นโค้ดดิบๆ อีกฝั่งเอาไว้เป็นอาวุธให้โปรแกรมเมอร์ (Logs) เข้าไปผ่าตัดรักษาโรคได้อย่างแม่นยำ

จงจำไว้ว่า “บั๊กเป็นเรื่องธรรมชาติ แต่การปล่อยให้บั๊กเกิดขึ้นโดยที่เราไม่รู้อะไรเลย เป็นความผิดของโปรแกรมเมอร์ครับ!”

เมื่อแอปพลิเคชันของเราแข็งแกร่งและตรวจสอบได้แล้ว… ในตอนต่อไป พี่จะพาไปงัดข้อกับเรื่องที่เกี่ยวข้องกับ “เวลา” บ้าง ถ้าน้องมีโค้ดที่รันช้ามากๆ (เช่น การแปลงไฟล์วิดีโอ) เราจะทำอย่างไรให้ลูกค้าไม่ต้องนั่งรอหน้าจอโหลดค้าง? เตรียมตัวพบกับสุดยอดสถาปัตยกรรมเบื้องหลังอย่าง “Queues & Jobs (ระบบคิว)” ชงกาแฟแก้วใหม่ แล้วพบกันครับ!


ต้องการที่ปรึกษาและพัฒนาระบบ Automation ให้กับโรงงานของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและติดตั้งระบบแบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p