golang error
stack trace error ردپای خطا
به این معناست که بفهمیم خطا از کجا شروع شده ، یعنی اگر پیام خطا در بیرونی ترین لایه ی برنامه نمایش داده شد ، بتوانیم اولین مرحله بروز خطا را پیدا کنیم
go get github.com/pkg/errors
در گولنگ این پکیج مناسب است امام مشکل اینجاست که برای تعریف ارور باید به روش پکیج ، ارور را تعریف کنیم . اگر خود سازنده ی پکیج هستیم ، می توان این ساختار را رعایت کرد اما اگر استفاده کننده از یه پکیج هستیم ، باید برای رپ کردن ابتدا ارور را به فرمت مورد نظر تبدیل کنیم:
errors.Errorf(“Could not write to file”)
Sentinel Errors (خطای نگهبان)
تعریف خطا از قبل و استفاده از آن برای پیشبینی خطاها.
- errors.Is: بررسی میکند خطای رخ داده برابر با خطای پیشبینی شده است یا خیر، حتی اگر wrapped شده باشد.
- errors.As: تایپ اَسرشن برای خطاها، امکان استفاده از custom error types.
Custom Error Types تایپ دستی خطا
به این نتیجه رسیدیم تو لایه های ریپازیتوری یا http call ها بهتره علاوه بر کد هم داشته باشیم ، در این صورت فانکشنی که قرار ارور هندل کنه می تونه از این دستور استفاده کنه :
if errors.As(err, &customErr) { با این روش تایپ اسرشن میکنیم به اون استراکت و از کد خطا استفاده میکنیم
یادمون باشه تست فقط کافی نیست ، تست میگه کار میکنه یا نه ولی نیاز به metric هم داریم تا بتونیم ببینیم با چه سرعتی کار میکنه
در این روش می توانیم با توجه با اینترفیس ارور ، علاوه بر پیام ارور ، مقدار های دیگری هم به استراکت بیفزاییم ( یعنی ساختار خطا را تغییر دهیم) .
حال در صورت رخ دادن ارور ، با استفاده از errors.As چک کنیم ساختار ارور ، با ساختار پیش بینی شده یکسان است یا خیر .
در این روش هم می بایست تایپ های ارور را پابلیک کرد و در تمامی کد باید فراخوانی شود و این خود مشکل است .
https://earthly.dev/blog/golang-errors/
بهتره ارور ساختار زیر رو داشته باشه :
// built-in interface
type error interface {
Error() string
}
// custom struct error
type AppError struct {
Code int
Description string
Message string
} دلایل :
-
گاهی در یک لایه امکان دارد چندیدن حالت از خطا رخ دهد و در لایه بالا تر باید تشخیص دهیم چه اکشنی نشان دهیم مثال ها :
-
- در ریپو امکان داره getItem بزنیم و پاسخ نیاد ، حال می تونیم یا خطا در سینتکس بخوریم ، امکان داره اون مورد در تیبل نباشه ، شایدم اون لحظه کانکشن قطع شده باشه ،* باید ۳ اکشن متفاوت داشته باشیم
-
- در apiCall ها حالت های مختلفی از خطا داشته باشیم
پس بهتره در لایه ی بیزینس لاجیک بدونیم هر لایه که خطا داره دلیلش چیه
Error wrapping بسته بندی خطا
در این روش ، می توانیم هر جا که به ارور خوردیم در پیام آن ، یک لایه متن ، رپ کنیم و به مرحله بعد دهیم ، هر موقع کاربر خواست می تواند لایه های خطا را ببیند
یکی از خوبی های رپ کردن اینه که میشه با استفاده از Sentinel و متد errors.Is وجود ارور رو دید
err := MyError{Code: 404}
wrapped := fmt.Errorf("failed request: %w", err)
// Is → only works with exact error or wrapped errors
fmt.Println(errors.Is(wrapped, err)) // true
1402.3.18
به بهترین ارور هندل تو گولنگ - البته تا اینجای کار - رسیدیم ، به طوری که توی هر لایه - ریپوزیتوری یا درخواست از بانک - همون جا ارور کامل میشه - متن فارسی - استتوس - دیسکریپشن که می تونه یا بادی پاسخ باشه و یا خطای پستگرس باشه - و در نهایت استک که از ران تایم میزاریم توش - و همچنین در موارد استسنا از لایه درونی مانند ریپازیتوری تا یوز کیس اگر خطا این بود که در مخزن یافت نشد - باید در لایه پایانی overwrite شه به خطای داخلی 500 رخ داده ، اما استک و دیسکریپشن تغییری نکنه
انواع خطا در گولنگ
- Runtime error
خطا هایی که بعد از کامپایل شدن برنامه رخ می دهند یعنی مشکل سینتکسی یا غیر در شروع نبوده و متداول ترین ها ش :
- Undefined variable/function
متغیر یا فانکشنی اطتفاده شود در حالی که تعریف نشده
- Multiple-value in single-value
اصولا زمانی که خروجی یک فانکشن درون یک متغییر ریخته شود و تعداد خروجی های فانکشن بیش از ظرفیت متغیر باشد
- Undefined reference
زمانی که فانکشن پیدا نشود یا ایمپورت نشود
-
syntax error: unexpected علامت زمانی که اشتباه سینتکسی تو کد باشه
-
Panic: runtime error: index out of range
زمانی که ایندکس مورد نظر در رشته نباشد
github.com/pkg/errors
import "github.com/pkg/errors"
var ErrS1 = errors.New("operation failed due to a bad request") // باید اول اسم حتما Err باشه
if err := riskyOperation(); err != nil {
return errors.Wrap(err, "failed to do something") // wrapper
}
if errors.Is(err, ErrGG) { // Unwrap the error
fmt.Println("salam") // حتی اگه خطا رپ شده هم باشد باز هم خروجی میده
}
