مقدمة: لماذا تسجيل الدخول في Go ليس مجرد fmt.Println
تسجيل الدخول هو عيون وآذان أي تطبيق يعمل في بيئة الإنتاج. في عالم Go (Golang)، تطور نهج التسجيل بشكل كبير: من الإخراج البسيط إلى وحدة التحكم عبر fmt.Println إلى مسجلات هيكلية قوية قادرة على إنتاج سجلات متوافقة مع JSON لأنظمة جمع السجلات المركزية (ELK, Grafana Loki, Datadog).
في هذه المقالة، سنقوم بتحليل أفضل الممارسات لتسجيل الدخول في Go عمليًا، وليس نظريًا. ستتعلم كيفية إعداد مستويات التسجيل، واستخدام السجلات الهيكلية، وتجنب "الضوضاء"، ومعالجة الأخطاء بشكل صحيح. جميع أمثلة الكود جاهزة للاستخدام في مشاريعك.
1. مكتبة log القياسية: متى تكون كافية ومتى لا تكون
توفر Go حزمة log المضمنة من المكتبة القياسية. إنها بسيطة، ولكن لها قيود كبيرة.
مثال أساسي
package main
import ( "log" "os")
func main() { // إعداد الإخراج إلى ملف file, _ := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) defer file.Close() log.SetOutput(file)
log.Println("تم تشغيل التطبيق") log.Printf("المستخدم %s مصرح له", "admin") log.Fatal("خطأ حرج: فشل الاتصال بقاعدة البيانات")}المزايا:
- لا يتطلب تثبيت تبعيات خارجية.
- سهولة الاستخدام للنصوص البرمجية الصغيرة أو أدوات CLI.
العيوب:
- لا توجد مستويات تسجيل (فقط Print, Fatal, Panic).
- تنسيق الإخراج ثابت (التاريخ، الوقت، الرسالة).
- لا توجد حقول هيكلية (مفتاح-قيمة).
- يصعب تحليلها بواسطة أنظمة جمع السجلات.
الخلاصة: بالنسبة لخدمات الإنتاج، أو بنية الخدمات المصغرة، أو أي تطبيق يتطلب مراقبة، فإن log القياسي غير مناسب. انتقل إلى التسجيل الهيكلي.
2. التسجيل الهيكلي مع zerolog: المعيار الحديث
مكتبة zerolog هي واحدة من أشهر وأسرع المسجلات في Go. وهي تدعم مستويات التسجيل، وإخراج JSON افتراضيًا، والحد الأدنى من تخصيص الذاكرة.
التثبيت
go get -u github.com/rs/zerolog/logمثال على الإعداد والاستخدام
package main
import ( "os" "time"
"github.com/rs/zerolog" "github.com/rs/zerolog/log")
func main() { // إعداد تنسيق الوقت zerolog.TimeFieldFormat = time.RFC3339
// الإخراج إلى وحدة التحكم بالألوان (للتطوير) log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339})
// للإنتاج — JSON إلى stdout // log.Logger = zerolog.New(os.Stdout).With().Timestamp().Logger()
log.Info().Msg("تم تشغيل الخادم على المنفذ 8080") log.Debug().Str("module", "auth").Msg("محاولة دخول المستخدم") log.Error().Err(err).Str("user_id", "12345").Msg("خطأ في التفويض") log.Fatal().Int("attempt", 3).Msg("تم تجاوز عدد المحاولات")}مستويات التسجيل في zerolog
- Trace (
log.Trace()) — للتصحيح العميق. - Debug (
log.Debug()) — معلومات تصحيح الأخطاء. - Info (
log.Info()) — الأحداث العادية. - Warn (
log.Warn()) — التحذيرات (ليست أخطاء). - Error (
log.Error()) — الأخطاء التي تتطلب الانتباه. - Fatal (
log.Fatal()) — أخطاء قاتلة (تنهي البرنامج). - Panic (
log.Panic()) — ذعر مع إخراج المكدس.
أفضل ممارسة: في الإنتاج، قم بتعيين الحد الأدنى