आपका एप्लिकेशन काम कर रहा है, लेकिन क्या आप सुनिश्चित हैं कि अंदर क्या हो रहा है?
\n\nकल्पना करें: आपने Go में एक माइक्रोसर्विस को प्रोडक्शन में डिप्लॉय किया। यह क्रैश नहीं हो रहा है, 500 एरर नहीं दे रहा है, लेकिन उपयोगकर्ता शिकायत कर रहे हैं कि पेज "कुछ धीमा" लोड हो रहा है। आप मॉनिटरिंग में देखते हैं — CPU 30%, मेमोरी सामान्य है। क्या करें? Go में ऑब्ज़र्वेबिलिटी के बिना, आप बिना नक्शे और कम्पास के जहाज के कप्तान हैं।
\n\nऑब्ज़र्वेबिलिटी (अवलोकनीयता) सिर्फ "लॉग्स" नहीं है। यह तीन स्तंभों पर आधारित है: ट्रेसिंग, मेट्रिक्स और लॉग्स। ये मिलकर आपको एक सुपरपावर देते हैं: सिस्टम में क्या हो रहा है, इसे समझना, भले ही आपको समस्या की उम्मीद न हो। इस लेख में हम Go कोड उदाहरणों के साथ इनमें से प्रत्येक पहलू पर चर्चा करेंगे। आप सिर्फ सिद्धांत नहीं पढ़ेंगे — आपको तैयार रेसिपीज़ मिलेंगी जिन्हें आज ही लागू किया जा सकता है।
\n\nGo ऑब्ज़र्वेबिलिटी के लिए आदर्श भाषा क्यों है?
\n\nGo को बैकएंड सिस्टम के लिए बनाया गया था, जहाँ प्रदर्शन और विश्वसनीयता महत्वपूर्ण है। मानक लाइब्रेरी (net/http, database/sql) पहले से ही मेट्रिक्स देने और ट्रेसिंग के लिए कॉन्टेक्स्ट को सपोर्ट करने में सक्षम है। और OpenTelemetry Go और Prometheus Go का इकोसिस्टम ऑब्ज़र्वेबिलिटी को लागू करना सरल और सुरुचिपूर्ण बनाता है।
लेकिन मुख्य बात यह है कि Go में कोई "जादू" नहीं है। आप ऐसा कोड लिखते हैं जिसे बिना किसी परेशानी के मापा, ट्रेस और लॉग किया जा सकता है। आइए देखें कि यह कैसे किया जाता है।
\n\nGo में ट्रेसिंग: OpenTelemetry क्रियान्वयन
\n\nट्रेसिंग (ट्रेसिंग) सिस्टम में प्रवेश से लेकर बाहर निकलने तक एक अनुरोध की कहानी है। यह दिखाता है कि प्रत्येक चरण में कितना समय लगा: DB क्वेरी, बाहरी API कॉल, डेटा प्रोसेसिंग। Go में, ट्रेसिंग कॉन्टेक्स्ट (context.Context) पर आधारित है।
OpenTelemetry SDK सेटअप करना
\n\nपैकेज इंस्टॉल करें:
\ngo get go.opentelemetry.io/otel \\\n go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \\\n go.opentelemetry.io/otel/sdk/trace\n\nअब ट्रेसर को इनिशियलाइज़ करें:
\n\npackage main\n\nimport (\n "context"\n "log"\n "go.opentelemetry.io/otel"\n "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"\n "go.opentelemetry.io/otel/sdk/trace"\n)\n\nfunc initTracer() {\n exporter, err := otlptracehttp.New(context.Background())\n if err != nil {\n log.Fatal(err)\n }\n\n tp := trace.NewTracerProvider(\n trace.WithBatcher(exporter),\n trace.WithSampler(trace.AlwaysSample()),\n )\n otel.SetTracerProvider(tp)\n}\n\nHTTP हैंडलर में स्पैन (span) बनाना
\n\nयहाँ बताया गया है कि वास्तविक कोड में ट्रेसिंग कैसी दिखती है:
\n\nfunc userHandler(w http.ResponseWriter, r *http.Request) {\n tracer := otel.Tracer("user-service")\n ctx, span := tracer.Start(r.Context(), "getUser")\n defer span.End()\n\n // DB क्वेरी का अनुकरण\n user, err := getUserFromDB(ctx, r.URL.Query().Get("id"))\n if err != nil {\n span.RecordError(err)\n span.SetStatus(codes.Error, err.Error())\n http.Error(w, err.Error(), 500)\n return\n }\n\n span.SetAttributes(\n attribute.String("user.id", user.ID),\n attribute.Int64("user.age", int64(user.Age)),\n )\n\n // बाहरी कॉल के लिए नेस्टेड स्पैन\n _, childSpan := tracer.Start(ctx, "callAnalyticsAPI")\n defer childSpan.End()\n\n callAnalyticsAPI(user)\n \n w.Write([]byte("OK"))\n}\n\nप्रत्येक स्पैन में नाम, आरंभ और समाप्ति समय, विशेषताएँ और स्थिति होती है। Jaeger या Grafana Tempo में, आप अनुरोध का पूरा मानचित्र देखेंगे।
\n\nव्यावहारिक सलाह
\nपूरे एप्लिकेशन में कॉन्टेक्स्ट पास करना न भूलें। Go में, यह स्वचालित रूप से होता है यदि आप फ़ंक्शन सिग्नेचर में context.Context का उपयोग करते हैं। OpenTelemetry Go स्वचालित रूप से HTTP अनुरोध से कॉन्टेक्स्ट ले लेगा यदि आप middleware का उपयोग करते हैं।
मेट्रिक्स: Prometheus और Go में एक्सपोर्ट
\n\nमेट्रिक्स वे संख्याएँ हैं जो सिस्टम की स्थिति के बारे में बताती हैं: RPS, लेटेंसी, एरर की संख्या, उपयोग