عنوان:

‫چالش‌های متداول توسعه‌دهندگان ASP.NET Core هنگام استفاده از Nginx - قسمت پنجم - لاگ‌برداری و عیب‌یابی


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۴/۱۱ ۰۸:۱۰
آدرس: www.dntips.ir
تصور کنید یک روز صبح، یکی از کاربران به شما اطلاع می‌دهد که سایت با خطا مواجه شده است. همه‌چیز تا دیروز به خوبی کار می‌کرد. از کجا شروع می‌کنید؟ در معماری چندلایه‌ای که ما ساخته‌ایم (کلاینت -> Nginx -> Kestrel)، یک خطا می‌تواند دلایل متعددی داشته باشد. آیا مشکل از کانفیگ Nginx است؟ یا برنامه ASP.NET Core ما Crash کرده؟
هدف این فصل، آموزش یک رویکرد سیستماتیک برای عیب‌یابی است. ما یاد می‌گیریم که مانند یک کارآگاه، سرنخ‌ها را از کدام منابع جمع‌آوری کنیم و چگونه آن‌ها را تفسیر کنیم تا به سرعت به ریشه مشکل برسیم.

بخش ۱: دو ستون اصلی لاگ‌برداری
در اکوسیستم ما، دو منبع اصلی برای ثبت وقایع (لاگ) وجود دارد. درک تفاوت آن‌ها، اولین قدم برای عیب‌یابی مؤثر است.
ستون اول: لاگ‌های Nginx (دفتر گزارش نگهبان)
Nginx به عنوان نگهبان دروازه، تمام تعاملات با دنیای بیرون و همچنین تلاش‌هایش برای صحبت با برنامه شما را ثبت می‌کند.
لاگ دسترسی (access.log):
  • مکان:/var/log/nginx/access.log
  • محتوا: این فایل هر درخواست موفقی که به Nginx می‌رسد را ثبت می‌کند. شامل IP کلاینت، تاریخ، نوع درخواست (GET/POST)، آدرس URL، کد وضعیت پاسخ (200, 404, 502 و...) و اطلاعات مرورگر کاربر است.
  • کاربرد: برای بررسی اینکه آیا درخواست کاربر اصلاً به سرور شما رسیده و Nginx چه پاسخی به آن داده است.

لاگ خطا (error.log):
  • مکان:/var/log/nginx/error.log
  • محتوا: این مهم‌ترین فایل شما برای شروع عیب‌یابی است. هر مشکلی که خود Nginx با آن مواجه شود، اینجا ثبت می‌شود. به خصوص خطاهایی که در تلاش برای ارتباط با Kestrel رخ می‌دهد.
  • نمونه خطا:2025/06/26 02:00:00 [error] 1122#1122: *1 connect() to http://localhost:5000 failed (111: Connection refused) while connecting to upstream این خطا به وضوح می‌گوید "نتوانستم به Kestrel وصل شوم چون اتصال را رد کرد".

ستون دوم: لاگ‌های برنامه ASP.NET Core (خاطرات روزانه اپلیکیشن)
این لاگ‌ها شامل تمام اتفاقاتی است که درون کد شما رخ می‌دهد.
  • مکان: از آنجایی که ما برنامه را با systemd به عنوان سرویس اجرا کردیم، تمام خروجی‌های کنسول برنامه به صورت متمرکز در Journald ذخیره می‌شود.
  • نحوه دسترسی: با دستور journalctl که در قسمت ۲ یاد گرفتیم.
# مشاهده لاگ‌های سرویس به صورت زنده
sudo journalctl -u kestrel-mywebapp.service -f
  • محتوا: هر چیزی که شما با ILogger در کدتان ثبت می‌کنید، به همراه خطاهای زمان اجرا (Runtime Exceptions) مانند NullReferenceException، خطاهای اتصال به دیتابیس و... در اینجا نمایش داده می‌شود.

بخش ۲: یک گردش کار سیستماتیک برای عیب‌یابی
وقتی با یک خطا مواجه شدید، مراحل زیر را به ترتیب طی کنید:
  • خطا را بازتولید کنید: سعی کنید خودتان دقیقاً همان کاری که کاربر انجام داده را تکرار کنید تا خطا را ببینید.
  • اول لاگ خطای Nginx را چک کنید:
sudo tail -f /var/log/nginx/error.log
  • سناریو الف: اگر خطایی از خانواده 50x (مانند 502, 503, 504) مشاهده کردید، یعنی Nginx سالم است اما نتوانسته با برنامه شما ارتباط برقرار کند. مشکل در سمت برنامه ASP.NET Core است. به مرحله ۳ بروید.
  • سناریو ب: اگر خطای دیگری دیدید (مثلاً permission denied روی یک فایل استاتیک)، مشکل از پیکربندی خود Nginx است.
  • سناریو ج: اگر هیچ خطایی در این فایل ثبت نشد، یعنی Nginx درخواست را موفقیت‌آمیز (مثلاً با کد 200) به برنامه ارسال کرده اما برنامه شما یک صفحه خطا (مثلاً با کد 500) برگردانده است. به مرحله ۳ بروید.
  • سپس لاگ برنامه را چک کنید:
# برای پریدن به انتهای لاگ و دیدن آخرین خطاها
sudo journalctl -u kestrel-mywebapp.service -e
  • اینجا به دنبال متن استثناها (Exceptions) و Stack Trace بگردید. ۹۰٪ از خطاهای برنامه‌نویسی در این لاگ‌ها خود را نشان می‌دهند.

بخش ۳: سناریوهای رایج و راه‌حل‌ها
سناریو ۱: لاگ‌های برنامه‌ام جزئیات کافی برای حل مشکل را ندارند!
  • علت: در فایل appsettings.Production.json، سطح لاگ‌برداری (LogLevel) معمولاً روی Warning یا Error تنظیم شده تا لاگ‌های اضافی در محیط پروداکشن تولید نشود.
  • راه‌حل: برای عیب‌یابی، به طور موقت سطح لاگ را پایین بیاورید تا جزئیات بیشتری ثبت شود. فایل appsettings.Production.json را باز کنید:
{
  "Logging": {
    "LogLevel": {
      "Default": "Information", // این مقدار را از Warning به Information تغییر دهید
      "Microsoft.AspNetCore": "Warning"
    }
  }
}
  • سپس سرویس را ری‌استارت کنید: sudo systemctl restart kestrel-mywebapp.service. حالا لاگ‌های بسیار دقیق‌تری خواهید داشت. (فراموش نکنید پس از حل مشکل، آن را به حالت قبل برگردانید).

سناریو ۲: من از Serilog برای ثبت لاگ در فایل استفاده می‌کنم، اما فایلی ساخته نمی‌شود.
  • علت: کاربر سرویس شما (www-data) اجازه نوشتن (Write Permission) در پوشه‌ای که برای ثبت لاگ مشخص کرده‌اید را ندارد.
  • راه‌حل: پوشه لاگ را دستی ایجاد کرده و مالکیت آن را به کاربر سرویس بدهید.
# یک پوشه استاندارد برای لاگ برنامه‌ها
sudo mkdir /var/log/mywebapp
sudo chown www-data:www-data /var/log/mywebapp
  • سپس در تنظیمات Serilog، مسیر فایل لاگ را به این پوشه جدید تغییر دهید.

سناریو ۳: تفاوت خطاهای 502, 503 و 504 در Nginx چیست؟
این کدها سرنخ‌های بسیار خوبی به ما می‌دهند:
502 Bad Gateway (دروازه خراب):
  • ترجمه ساده: "درِ خانه Kestrel را زدم، اما کسی جواب نداد."
  • معنی: سرویس برنامه شما به احتمال زیاد Down یا Crash کرده و اصلاً در حال اجرا نیست. اولین کاری که می‌کنید systemctl status و سپس journalctl را چک کنید.

503 Service Unavailable (سرویس در دسترس نیست):
  • ترجمه ساده: "در زدم، کسی جواب داد ولی گفت الان خیلی شلوغ است و نمی‌تواند پاسخگو باشد."
  • معنی: برنامه شما در حال اجراست اما به دلیل بار زیاد یا قرار داشتن در وضعیت خاصی (مثلاً در حال راه‌اندازی) نمی‌تواند به درخواست‌ها پاسخ دهد.

504 Gateway Timeout (وقفه در دروازه):
  • ترجمه ساده: "در زدم، مرا به داخل راه دادند، سوالم را پرسیدم، اما آنقدر منتظر ماندم که حوصله‌ام سر رفت و برگشتم."
  • معنی: Nginx با موفقیت به Kestrel وصل شده، اما برنامه شما برای پاسخ دادن بیش از حد طول داده است (مثلاً درگیر یک کوئری سنگین دیتابیس یا یک حلقه بی‌نهایت شده). این خطا مستقیماً به یک مشکل عملکردی (Performance Issue) در کد شما اشاره دارد.

جمع‌بندی قسمت ۵:
عیب‌یابی یک مهارت است، نه یک کار تصادفی. با درک نقش هر لایه و دانستن اینکه لاگ‌های مربوط به آن کجا قرار دارند، شما می‌توانید به جای حدس زدن، به صورت علمی و گام به گام مشکل را ریشه‌یابی کنید. شما اکنون ابزارهای لازم برای حفظ سلامت و پایداری سیستم خود را در اختیار دارید. در قسمت پایانی، نگاهی به چند موضوع پیشرفته خواهیم داشت تا عملکرد و قابلیت‌های برنامه خود را یک قدم فراتر ببریم.