आपका Go कोड क्यों क्रैश होता है, और इसे बिना सिरदर्द के कैसे ठीक करें
\n\nआपने अपनी राय में Go में एक परफेक्ट कोड लिखा है। कंपाइलेशन सफल रहा, टेस्ट ग्रीन हैं... लेकिन प्रोडक्शन में सब कुछ बिखर जाता है। परिचित लगता है? डेवलपमेंट की वास्तविक दुनिया में आपका स्वागत है, जहाँ बग्स शुरुआती लोगों की गलतियाँ नहीं, बल्कि पेशेवर विकास का हिस्सा हैं। आज हम Go कोड की डिबगिंग को इस तरह से समझेंगे कि आप न केवल त्रुटियाँ ढूंढेंगे, बल्कि कोड लिखने के चरण में ही उन्हें रोक पाएंगे।
\n\nGo एक ऐसी भाषा है जो डेवलपर को डिबगिंग के लिए शक्तिशाली उपकरण "बॉक्स से बाहर" ही देती है। लेकिन कई लोग केवल fmt.Println का उपयोग करते हैं और ईमानदारी से आश्चर्य करते हैं कि उनकी गोरूटीन गर्म छत पर बिल्लियों की तरह क्यों व्यवहार करती हैं। आइए इसे हमेशा के लिए ठीक करें।
तकनीक #1: स्मार्ट Print - जब log.Fatal की आवश्यकता नहीं है
\n\nहाँ, मुझे पता है आप क्या कहेंगे: "मुझे delve की क्या ज़रूरत है जब मैं एक वेरिएबल प्रिंट कर सकता हूँ?" और आप 80% मामलों में सही होंगे। लेकिन समस्या fmt.Println में नहीं है, बल्कि इस बात में है कि आप इसका उपयोग कैसे करते हैं।
Println से structured logging पर जाएँ
\n\nदर्जनों प्रिंट चिपकाने के बजाय, log या slog पैकेज का उपयोग करें (Go 1.21 से उपलब्ध):
package main\n\nimport (\n "log/slog"\n "os"\n)\n\nfunc main() {\n logger := slog.New(slog.NewTextHandler(os.Stdout, nil))\n \n // बजाय fmt.Println("error:", err) के\n if err := doSomething(); err != nil {\n logger.Error("ऑपरेशन विफल", \n "error", err,\n "module", "data_processor",\n "attempt", 3,\n )\n }\n}\n\n\nयह दृष्टिकोण आपको संरचित लॉग देता है, जिन्हें पार्स करना, फ़िल्टर करना और विश्लेषण करना आसान है। प्रोडक्शन में यह आपको रात के कॉल से बचाएगा।
\n\nलाइफहैक: डीबग लॉग के लिए सशर्त कंपाइलेशन
\n\nप्रोडक्शन को अव्यवस्थित न करने के लिए, build tags का उपयोग करें:
\n\n//go:build debug\n\npackage main\n\nvar debug = true\n\n\n//go:build !debug\n\npackage main\n\nvar debug = false\n\n\nफ्लैग -tags debug के साथ चलाएँ - विस्तृत लॉग प्राप्त करें। बिना फ्लैग के - स्वच्छ प्रोडक्शन।
तकनीक #2: Delve - Go के लिए आपका निजी जासूस
\n\nअगर print डिबगिंग एक साइकिल है, तो Delve एक Tesla है। यह डिबगर विशेष रूप से Go के लिए बनाया गया है और गोरूटीन, इंटरफ़ेस और यहाँ तक कि generics को भी समझता है। इंस्टॉलेशन सरल है:
\n\ngo install github.com/go-delve/delve/cmd/dlv@latest\n\n\nब्रेकपॉइंट जो सोच सकते हैं
\n\nDelve आपको केवल breakpoint नहीं, बल्कि सशर्त बिंदु सेट करने की अनुमति देता है:
\n\n(dlv) break main.go:25 if userID == 42\n(dlv) continue\n\n\nडिबगर केवल तभी रुकेगा जब userID 42 के बराबर हो। कल्पना करें कि लूप को डीबग करते समय यह कितना समय बचाता है।
गोरूटीन की जाँच
\n\nGo में सबसे डरावनी चीज़ें deadlock और race condition हैं। Delve सभी सक्रिय गोरूटीन दिखाता है:
\n\n(dlv) goroutines\n Goroutine 1 - User: ./main.go:10 main.main (0x109a5b6)\n Goroutine 2 - User: ./main.go:15 main.worker (0x109a6c8)\n* Goroutine 3 - User: ./main.go:22 main.worker (0x109a6c8)\n\n\nतारांकन वर्तमान गोरूटीन दिखाता है। उनके बीच स्विच करें:
\n\n(dlv) goroutine 2\n(dlv) stack\n\n\nमेमोरी के साथ काम: अंदर क्या है देखें
\n\nकमांड locals सभी स्थानीय वेरिएबल दिखाता है, और print उनके मान प्रकारों के साथ आउटपुट करता है:
(dlv) locals\ndata = []int len: 100000, cap: 100000\nresult = map[string]int ["error": 5, "success": 99995]\n(dlv) print data[0:5]\n[]int len: 5, cap: 100000, [42, 17, 89, 3, 256]\n\n\nतकनीक #3: pprof प्रोफाइलिंग - अड़चनें ढूँढें
\n\nआपका कोड काम करता है, लेकिन धीमा है? pprof Go का अंतर्निहित प्रोफाइलर है। यह दिखाएगा कि प्रोग्राम कहाँ "धीमा" है और कहाँ मेमोरी खाता है।
\n\n