محل لاگ لینوکس: هر سرویس کجا می‌نویسد؟

راهنمای دقیق محل لاگ لینوکس: مسیر فایل‌های لاگ هر سرویس، تفاوت توزیع‌ها، و اینکه چرا journald جای /var/log را گرفته است.

۶ دقیقه به‌روزرسانی ۱۴ مهر ۱۴۰۵

سرویس بالاست، کاربر می‌گوید «دیروز کار می‌کرد»، و شما یک tail -f /var/log/syslog می‌زنید که هیچ خط تازه‌ای نشان نمی‌دهد. مشکل اینجاست که روی آن سرور، سرویس موردبحث اصلاً در syslog نمی‌نویسد. محل لاگ لینوکس یک مسیر ثابت نیست؛ به توزیع، به init system، و به اینکه سرویس چطور کامپایل شده بستگی دارد. تا این سه‌تا را جدا نکنید، دنبال فایل لاگ گشتن وقت‌تلف‌کن است.

نقشه‌ی سریع: هر سرویس کجا می‌نویسد

روی اکثر توزیع‌های امروزی، این جدول ۹۰٪ جست‌وجوها را جواب می‌دهد:

سرویسمسیر معمولنکته
کرنل و بوت/var/log/kern.log یا dmesgروی RHEL خانواده در /var/log/messages
احراز هویت و SSH/var/log/auth.logروی CentOS/Rocky: /var/log/secure
Nginx/var/log/nginx/access.logخطا در error.log همان پوشه
Apache/var/log/apache2/ یا /var/log/httpd/بسته به توزیع فرق می‌کند
MySQL / MariaDB/var/log/mysql/error.logروی RHEL: /var/log/mysqld.log
PostgreSQL/var/log/postgresql/یا داخل data directory
PHP-FPM/var/log/php8.2-fpm.logشماره نسخه در نام فایل
Dockerjournalctl -u dockerلاگ کانتینرها جای دیگری است

این جدول را حفظ نکنید. دستور systemctl status nginx در خط آخر خودش می‌گوید لاگ کجاست، و nginx -T کل کانفیگ را با مسیر access_log چاپ می‌کند. سریع‌تر از حدس زدن است.

journald در برابر فایل: کدام را باور کنیم

روی Ubuntu 22.04 و بالاتر، و تقریباً همه‌ی توزیع‌هایی که systemd دارند، بخش بزرگی از لاگ‌ها اصلاً فایل متنی نیستند. در باینری‌های journal ذخیره می‌شوند، زیر /var/log/journal/ یا /run/log/journal/. اگر پوشه‌ی اول وجود نداشته باشد، لاگ‌ها در RAM می‌مانند و با هر ریبوت پاک می‌شوند. این یکی از رایج‌ترین دلایل «لاگ دیروزم نیست» است.

برای دیدن اینکه journal روی دیسک می‌نویسد یا نه:

ls -d /var/log/journal
journalctl --disk-usage

اگر دستور اول خطا داد، یعنی persistent نیست. با mkdir -p /var/log/journal && systemd-journald --flush و یک ری‌استارت سرویس درست می‌شود. حجم پیش‌فرض journal روی نصب‌های معمول تا ۱۰٪ از فایل‌سیستم رشد می‌کند؛ روی سروری با دیسک ۴۰ گیگابایتی یعنی حدود ۴ گیگابایت، که اگر حواستان نباشد با df -h یک روز صبح غافلگیر می‌شوید.

فیلترهایی که واقعاً به کار می‌آیند

journalctl -u nginx --since "1 hour ago" نقطه‌ی شروع خوبی است. برای دیدن فقط خطاها -p err اضافه کنید، و برای دنبال‌کردن زنده -f. اگر PID دارید، journalctl _PID=1234 دقیقاً همان پروسه را می‌دهد. این آخری وقتی چند worker دارید و فقط یکی‌شان مشکل دارد، تفاوت بین ده دقیقه و دو ساعت است.

یک محدودیت واقعی: journald لاگ‌های access وب‌سرور را نگه نمی‌دارد. Nginx و Apache مستقیم در فایل می‌نویسند، چون حجمشان آن‌قدر بالاست که نوشتن در journal عملی نیست. پس روی همان سروری که journald دارد، باید هم journalctl بزنید و هم tail روی فایل. این دو تا مکمل‌اند، جانشین هم نیستند.

این‌جا اشتباه می‌کنند

خطای رایجی که زیاد دیده‌ام: کسی rm /var/log/nginx/access.log می‌زند تا فضا آزاد کند، بعد df -h می‌زند و می‌بیند فضا آزاد نشده. علتش این است که Nginx هنوز فایل را باز نگه داشته و inode زنده است؛ فایل از دایرکتوری غیب شده ولی بایت‌هایش روی دیسک مانده. راه درست truncate -s 0 /var/log/nginx/access.log است، یا logrotate -f /etc/logrotate.d/nginx. اگر قبلاً rm کرده‌اید، با lsof +L1 فایل‌های حذف‌شده‌ی باز را پیدا کنید و سرویس را reload کنید.

اشتباه دوم ظریف‌تر است: بعضی‌ها فکر می‌کنند چون journalctl -u mysql خروجی می‌دهد، پس لاگ MySQL همان‌جاست. در واقع systemd فقط stdout سرویس را می‌گیرد؛ خود MySQL در error.log می‌نویسد و آن فایل جزئیات کامل‌تری دارد. اگر دنبال علت crash می‌گردید، فایل را بخوانید نه journal را.

چرخش لاگ: چیزی که یک شب سرور را می‌خواباند

logrotate به‌صورت پیش‌فرض روزانه اجرا می‌شود و کانفیگ سرویس‌ها در /etc/logrotate.d/ است. یک بلوک معمولی این شکلی است:

/var/log/nginx/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        invoke-rc.d nginx rotate >/dev/null 2>&1
    endscript
}

دو خط اینجا حیاتی‌اند. create 0640 www-data adm مالکیت فایل تازه را تعیین می‌کند؛ اگر اشتباه باشد، بعد از اولین چرخش Nginx دیگر نمی‌تواند بنویسد و سایت با ۵۰۰ بالا می‌آید. و postrotate باید سرویس را وادار کند فایل را دوباره باز کند، وگرنه همان مشکل inode باز تکرار می‌شود. با logrotate -d /etc/logrotate.d/nginx می‌توانید بدون اجرای واقعی، خروجی را ببینید.

روی سرورهایی که ترافیک سنگین دارند، چرخش روزانه کافی نیست. اگر access.log شما در ۲۴ ساعت به چند گیگابایت می‌رسد، size 500M را جای daily بگذارید. اینجا انتخاب بین دو گزینه است: چرخش بر اساس زمان، فایل‌های قابل‌پیش‌بینی می‌دهد و برای تحلیل راحت‌تر است؛ چرخش بر اساس حجم، دیسک را امن‌تر نگه می‌دارد. من روی وب‌سرورهای پرترافیک حجم را انتخاب می‌کنم، چون یک روز پرمصرف می‌تواند قبل از نوبت چرخش، دیسک را پر کند.

وقتی سرور بالا نمی‌آید و لاگ ندارید

بدترین حالت این است که سرویس اصلاً استارت نمی‌خورد و لاگی هم تولید نمی‌کند. اول systemctl status myservice -l --no-pager را بزنید؛ -l باعث می‌شود خطوط کوتاه نشوند و پیام واقعی خطا را ببینید. اگر سرویس با systemd مدیریت نمی‌شود، مستقیم با strace -f -e trace=openat ./binary اجرایش کنید تا ببینید کدام فایل را باز می‌کند و کجا شکست می‌خورد.

اگر مشکل از خود سیستم‌عامل است و دسترسی‌تان قطع شده، از حالت rescue استفاده کنید. راهنمای بازنصب سرور و کار با حالت rescue؛ نجات داده‌ها وقتی دسترسی را از دست دادید دقیقاً همین سناریو را پوشش می‌دهد. و اگر لاگ‌ها نشان می‌دهند مشکل از مصرف منابع است نه از یک سرویس خاص، تشخیص علت لود بالای سرور؛ راهنمای عملی و گام‌به‌گام مسیر درست‌تری است.

تفاوت توزیع‌ها در یک نگاه

روی Debian و Ubuntu، /var/log/syslog همه‌چیز را جمع می‌کند و /var/log/auth.log جدا است. روی RHEL، Rocky و AlmaLinux، خبری از syslog نیست؛ /var/log/messages و /var/log/secure جایشان را گرفته‌اند. روی Alpine که musl دارد و busybox، حتی rsyslog هم ممکن است نصب نباشد و همه‌چیز فقط در journal باشد. اگر اسکریپت مانیتورینگ می‌نویسید، مسیر را hardcode نکنید؛ اول وجود فایل را چک کنید.

یک نکته‌ی عملی برای سرورهای تازه: قبل از اینکه مشکلی پیش بیاید، یک بار ls -la /var/log/ بزنید و ببینید چه چیزی آنجاست. پنج دقیقه الان، در ساعت دو بامداد که سایت خوابیده، صرفه‌جویی بزرگی است. اگر روی زیرساخت ابری کار می‌کنید و می‌خواهید این کار را از ابتدا درست انجام دهید، سرور ابری امکان جدا نگه‌داشتن دیسک لاگ را می‌دهد و مستندات و پایگاه دانش هم نمونه‌های کانفیگ logrotate را دارد. برای سرورهای فیزیکی با دیسک NVMe، نوشتن لاگ پرحجم مسئله‌ی I/O نیست و می‌توانید rotate را بالاتر ببرید.

پرسش‌های پرتکرار

لاگ لینوکس به‌طور پیش‌فرض کجاست؟

پوشه‌ی اصلی /var/log/ است و بیشتر سرویس‌ها زیرپوشه‌ی خودشان را دارند، مثل /var/log/nginx/ یا /var/log/mysql/. روی سیستم‌هایی که systemd دارند، بخشی از لاگ‌ها در journal ذخیره می‌شود و با journalctl خوانده می‌شود، نه با cat.

چطور بفهمم یک سرویس کدام فایل را می‌نویسد؟

سریع‌ترین راه systemctl status <service> است که مسیر لاگ را در خروجی نشان می‌دهد. اگر کافی نبود، lsof -p $(pidof nginx) | grep log تمام فایل‌های لاگ بازِ آن پروسه را لیست می‌کند. برای سرویس‌هایی که کانفیگ دارند، مثل Nginx، دستور nginx -T مقدار access_log را چاپ می‌کند.

چرا لاگ‌های قدیمی‌ام بعد از ریبوت پاک شده‌اند؟

چون journald در حالت volatile کار می‌کند و لاگ‌ها را در /run/log/journal/ نگه می‌دارد که روی tmpfs است. با ساختن /var/log/journal/ و ری‌استارت systemd-journald، حالت persistent فعال می‌شود و لاگ‌ها روی دیسک می‌مانند.

آیا می‌شود لاگ‌ها را به سرور دیگری فرستاد؟

بله، با rsyslog یا با systemd-journal-upload. برای حجم کم، rsyslog روی UDP پورت 514 کافی است؛ برای محیط‌هایی که یکپارچگی لاگ مهم است، TCP با TLS انتخاب درست‌تری است. فقط حواستان باشد که اگر سرور مقصد از دسترس خارج شود، rsyslog محلی ممکن است صف را پر کند و خودش منبع مشکل شود.

آیا این مطلب برایتان مفید بود؟