Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रूबी एक्सेप्शन में TracePoint के साथ महारत हासिल करें: जटिल एरर परिदृश्यों का निदान करें

कभी-कभी यह समझना वास्तव में मुश्किल हो सकता है कि एक्सेप्शन के साथ क्या हो रहा है - विशेष रूप से बड़े ऐप्स में। कल्पना करें कि आप किसी मौजूदा प्रोजेक्ट के अंदर कुछ कोड पर काम कर रहे हैं। आप एक एक्सेप्शन उठाते हैं, फिर कुछ अजीब होता है। शायद एक्सेप्शन निगल लिया जाता है। शायद एक एनवायरनमेंट वेरिएबल बदल जाता है। शायद आपका एक्सेप्शन दूसरे एक्सेप्शन में लपेट दिया जाता है।

मैं आपको TracePoints का उपयोग करके अपने ऐप में एक्सेप्शन के बारे में थोड़ी अधिक जानकारी प्राप्त करने का एक सरल तरीका दिखाने जा रहा हूँ - भले ही उन एक्सेप्शन को निगल लिया गया हो।

एक सुविधाजनक उदाहरण

रेल्स में कंट्रोलर और व्यू के बीच की सीमा एक ऐसा स्थान है जहां एक्सेप्शन तर्क को धता बताते प्रतीत होते हैं। इसे स्वयं देखना आसान है। बस एक व्यू में एक एक्सेप्शन उठाएं और कंट्रोलर में इसे रेस्क्यू करने का प्रयास करें। आप पाएंगे कि आप कंट्रोलर से टेम्पलेट एरर को रेस्क्यू नहीं कर सकते!

# pages_controller.rb def index render rescue # this will never run logger.debug "someone raised the roof" end 
# index.haml - raise "the roof" 

रूबी एक्सेप्शन में TracePoint के साथ महारत हासिल करें: जटिल एरर परिदृश्यों का निदान करें WTF!?! मुझे लगा कि मैंने इसे रेस्क्यू कर लिया!

यह स्पष्ट है कि कुछ मुश्किल चल रहा है। आइए देखें कि क्या हम यह पता लगा सकते हैं कि यह क्या है।

TracePoint के साथ सभी एक्सेप्शन लॉग करना

TracePoints एक बहुत शक्तिशाली इंट्रोस्पेक्शन टूल हैं जो रूबी 2.0 से मौजूद हैं। वे आपको रनटाइम इवेंट की एक विस्तृत विविधता के लिए कॉलबैक परिभाषित करने की अनुमति देते हैं। उदाहरण के लिए, आपको जब भी कोई क्लास परिभाषित की जाती है, जब भी कोई मेथड कॉल किया जाता है, या जब भी कोई एक्सेप्शन उठाया जाता है, तो सूचित किया जा सकता है। और भी अधिक इवेंट के लिए TracePoint दस्तावेज़ देखें।

आइए एक TracePoint जोड़कर शुरू करें जिसे हर बार एक्सेप्शन उठाए जाने पर कॉल किया जाता है और उसका सारांश लॉग में लिखता है।

class PagesController < ApplicationController def index TracePoint.new(:raise) do |tp| # tp.raised_exeption contains the actual exception object that was raised! logger.debug "#{tp.raised_exception.object_id}: #{tp.raised_exception.class} #{tp.raised_exception.message} ".yellow + tp.raised_exception.backtrace[0].sub(Rails.root.to_s, "").blue end.enable do render end end end 

यदि आप yellow और blue मेथड के बारे में उत्सुक हैं, तो मैं colorize जेम का उपयोग कर रहा हूँ। यह आउटपुट में ANSI कलर कोड जोड़ता है।

अब जब मैं जाकर अपना पेज रीफ्रेश करता हूँ, तो मेरे लॉग नीचे स्क्रीनशॉट की तरह दिखते हैं। एक दिलचस्प बात जो आप देख सकते हैं वह यह है कि दो अलग-अलग एक्सेप्शन हैं, और उनमें से प्रत्येक को दो बार उठाया गया है। प्रत्येक पंक्ति की शुरुआत में वह लंबी संख्या एक्सेप्शन की ऑब्जेक्ट आईडी है। इसी तरह हम जानते हैं कि चार नहीं, बल्कि दो एक्सेप्शन ऑब्जेक्ट हैं।

रूबी एक्सेप्शन में TracePoint के साथ महारत हासिल करें: जटिल एरर परिदृश्यों का निदान करें यह लॉग रेंडरिंग प्रक्रिया में raise के हर उपयोग को दिखाता है

किस मेथड ने कौन सा raise कारण बनाया?

"raise" इवेंट की एक सूची होना काफी उपयोगी है। लेकिन यह और भी बेहतर होगा अगर हमें कुछ अंदाजा हो कि कौन से मेथड प्रत्येक raise का कारण बने। एक बार फिर, TracePoint बचाव के लिए आता है।

TracePoint हमें एक हैंडलर जोड़ने देता है जिसे हर बार मेथड रिटर्न होने पर कॉल किया जाता है। यह "raise" इवेंट जितना ही सरल है। नीचे दिए गए उदाहरण में हम हर मेथड रिटर्न को लॉग कर रहे हैं:

TracePoint.trace(:return) do |tp| logger.debug [tp.method_id, tp.lineno, tp.path.sub(Rails.root.to_s, "")].join(" : ").green end 

एक समस्या है हालांकि। यदि आप इस कोड को अपने रेल्स ऐप में जोड़ते हैं, तो आप पाएंगे कि आपका ऐप अनुरोधों का जवाब देना बंद कर देता है। सबसे सरल रेल्स अनुरोध में इतने सारे मेथड कॉल होते हैं कि सर्वर उन सभी को लॉग में लिखने से पहले टाइम आउट हो जाता है।

चूंकि हम वास्तव में केवल उन मेथड कॉल में रुचि रखते हैं जिनके कारण एक्सेप्शन हुए, आइए अपने कोड को संशोधित करें ताकि प्रत्येक एक्सेप्शन के बाद पहले दो "रिटर्न" इवेंट आउटपुट हों।

class PagesController < ApplicationController def index counter = 0 return_trace = TracePoint.trace(:return) do |tp| logger.debug "\t" + [tp.method_id, tp.lineno, tp.path.sub(Rails.root.to_s, "")].join(" : ").green if (counter += 1) > 3 return_trace.disable counter = 0 end end return_trace.disable # disable the tracepoint by default TracePoint.new(:raise) do |tp| logger.debug "#{tp.raised_exception.object_id}: #{tp.raised_exception.class} #{tp.raised_exception.message} ".yellow + tp.raised_exception.backtrace[0].sub(Rails.root.to_s, "").blue # The "raise" enables the "return" tracepoint return_trace.enable end.enable do render end end end 

जब मैं अपना ब्राउज़र रीफ्रेश करता हूँ, तो मुझे लॉग में निम्नलिखित पंक्तियाँ जुड़ी हुई दिखाई देती हैं:

रूबी एक्सेप्शन में TracePoint के साथ महारत हासिल करें: जटिल एरर परिदृश्यों का निदान करें प्रत्येक "raise" इवेंट को उसके कारण बने मेथड के ऊपर दिखाया गया है

क्योंकि हम "रिटर्न" TracePoint को केवल तभी सक्षम करते हैं जब कोई एक्सेप्शन उठाया जाता है, पहला "रिटर्न" इवेंट उस मेथड से होने वाला है जिसने एक्सेप्शन उठाया।

हम इस जानकारी का उपयोग अपने रहस्य को सुलझाने के लिए कर सकते हैं। हमारा मूल RuntimeError handle_render_error मेथड द्वारा template.rb की लाइन 310 पर ActionView::Template::Error में परिवर्तित किया जा रहा है।

इस तकनीक के बारे में अच्छी बात यह है कि इसका रेल्स से कोई लेना-देना नहीं है। आप इसका उपयोग किसी भी समय कर सकते हैं जब आपको अधिक विस्तार से समझने की आवश्यकता हो कि हुड के तहत कौन से एक्सेप्शन उठाए और पकड़े जा रहे हैं।


  1. Ruby में Lambdas में महारत हासिल करें: बुनियादी से उन्नत तकनीकें तक Ruby में Lambdas में महारत हासिल करें: बुनियादी से उन्नत तकनीकें तक

    ब्लॉक Ruby का इतना महत्वपूर्ण हिस्सा हैं, उनके बिना भाषा की कल्पना करना कठिन है। लेकिन लैम्ब्डा? कौन लैम्ब्डा से प्यार करता है? आप वर्षों तक बिना एक का उपयोग किए जा सकते हैं। वे लगभग एक बीते युग के अवशेष लगते हैं। ...लेकिन यह पूरी तरह सच नहीं है। लैम्ब्डा की आस्तीन में कुछ दिलचस्प तरकीबें हैं एक बार

  1. - Ruby के अपवाद पदानुक्रम में महारत हासिल करें: एक व्यापक गाइड

    Ruby में अपवाद केवल क्लास हैं। अपवाद पदानुक्रम उन सभी क्लासेस से बना है जो Exception से इनहेरिट करती हैं। यहाँ Ruby 2.1 की मानक लाइब्रेरी के लिए अपवाद पदानुक्रम है। Exception NoMemoryError ScriptError LoadError NotImplementedError SyntaxError SecurityError SignalException Interrupt StandardError --

  1. Ruby में कस्टम अपवाद में महारत हासिल करें: एक चरण-दर-चरण गाइड Ruby में कस्टम अपवाद में महारत हासिल करें: एक चरण-दर-चरण गाइड

    Ruby में अपने स्वयं के अपवाद बनाना आसान है। बस इन चरणों का पालन करें: 1. एक नई क्लास बनाएं अपवाद क्लास हैं, Ruby में बाकी सब की तरह! एक नए प्रकार का अपवाद बनाने के लिए, बस एक क्लास बनाएं जो StandardError, या उसके बच्चों में से एक से इनहेरिट करती है। class MyError < StandardError end raise MyError