عنوان:

‫عیب‌یابی خطاهای استارت‌آپ ASP.NET Core در لینوکس


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۴/۰۶ ۰۸:۰۵
آدرس: www.dntips.ir
مقدمه: صحنه جرم - وقتی سرویس شما اجرا نمی‌شود!

در این مطلب می‌خواهیم نقش یک کارآگاه را بازی کنیم. تصور کنید شما به تازگی Runtime دات‌نت روی سرور لینوکس خود را به یک نسخه جدیدتر ارتقا داده‌اید. اپلیکیشن ASP.NET Core خود را پابلیش و روی سرور کپی می‌کنید. سرویس systemd را ری‌استارت می‌کنید و با هیجان آدرس سایت را در مرورگر وارد می‌کنید... اما سایت بالا نمی‌آید!
شما اولین و مهم‌ترین ابزار خود را به کار می‌گیرید:
sudo systemctl status my-site.service
و با یک صحنه جرم ترسناک روبرو می‌شوید:
● my-site.service - My Site
     Loaded: loaded (/etc/systemd/system/my-site.service; enabled; preset: enabled)
     Active: activating (auto-restart) (Result: signal) since Tue 2025-06-24 13:30:00 EDT; 2s ago
    Process: 96890 ExecStart=/usr/bin/dotnet /path/site.dll (code=killed, signal=ABRT)
   Main PID: 96890 (code=killed, signal=ABRT)
بیایید این سرنخ‌ها را به عنوان کارآگاه بررسی کنیم:
  • Active: activating (auto-restart): این یعنی systemd (مدیر سرویس‌های ما) مثل یک همکار دلسوز، تلاش می‌کند سرویس شما را اجرا کند، اما سرویس بلافاصله پس از اجرا "می‌میرد". systemd دوباره تلاش می‌کند و این چرخه مدام تکرار می‌شود.
  • code=killed, signal=ABRT: این سرنخ اصلی ماست! ABRT مخفف Abort (توقف ناگهانی) است. این یک خروج عادی نیست. این یعنی اپلیکیشن شما در همان لحظات اولیه اجرا، با یک خطای مرگبار و غیرقابل‌تحمل مواجه شده و خودش را متوقف کرده است. این خطا از داخل خود اپلیکیشن .NET نشأت گرفته است.
ما فهمیدیم چه اتفاقی افتاده (سرویس در حال کرش کردن است)، اما هنوز نمی‌دانیم چرا.

بخش اول: بازجویی از شاهد ماجرا با journalctl
systemd یک دفترچه خاطرات بسیار دقیق به نام Journal دارد که تمام وقایع مربوط به سرویس‌ها را ثبت می‌کند. ما برای خواندن این دفترچه از دستور journalctl استفاده می‌کنیم. مشکل اینجاست که اگر فقط دستور زیر را اجرا کنید:
sudo journalctl -u my-site.service
شما با یک دیوار بلند از متن‌ها و لاگ‌های مربوط به روزها یا هفته‌های گذشته مواجه می‌شوید. پیدا کردن خطای اخیر در این انبوه اطلاعات، مانند پیدا کردن یک سوزن در انبار کاه است. ما به عنوان یک کارآگاه حرفه‌ای، به ابزارهای بهتری برای "فیلتر کردن" این اطلاعات نیاز داریم.

بخش دوم: جعبه‌ابزار کارآگاه - فیلترهای قدرتمند journalctl
بیایید با ابزارهای اصلی برای پرسیدن سوالات دقیق از journalctl آشنا شویم:

ابزار شماره ۱: تماشای زنده صحنه جرم (فیلتر -f)
این یکی از پرکاربردترین ابزارهاست. آپشن -f یا --follow به journalctl می‌گوید که لاگ‌ها را به صورت زنده و در لحظه نمایش بده.
روش کار:
  • یک پنجره ترمینال باز کنید و این دستور را در آن اجرا کنید: sudo journalctl -u my-site.service -f
  • یک پنجره ترمینال دیگر باز کنید و در آن، سرویس را ری‌استارت کنید: sudo systemctl restart my-site.service
  • حالا به پنجره اول برگردید و ببینید که چگونه لاگ‌های مربوط به تلاش برای اجرای برنامه و خطای آن، در همان لحظه جلوی چشمان شما ظاهر می‌شوند!

ابزار شماره ۲: سفر در زمان (فیلتر --since)
همانطور که در سناریو مطرح شد، اگر خطا در گذشته رخ داده باشد، می‌توانیم به journalctl بگوییم فقط لاگ‌های مربوط به یک بازه زمانی خاص را به ما نشان دهد.
# فقط لاگ‌های امروز را نشان بده
sudo journalctl -u my-site.service --since today

# فقط لاگ‌های ۱۰ دقیقه اخیر را نشان بده
sudo journalctl -u my-site.service --since "10 minutes ago"

# فقط لاگ‌های مربوط به بعد از یک تاریخ و زمان مشخص
sudo journalctl -u my-site.service --since "2025-06-24 13:00:00"

ابزار شماره ۳: رفتن به سر اصل مطلب (فیلترهای -n و -e)
  • -n یا --lines: به شما اجازه می‌دهد فقط تعداد مشخصی از آخرین خطوط لاگ را ببینید. این برای گرفتن یک نمای کلی از آخرین اتفاقات عالی است.
  • sudo journalctl -u my-site.service -n 50 (۵۰ خط آخر را نشان می‌دهد)
  • -e یا --pager-end: این دستور بلافاصله شما را به انتهای لاگ‌ها می‌برد، جایی که جدیدترین خطاها ثبت شده‌اند.
  • sudo journalctl -u my-site.service -e

ترکیب طلایی: یک دستور ترکیبی بسیار قدرتمند برای شروع عیب‌یابی این است:
sudo journalctl -u my-site.service -n 100 -f
این دستور می‌گوید: "۱۰۰ خط آخر لاگ‌های این سرویس را به من نشان بده و بعد از آن، منتظر بمان و هر لاگ جدیدی را به صورت زنده نمایش بده."

بخش سوم: حل پرونده - تفسیر لاگ خطا
حالا که ابزارهای خود را داریم، به سناریوی اصلی برمی‌گردیم. ما با یکی از دستورهای فیلتر شده (مثلاً --since today) لاگ‌ها را بررسی می‌کنیم و به احتمال زیاد با پیامی شبیه به این مواجه می‌شویم:
It was not possible to find any compatible framework version
The framework 'Microsoft.AspNetCore.App', version '8.0.6' was not found.
  - No frameworks were found in the [/usr/share/dotnet/shared/Microsoft.AspNetCore.App] directory.

You can resolve the issue by installing the specified framework version or changing the specified version in the application's config file.
Learn more at https://aka.ms/dotnet/ tìm-runtime
تحلیل کارآگاه:
این پیام به وضوح علت اصلی Abort شدن برنامه را به ما می‌گوید:
"اپلیکیشن شما برای اجرا شدن به فریمورک Microsoft.AspNetCore.App نسخه 8.0.6 نیاز دارد، اما من نتوانستم این نسخه را روی سرور پیدا کنم."
این دقیقاً با سناریوی ما (ارتقای دات‌نت) همخوانی دارد. احتمالاً ما نسخه جدیدتر .NET (مثلاً .NET 9) را نصب کرده‌ایم، اما فراموش کرده‌ایم که نسخه دقیق Runtime مورد نیاز این اپلیکیشن خاص (8.0.6) را هم نصب کنیم یا اپلیکیشن را برای کار با نسخه جدید، دوباره پابلیش نکرده‌ایم.

راه حل:
  • نصب نسخه دقیق .NET Runtime مورد نیاز روی سرور.
  • یا پابلیش مجدد اپلیکیشن با هدف‌گذاری نسخه .NET نصب شده روی سرور.

نتیجه‌گیری:
systemctl status به شما می‌گوید که یک "جرم" اتفاق افتاده است. اما journalctl با فیلترهای قدرتمندش، "اعترافات" دقیق اپلیکیشن شما را ثبت کرده و به شما می‌گوید که دقیقاً چرا و چگونه این اتفاق افتاده است. تسلط بر این دو دستور، شما را از یک توسعه‌دهنده به یک کارآگاه سرور حرفه‌ای تبدیل می‌کند.
مطالب مشابه