Go OpenTelemetry ट्रेसिंग: end-to-end API दृश्यता
Go OpenTelemetry ट्रेसिंग को व्यावहारिक कदमों के साथ समझाएँ ताकि आप HTTP रिक्वेस्ट्स, बैकग्राउंड जॉब्स और थर्ड-पार्टी कॉल्स के across ट्रेसेस, मैट्रिक्स और लॉग्स को सहसंबद्ध कर सकें।

एक Go API के लिए end-to-end ट्रेसिंग का मतलब क्या है
ट्रेस उस एक रिक्वेस्ट का टाइमलाइन होता है जो आपके सिस्टम के माध्यम से गुजरता है। यह तब शुरू होता है जब एक API कॉल आती है और तब समाप्त होता है जब आप प्रतिक्रिया भेजते हैं।
एक ट्रेस के अंदर स्पैन होते हैं। एक स्पैन एक टाइम किए हुए कदम को दर्शाता है, जैसे “request पार्स करना”, “SQL चलाना” या “payment provider को कॉल करना।” स्पैन में उपयोगी विवरण भी हो सकते हैं, जैसे HTTP स्टेटस कोड, एक सुरक्षित user पहचानकर्ता, या किसी क्वेरी ने कितनी पंक्तियाँ रिटर्न कीं।
“End-to-end” का मतलब है कि ट्रेस आपके पहले हैंडलर पर आरंभ होकर वहीं नहीं रुकता। यह रिक्वेस्ट का पालन करता है उन जगहों तक जहाँ सामान्यत: समस्याएँ छिपती हैं: middleware, डेटाबेस क्वेरीज़, cache कॉल्स, बैकग्राउंड जॉब्स, थर्ड-पार्टी APIs (payments, email, maps), और अन्य इंटरनल सर्विसेज़।
ट्रेसिंग सबसे ज़्यादा तब उपयोगी होता है जब समस्याएँ अनियमित हों। अगर 200 रिक्वेस्ट में से 1 धीमी है, तो लॉग अक्सर तेज और धीमी केस के लिए समान दिखते हैं। एक ट्रेस फर्क को स्पष्ट कर देता है: एक रिक्वेस्ट ने बाहरी कॉल की प्रतीक्षा में 800 ms बिताया, दो बार retry किया गया, और फिर एक follow-up जॉब शुरू किया गया।
लॉग्स को भी सर्विसेज़ के across जोड़ना मुश्किल होता है। आपके पास API में एक लॉग लाइन हो सकती है, वर्कर में दूसरी, और बीच में कुछ नहीं। ट्रेसिंग के साथ ये इवेंट्स एक ही trace ID साझा करते हैं, इसलिए आप चेन का पालन बिना अनुमान लगाए कर सकते हैं।
ट्रेस, मैट्रिक्स और लॉग्स: ये कैसे मेल खाते हैं
ट्रेस, मैट्रिक्स, और लॉग्स अलग सवालों के जवाब देते हैं।
ट्रेस दिखाते हैं कि एक वास्तविक रिक्वेस्ट के लिए क्या हुआ। वे बताते हैं कि आपके हैंडलर, डेटाबेस कॉल्स, कैश लुकअप और थर्ड-पार्टी रिक्वेस्ट्स में समय कहाँ गया।
मैट्रिक्स रुझान दिखाते हैं। वे अलर्ट के लिए सबसे अच्छे होते हैं क्योंकि इन्हें एग्रीगेट करना सस्ता और स्थिर है: लेटेंसी पर्सेंटाइल्स, रिक्वेस्ट रेट, एरर रेट, queue depth, और saturation।
लॉग्स सादा टेक्स्ट में “क्यों” बताते हैं: validation failures, अनपेक्षित इनपुट, एज केस, और आपके कोड ने कौन से निर्णय किए।
असली जीत सहसंबोधन (correlation) है। जब वही trace ID स्पैन्स और स्ट्रक्चर्ड लॉग्स दोनों में दिखे, तो आप एक एरर लॉग से सीधे उस सही ट्रेस पर जा सकते हैं और तुरंत देख सकते हैं कि कौन सा डिपेंडेंसी धीमा था या किस स्टेप में फेलियर हुआ।
एक सरल मानसिक मॉडल
हर सिग्नल का उपयोग उसके सबसे अच्छे उद्देश्य के लिए करें:
- मैट्रिक्स बताती हैं कि कुछ गड़बड़ है।
- ट्रेसेस दिखाते हैं कि एक रिक्वेस्ट में समय कहाँ गया।
- लॉग्स समझाते हैं कि आपके कोड ने क्या फैसला किया और क्यों।
उदाहरण: आपका POST /checkout एंडपॉइंट टाइमआउट होने लगता है। मैट्रिक्स p95 लेटेंसी में उछाल दिखाती हैं। एक ट्रेस दिखाता है कि अधिकतर समय payment provider कॉल में गया। उस स्पैन के अंदर correlated लॉग लाइन retries और 502 बताती है, जो बैकऑफ़ सेटिंग्स या अपस्ट्रीम incident की ओर इशारा करती है।
कोड जोड़ने से पहले: नामकरण, सैंपलिंग, और क्या ट्रैक करना है
थोड़ी सी प्लानिंग आगे चलकर ट्रेसेस को searchable बनाती है। इसके बिना, आप डेटा इकट्ठा करेंगे, पर बुनियादी सवाल मुश्किल हो जाते हैं: “क्या यह staging है या prod?” “किस सर्विस ने समस्या शुरू की?”
पहले एक सुसंगत पहचान से शुरू करें। हर Go API के लिए एक स्पष्ट service.name चुनें (उदाहरण के लिए, checkout-api) और एक सिंगल environment फील्ड जैसे deployment.environment=dev|staging|prod रखें। इन्हें स्थिर रखें। अगर नाम बीच में बदलते हैं, तो चार्ट्स और सर्च अलग सिस्टम जैसी दिखेंगी।
अगला, सैंपलिंग का निर्णय लें। डेवलपमेंट में हर रिक्वेस्ट ट्रेस करना बढ़िया है, लेकिन प्रोडक्शन में अक्सर महंगा होता है। एक सामान्य तरीका यह है कि सामान्य ट्रैफ़िक का एक छोटा प्रतिशत सैंपल करें और एरर्स और धीमी रिक्वेस्ट्स के ट्रेसेस हमेशा रखें। अगर आप पहले से जानते हैं कि कुछ एंडपॉइंट्स हाई वॉल्यूम हैं (health checks, polling), तो उन्हें कम या बिल्कुल न ट्रेस करें।
अंत में, तय करें कि आप स्पैन्स पर क्या टैग करेंगे और क्या कभी भी कलेक्ट नहीं करेंगे। एक छोटा allowlist रखें उन attributes का जो सर्विसेज़ के across इवेंट्स को जोड़ने में मदद करें, और सरल प्राइवेसी नियम लिखें।
अच्छे टैग्स में आमतौर पर स्थिर IDs और रूढ़ मार्ग संबंधी जानकारी होती है (route template, method, status code)। संवेदनशील payloads को पूरी तरह से टालें: पासवर्ड, पेमेंट डेटा, पूरा ईमेल, auth टोकन, और raw request बोडी। अगर आपको यूज़र-संबंधी मान शामिल करना ही हो, तो उन्हें जोड़ने से पहले hash या redact करें।
चरण-दर-चरण: एक Go HTTP API में OpenTelemetry ट्रेसिंग जोड़ना
स्टार्टअप पर आप एक tracer provider सेट करेंगे। यह तय करता है कि स्पैन्स कहाँ जाते हैं और कौन से resource attributes हर स्पैन के साथ जुड़ेंगे।
1) OpenTelemetry इनिशियलाइज़ करें
सुनिश्चित करें कि आप service.name सेट करें। इसके बिना, अलग सर्विसेज़ के ट्रेसेस एक साथ मिल सकते हैं और चार्ट्स पढ़ना मुश्किल हो जाता है।
// main.go (startup)
exp, _ := stdouttrace.New(stdouttrace.WithPrettyPrint())
res, _ := resource.New(context.Background(),
resource.WithAttributes(
semconv.ServiceName("checkout-api"),
),
)
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exp),
sdktrace.WithResource(res),
)
otel.SetTracerProvider(tp)
यह Go OpenTelemetry ट्रेसिंग की नींव है। अगला कदम हर इनकमिंग रिक्वेस्ट के लिए एक स्पैन बनाना है।
2) HTTP मिडलवेयर जोड़ें और मुख्य फ़ील्ड कैप्चर करें
ऐसा HTTP मिडलवेयर उपयोग करें जो स्वचालित रूप से एक स्पैन शुरू कर दे और status code व duration रिकॉर्ड करे। स्पैन का नाम route template (जैसे /users/:id) रखिए, न कि कच्चा URL, वरना आपके पास हजारों यूनिक पाथ्स हो जाएंगे।
एक साफ बेसलाइन के लिए लक्ष्य रखें: प्रति रिक्वेस्ट एक server स्पैन, route-based स्पैन नाम, HTTP स्टेटस कैप्चर किया गया, हैंडलर फेलियर स्पैन एरर के रूप में दिखे, और duration आपके ट्रेस व्यूअर में दिखाई दे।
3) फेलियर स्पष्ट करें
जब कुछ गड़बड़ हो, तो एरर लौटाएँ और वर्तमान स्पैन को failed मार्क करें। इससे ट्रेस पहले ही नज़र में अलग दिखने लगता है।
हैंडलर्स में आप कर सकते हैं:
span := trace.SpanFromContext(r.Context())
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
4) लोकली trace IDs सत्यापित करें
API चलाएँ और किसी एंडपॉइंट को हिट करें। अनुरोध context से trace ID लॉग करके पुष्टि करें कि यह प्रति रिक्वेस्ट बदलता है। अगर यह हमेशा खाली है, तो आपका मिडलवेयर आपके हैंडलर के मिलने वाले context का उपयोग नहीं कर रहा।
DB और थर्ड-पार्टी कॉल्स में context कैरी करें
End-to-end विज़िबिलिटी टूट जाती है जब आप context.Context खो देते हैं। इनकमिंग रिक्वेस्ट का context वह धागा होना चाहिए जिसे आप हर DB कॉल, HTTP कॉल और हेल्पर में पास करें। अगर आप इसे context.Background() से बदल देते हैं या पास करना भूल जाते हैं, तो आपका ट्रेस अलग-अलग, असंबंधित काम बन जाता है।
आउटगोइंग HTTP के लिए, एक इंस्ट्रूमेंटेड ट्रांसपोर्ट उपयोग करें ताकि हर Do(req) वर्तमान रिक्वेस्ट का एक चाइल्ड स्पैन बन जाए। आउटबाउंड रिक्वेस्ट्स पर W3C trace हेडर्स फॉरवर्ड करें ताकि डाउनस्ट्रीम सर्विसेज़ उसी ट्रेस से जुड़ सकें।
डेटाबेस कॉल्स के लिए भी यही व्यवहार करें। एक इंस्ट्रूमेंटेड ड्राइवर का उपयोग करें या QueryContext और ExecContext के चारों ओर स्पैन रैप करें। केवल सुरक्षित विवरण रिकॉर्ड करें। आप धीमी क्वेरीज़ खोजना चाहते हैं बिना डेटा लीक किए।
उपयोगी, कम-जोखिम वाले attributes में एक ऑपरेशन नाम शामिल है (उदाहरण के लिए, SELECT user_by_id), टेबल या मॉडल का नाम, रो काउंट (सिर्फ गिनती), अवधि, retry काउंट, और एक मोटा एरर प्रकार (timeout, canceled, constraint)।
टाइमआउट्स कहानी का हिस्सा हैं, सिर्फ फेलियर नहीं। DB और थर्ड-पार्टी कॉल्स के लिए context.WithTimeout सेट करें, और cancellations को ऊपर तक आने दें। जब कॉल cancel हो, स्पैन को error के रूप में मार्क करें और एक छोटा कारण जोड़ें जैसे deadline_exceeded।
बैकग्राउंड जॉब्स और 큐ज़ का ट्रेसिंग
बैकग्राउंड वर्क वह जगह है जहाँ अक्सर ट्रेसेस रुक जाती हैं। एक HTTP रिक्वेस्ट समाप्त होती है, फिर वर्कर बाद में किसी अलग मशीन पर एक संदेश उठाता है बिना साझा context के। अगर आपने कुछ नहीं किया, तो आपको दो कहानियाँ मिलती हैं: API ट्रेस और एक जॉब ट्रेस जो अचानक कहीं से शुरू हुआ दिखता है।
फिक्स सीधा है: जब आप जॉब enqueue करते हैं, तो वर्तमान ट्रेस context कैप्चर करें और उसे जॉब मेटाडेटा (payload, headers, या attributes, आपकी 큐 पर निर्भर करते हुए) में स्टोर करें। जब वर्कर शुरू हो, उस context को एक्सट्रैक्ट करें और एक नया स्पैन मूल रिक्वेस्ट का चाइल्ड बनाकर शुरू करें।
context सुरक्षित रूप से propagate करें
केवल ट्रेस context कॉपी करें, यूज़र डेटा नहीं।
- केवल ट्रेस identifiers और सैंपलिंग फ्लैग्स inject करें (W3C traceparent स्टाइल)।
- इसे बिज़नेस फील्ड्स से अलग रखें (उदाहरण के लिए, एक समर्पित "otel" या "trace" फील्ड)।
- इसे पढ़ते समय अनट्रस्टेड इनपुट की तरह ट्रीट करें (फॉर्मेट वेलिडेट करें, मिसिंग डेटा संभालें)।
- जॉब मेटाडेटा में टोकन्स, ईमेल्स, या रिक्वेस्ट बॉडी न रखें।
जिन स्पैन्स को जोड़ना चाहिए (बिना ट्रेसेस को शोर में बदलने)
पठनीय ट्रेसेस आमतौर पर कुछ अर्थपूर्ण स्पैन्स होते हैं, दर्जनों छोटे स्पैन्स नहीं। सीमा और “wait points” के चारों ओर स्पैन्स बनाएँ। एक अच्छा शुरुआती बिंदु है API हैंडलर में एक enqueue स्पैन और वर्कर में एक job.run स्पैन।
थोड़ा सा संदर्भ जोड़ें: प्रयास संख्या, queue नाम, जॉब प्रकार, और payload का आकार (न कि payload कंटेंट)। अगर retries होते हैं, तो उन्हें अलग स्पैन्स या इवेंट्स के रूप में रिकॉर्ड करें ताकि आप बैकऑफ़ देरी देख सकें।
शेड्यूल किए गए टास्क्स का भी एक पैरेंट होना चाहिए। अगर कोई इनकमिंग रिक्वेस्ट नहीं है, तो प्रत्येक रन के लिए एक नया root स्पैन बनाएं और उसे schedule नाम के साथ टैग करें।
लॉग्स को ट्रेसेस के साथ सहसंबद्ध करना (और लॉग्स को सुरक्षित रखना)
ट्रेसेस बताते हैं कि समय कहाँ गया। लॉग्स बताते हैं कि क्या हुआ और क्यों। उन्हें जोड़ने का सबसे सरल तरीका है हर लॉग एंट्री में trace_id और span_id को स्ट्रक्चर्ड फील्ड्स के रूप में जोड़ना।
Go में, context.Context से सक्रिय स्पैन लें और अपने लॉगर को हर रिक्वेस्ट (या जॉब) के लिए एक बार enrich करें। फिर हर लॉग लाइन एक विशिष्ट ट्रेस की ओर इशारा करेगी।
span := trace.SpanFromContext(ctx)
sc := span.SpanContext()
logger := baseLogger.With(
"trace_id", sc.TraceID().String(),
"span_id", sc.SpanID().String(),
)
logger.Info("charge_started", "order_id", orderID)
इतना ही काफी है एक लॉग एंट्री से उस सटीक स्पैन पर कूदने के लिए जो उस समय चल रहा था। यह गायब context को भी स्पष्ट कर देता है: trace_id खाली होगा।
PII लीक किए बिना लॉग्स उपयोगी रखें
लॉग्स अक्सर लंबे समय तक रहते और अधिक जगहों पर जाते हैं, इसलिए इन पर और भी सख्ती बरतें। स्थिर identifiers और परिणाम पसंद करें: user_id, order_id, payment_provider, status, और error_code। अगर आपको यूज़र इनपुट लॉग करना ही है, तो पहले उसे redact करें और लंबाई सीमित करें।
एरर्स को ग्रुप करना आसान बनाएं
संगत इवेंट नाम और एरर प्रकार उपयोग करें ताकि आप उन्हें count और search कर सकें। अगर वर्डिंग हर बार बदलती रहती है, तो वही समस्या कई अलग-अलग मुद्दों की तरह दिखेगी।
ऐसे मैट्रिक्स जोड़ें जो वाकई मदद करें
मैट्रिक्स आपकी शुरुआती चेतावनी प्रणाली हैं। एक सेटअप में जो पहले से Go OpenTelemetry ट्रेसिंग का उपयोग करता है, मैट्रिक्स को जवाब देना चाहिए: कितनी बार, कितना बुरा, और कब से।
हर API के लिए एक छोटा सेट शुरू करें जो लगभग हर जगह काम करता है: request count, error count (status class के हिसाब से), latency percentiles (p50, p95, p99), in-flight requests, और आपकी DB व मुख्य थर्ड-पार्टी कॉल्स के लिए dependency latency।
ट्रेस के साथ मैट्रिक्स को संरेखित रखने के लिए वही route templates और नाम उपयोग करें। अगर आपके स्पैन्स /users/{id} उपयोग करते हैं, तो आपके मैट्रिक्स को भी ऐसा ही होना चाहिए। तब जब कोई चार्ट दिखाए “p95 for /checkout jumped,” आप सीधे उस रूट के फ़िल्टर किए हुए ट्रेसेस में जा सकते हैं।
लेबल्स (attributes) के साथ सावधान रहें। एक खराब लेबल लागत बढ़ा सकता है और डैशबोर्ड्स बेकार कर सकता है। Route template, method, status class, और service name आमतौर पर सुरक्षित होते हैं। User IDs, ईमेल्स, पूर्ण URLs, और कच्चे एरर मैसेज आमतौर पर नहीं होते।
कुछ बिज़नेस-क्रिटिकल कस्टम मैट्रिक्स जोड़ें (उदाहरण के लिए, checkout started/completed, payment failures by result code group, background job success vs retry)। सेट छोटा रखें और जो उपयोग नहीं हो रहे उन्हें निकाल दें।
टेलीमेट्री एक्सपोर्ट करना और सुरक्षित रोलआउट
एक्सपोर्टिंग वह जगह है जहाँ OpenTelemetry असली बनता है। आपकी सर्विस को स्पैन्स, मैट्रिक्स, और लॉग्स कहीं भरोसेमंद जगह भेजने होंगे बिना रिक्वेस्ट्स को धीमा किए।
लोकल डेवलपमेंट के लिए, इसे सिंपल रखें। एक console exporter (या OTLP को लोकल कलेक्टर) आपको तेजी से ट्रेसेस देखने और स्पैन नाम व attributes वैलिडेट करने देता है। प्रोडक्शन में OTLP को एक एजेंट या OpenTelemetry Collector के पास भेजना बेहतर है। यह आपको retries, routing, और filtering का एक केंद्रीकृत स्थान देता है।
बैचिंग मायने रखता है। telemetry को छोटे इंटरवल पर बैच में भेजें, साथ में तंग timeouts ताकि फंसा हुआ नेटवर्क आपके ऐप को ब्लॉक न करे। टेलीमेट्री क्रिटिकल पाथ पर नहीं होनी चाहिए। अगर एक्सपोर्टर पीछे छूट रहा है, तो वह डेटा ड्रॉप करे बजाय मेमोरी में जमा करने के।
सैंपलिंग लागतों को पूर्वानुमानित बनाती है। head-based सैंपलिंग से शुरू करें (उदाहरण के लिए, 1-10% रिक्वेस्ट्स), फिर साधारण नियम जोड़ें: हमेशा एरर्स सैंपल करें, और हमेशा उन रिक्वेस्ट्स को सैंपल करें जो किसी थ्रेशोल्ड से ऊपर धीमें हैं। अगर आपके हाई-वॉल्यूम बैकग्राउंड जॉब्स हैं, तो उन्हें कम दर पर सैंपल करें।
छोटे कदमों में रोलआउट करें: dev में 100% सैंपलिंग, staging में यथार्थवादी ट्रैफ़िक और कम सैंपलिंग, फिर प्रोडक्शन में सतर्क सैंपलिंग और एक्सपोर्टर फेलियर्स पर अलर्ट।
सामान्य गलतियाँ जो end-to-end विज़िबिलिटी बर्बाद कर देती हैं
End-to-end विज़िबिलिटी अक्सर सरल कारणों से फेल होती है: डेटा मौजूद होता है, पर वह कनेक्ट नहीं होता।
Go में वितरित ट्रेसिंग को तोड़ने वाले सामान्य मुद्दे हैं:
- लेयर्स के बीच context ड्रॉप होना। एक हैंडलर स्पैन बनाता है, पर DB कॉल, HTTP क्लाइंट, या goroutine
context.Background()का उपयोग करते हैं बजाय रिक्वेस्ट context के। - एरर लौटाने पर स्पैन्स को मार्क न करना। अगर आप एरर रिकॉर्ड नहीं करते और स्पैन स्टेटस सेट नहीं करते, तो ट्रेसेस “ग्रीन” दिखेंगे भले ही यूज़र्स 500 देख रहे हों।
- हर चीज़ का इंस्ट्रूमेंटेशन। अगर हर हेल्पर एक स्पैन बन जाता है तो ट्रेसेस शोर में बदल जाते हैं और लागत बढ़ती है।
- हाई-कार्डिनैलिटी attributes जोड़ना। IDs वाले पूरे URLs, ईमेल्स, raw SQL मान, request बॉडीज़, या कच्चे एरर स्ट्रिंग्स लाखों यूनिक वैल्यूज़ बना सकते हैं।
- प्रदर्शन का आकलन औसत से करना। Incidents पर्सेंटाइल्स (p95/p99) और एरर रेट में दिखते हैं, न कि mean latency में।
एक शीघ्र सेन्हिटी चेक यह है कि एक रियल रिक्वेस्ट चुनें और उसे सीमाओं के across फॉलो करें। अगर आप एक ट्रेस ID नहीं देख पा रहे जो इनबाउंड रिक्वेस्ट, DB क्वेरी, थर्ड-पार्टी कॉल, और असिंक वर्कर में बहती हो, तो आपके पास end-to-end विज़िबिलिटी अभी नहीं है।
व्यावहारिक “हो चुका” चेकलिस्ट
आप तब करीब हैं जब आप एक यूज़र रिपोर्ट से शुरू करके उसी सटीक रिक्वेस्ट तक जा सकें, और फिर उसे हर हॉप पर फॉलो कर सकें।
- एक API लॉग लाइन चुनें और
trace_idके द्वारा सही ट्रेस ढूँढें। पुष्टि करें कि उसी रिक्वेस्ट के डीप लॉग्स (DB, HTTP क्लाइंट, वर्कर) में वही trace context है। - ट्रेस खोलें और नेस्टिंग सत्यापित करें: ऊपर एक HTTP सर्वर स्पैन हो, और उसके चाइल्ड स्पैन्स DB कॉल्स और थर्ड-पार्टी APIs के लिए हो। एक फ्लैट सूची अक्सर context खो जाने का मतलब है।
- एक API रिक्वेस्ट से बैकग्राउंड जॉब ट्रिगर करें (जैसे ईमेल रसीद भेजना) और पुष्टि करें कि वर्कर स्पैन रिक्वेस्ट से कनेक्ट होता है।
- बेसिक्स के लिए मैट्रिक्स चेक करें: request count, error rate, और latency percentiles। पुष्टि करें कि आप route या operation से फ़िल्टर कर सकते हैं।
- attributes और लॉग्स की सुरक्षा स्कैन करें: कोई पासवर्ड्स, टोकन्स, पूरा क्रेडिट कार्ड नंबर, या कच्चे पर्सनल डेटा नहीं होना चाहिए।
एक सरल रियलिटी टेस्ट यह है कि एक धीमा चेकआउट सिमुलेट करें जहाँ payment provider देरी कर रहा है। आपको एक ट्रेस दिखाई देना चाहिए जिस में स्पष्ट रूप से लेबल्ड external call स्पैन हो, साथ ही चेकआउट रूट के लिए p95 लेटेंसी में मैट्रिक स्पाइक भी दिखना चाहिए।
यदि आप Go बैकएंड्स जनरेट कर रहे हैं (उदाहरण के लिए AppMaster के साथ), तो यह मददगार होता है कि इस चेकलिस्ट को आपकी रिलीज़ रूटीन का हिस्सा बनाएं ताकि नए एंडपॉइंट्स और वर्कर्स एप बढ़ने पर भी ट्रेस योग्य रहें। AppMaster वास्तविक Go सर्विसेज़ जेनरेट करता है, इसलिए आप एक OpenTelemetry सेटअप को स्टैंडर्डाइज़ कर सकते हैं और इसे सर्विसेज़ और बैकग्राउंड जॉब्स में एक साथ ले जा सकते हैं।
उदाहरण: सर्विसेज़ के across एक धीमे चेकआउट को डिबग करना
एक ग्राहक मैसेज कहता है: “चेकआउट कभी-कभी हैंग होता है।” आप इसे मांग पर reproduce नहीं कर पा रहे हैं, और यही वह स्थिति है जहाँ Go OpenTelemetry ट्रेसिंग काम आती है।
शुरू करें मैट्रिक्स से ताकि समस्या की आकृति समझ में आये। चेकआउट एंडपॉइंट के लिए request rate, error rate, और p95 या p99 लेटेंसी देखें। अगर slowdown छोटे bursts में और केवल कुछ रिक्वेस्ट्स के लिए होता है, तो अक्सर यह किसी डिपेंडेंसी, क्यूइंग, या retry व्यवहार की ओर इशारा करता है बजाए CPU के।
फिर उसी टाइम विंडो का एक slow ट्रेस खोलें। अक्सर एक ट्रेस ही काफी होता है। एक स्वस्थ चेकआउट 300-600 ms एंड-टू-एंड हो सकता है। एक खराब एक 8-12 सेकंड का हो सकता है, जिसमें अधिकतर समय एक ही स्पैन के भीतर हो।
एक सामान्य पैटर्न ऐसा दिखता है: API हैंडलर तेज है, DB वर्क ज्यादातर ठीक है, फिर payment provider स्पैन retries और बैकऑफ़ दिखाता है, और डाउनस्ट्रीम कॉल किसी लॉक या क्यू के पीछे इंतज़ार कर रहा है। प्रतिक्रिया 200 भी लौट सकती है, इसलिए केवल एरर पर आधारित अलर्ट कभी नहीं चलेंगे।
फिर correlated लॉग्स बताते हैं कि सटीक रास्ता क्या था: “retrying Stripe charge: timeout,” उसके बाद “db tx aborted: serialization failure,” और फिर “retry checkout flow।” यह स्पष्ट संकेत है कि कुछ छोटे मुद्दे एक साथ मिलकर खराब यूज़र अनुभव बना रहे हैं।
बॉटलनेक मिलने के बाद, स्थिरता ही चीज़ है जो चीज़ों को पढ़ने योग्य बनाए रखती है। स्पैन नाम, attributes (सुरक्षित user ID hash, order ID, dependency name), और सैंपलिंग नियमों को सर्विसेज़ में स्टैंडर्डाइज़ करें ताकि सब लोग एक ही तरह से ट्रेसेस पढ़ें।


