اضافه کردن حالت دیباگ (Adding Debug Mode)
اگر از فریمورکهای وب (Web Frameworks) برای زبانهای دیگر مانند Django یا Laravel استفاده کردهاید، احتمالاً با ایدهی حالت دیباگ (Debug Mode) آشنا هستید که در آن خطاهای دقیق (Detailed Errors) به جای پیام عمومی (Generic Message) "خطای داخلی سرور" به کاربر نمایش داده میشود.
هدف شما در این تمرین این است که یک حالت «دیباگ» مشابه برای برنامه خود تنظیم کنید که با استفاده از فلگ خط فرمان (Command Line Flag) -debug به صورت زیر فعال شود:
$ go run ./cmd/web -debug
هنگام اجرای برنامه در حالت دیباگ، هرگونه خطاهای دقیق (Detailed Errors) و ردیابی استک (Stack Trace) باید در مرورگر نمایش داده شود، مشابه این:
مرحله ۱
یک فلگ خط فرمان (Command Line Flag) جدید با نام debug و مقدار پیشفرض (Default Value) false ایجاد کنید. سپس مقدار این فلگ خط فرمان را از طریق ساختار برنامه (Application Struct) در دسترس هندلرهای خود قرار دهید.
نکته: تابع flag.Bool() برای این کار مناسبترین است.
مرحله ۲
به فایل cmd/web/helpers.go بروید و تابع کمکی (Helper Function) serverError() را بهروزرسانی کنید تا در صورت تنظیم فلگ debug، یک پیام خطا (Error Message) و ردیابی استک (Stack Trace) دقیق در پاسخ HTTP (HTTP Response) رندر کند. در غیر این صورت، پیام خطای عمومی را به صورت عادی ارسال کنید. میتوانید ردیابی استک را با استفاده از تابع debug.Stack() دریافت کنید.
مرحله ۳
تغییرات را امتحان کنید. برنامه را اجرا کنید و با استفاده از DSN بدون پارامتر parseTime=true یک خطای زمان اجرا ایجاد کنید:
$ go run ./cmd/web/ -debug -dsn=web:pass@/snippetbox
بازدید از https://localhost:4000/ باید منجر به پاسخی مانند این شود:
اجرای مجدد برنامه بدون فلگ -debug باید منجر به پیام عمومی "خطای داخلی سرور" شود.
کد پیشنهادی
کد پیشنهادی برای مرحله ۱
package main ... type application struct { debug bool // Add a new debug field. logger *slog.Logger snippets models.SnippetModelInterface users models.UserModelInterface templateCache map[string]*template.Template formDecoder *form.Decoder sessionManager *scs.SessionManager } func main() { addr := flag.String("addr", ":4000", "HTTP network address") dsn := flag.String("dsn", "web:pass@/snippetbox?parseTime=true", "MySQL data source name") // Create a new debug flag with the default value of false. debug := flag.Bool("debug", false, "Enable debug mode") flag.Parse() logger := slog.New(slog.NewTextHandler(os.Stdout, nil)) db, err := openDB(*dsn) if err != nil { logger.Error(err.Error()) os.Exit(1) } defer db.Close() templateCache, err := newTemplateCache() if err != nil { logger.Error(err.Error()) os.Exit(1) } formDecoder := form.NewDecoder() sessionManager := scs.New() sessionManager.Store = mysqlstore.New(db) sessionManager.Lifetime = 12 * time.Hour sessionManager.Cookie.Secure = true app := &application{ debug: *debug, // Add the debug flag value to the application struct. logger: logger, snippets: &models.SnippetModel{DB: db}, users: &models.UserModel{DB: db}, templateCache: templateCache, formDecoder: formDecoder, sessionManager: sessionManager, } tlsConfig := &tls.Config{ CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256}, } srv := &http.Server{ Addr: *addr, Handler: app.routes(), ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError), TLSConfig: tlsConfig, IdleTimeout: time.Minute, ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } logger.Info("starting server", "addr", srv.Addr) err = srv.ListenAndServeTLS("./tls/cert.pem", "./tls/key.pem") logger.Error(err.Error()) os.Exit(1) } ...
کد پیشنهادی برای مرحله ۲
... func (app *application) serverError(w http.ResponseWriter, r *http.Request, err error) { var ( method = r.Method uri = r.URL.RequestURI() trace = string(debug.Stack()) ) app.logger.Error(err.Error(), "method", method, "uri", uri) if app.debug { body := fmt.Sprintf("%s\n%s", err, trace) http.Error(w, body, http.StatusInternalServerError) return } http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } ...
واژهنامه اصطلاحات فنی
| اصطلاح فارسی | معادل انگلیسی | توضیح |
|---|---|---|
| حالت دیباگ | Debug Mode | حالت اشکالزدایی برنامه |
| فریمورکهای وب | Web Frameworks | چارچوبهای توسعه وب |
| خطاهای دقیق | Detailed Errors | پیامهای خطای جزئی |
| پیام عمومی | Generic Message | پیام خطای کلی |
| فلگ خط فرمان | Command Line Flag | پارامتر ورودی برنامه |
| ردیابی استک | Stack Trace | مسیر اجرای برنامه |
| مقدار پیشفرض | Default Value | مقدار اولیه پارامتر |
| ساختار برنامه | Application Struct | ساختار داده اصلی برنامه |
| تابع کمکی | Helper Function | تابع کمکی برای عملیات رایج |
| پیام خطا | Error Message | توضیح خطای رخ داده |
| پاسخ HTTP | HTTP Response | پاسخ ارسالی به مرورگر |