कभी-कभी यह समझना वास्तव में कठिन हो सकता है कि अपवादों के साथ क्या हो रहा है - विशेष रूप से बड़े ऐप्स में। कल्पना कीजिए कि आप किसी मौजूदा प्रोजेक्ट के अंदर किसी कोड पर काम कर रहे हैं। आप अपवाद उठाते हैं, फिर कुछ अजीब होता है। शायद अपवाद निगल लिया गया है। शायद एक पर्यावरण चर बदल गया है। हो सकता है कि आपका अपवाद किसी अन्य अपवाद में लिपटा हो।
मैं आपको आपके ऐप में अपवादों के बारे में थोड़ी अधिक जानकारी प्राप्त करने के लिए TracePoints का उपयोग करने का एक आसान तरीका दिखाने जा रहा हूं - भले ही वे अपवाद निगल लिए गए हों।
एक सुविधाजनक उदाहरण
रेल में नियंत्रकों और विचारों के बीच की सीमा एक ऐसा स्थान है जहां अपवाद तर्क को धता बताते हैं। अपने लिए देखना आसान है। बस एक दृश्य में अपवाद उठाएं और इसे नियंत्रक में बचाने का प्रयास करें। आप पाएंगे कि आप नियंत्रक से टेम्पलेट त्रुटि को नहीं बचा सकते!
# pages_controller.rb
def index
render
rescue
# this will never run
logger.debug "someone raised the roof"
end
# index.haml
- raise "the roof"
डब्ल्यूटीएफ!?! मुझे लगा कि मैंने इसे बचा लिया!
यह स्पष्ट है कि कुछ मुश्किल हो रहा है। आइए देखें कि क्या हम यह पता लगा सकते हैं कि यह क्या है।
ट्रेसपॉइंट के साथ सभी अपवादों को लॉग करना
TracePoints वास्तव में एक शक्तिशाली आत्मनिरीक्षण उपकरण है जो रूबी 2.0 के बाद से मौजूद है। वे आपको विभिन्न प्रकार के रनटाइम ईवेंट के लिए कॉलबैक परिभाषित करने की अनुमति देते हैं। उदाहरण के लिए, जब भी किसी वर्ग को परिभाषित किया जाता है, जब भी कोई विधि कहा जाता है या जब भी कोई अपवाद उठाया जाता है, तो आपको सूचित किया जा सकता है। और भी अधिक घटनाओं के लिए 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
विधियाँ, मैं रंगीन रत्न का उपयोग कर रहा हूँ। यह आउटपुट में एएनएसआई रंग कोड जोड़ता है।
अब जब मैं जाता हूं और अपना पेज रीफ्रेश करता हूं, तो मेरे लॉग नीचे स्क्रीनशॉट की तरह दिखते हैं। एक दिलचस्प बात जो आप देख सकते हैं वह यह है कि दो अलग-अलग अपवाद हैं, और उनमें से प्रत्येक को दो बार उठाया गया है। प्रत्येक पंक्ति की शुरुआत में वह लंबी संख्या अपवाद की वस्तु आईडी है। इस तरह हम जानते हैं कि दो अपवाद वस्तुएं हैं, चार नहीं।
यह लॉग raise
के हर उपयोग को दर्शाता है प्रतिपादन प्रक्रिया में
कौन सी विधि के कारण कौन सी वृद्धि हुई?
"उठाएं" घटनाओं की सूची रखना बहुत उपयोगी है। लेकिन यह और भी बेहतर होगा अगर हमें इस बात का अंदाजा हो कि कौन से तरीके प्रत्येक वृद्धि का कारण बन रहे हैं। एक बार फिर, ट्रेसपॉइंट बचाव के लिए आता है।
ट्रेसपॉइंट हमें एक हैंडलर जोड़ने देता है जिसे जब भी कोई विधि वापस आती है तो उसे कॉल किया जाता है। इसका उपयोग करना उतना ही सरल है जितना कि "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
जब मैं अपने ब्राउज़र को रीफ़्रेश करता हूँ, तो मैं देखता हूँ कि लॉग में निम्नलिखित पंक्तियाँ जोड़ी गई हैं:
प्रत्येक "raise" ईवेंट को उस विधि के ऊपर दिखाया गया है जिसके कारण यह हुआ
चूंकि हम केवल "रिटर्न" ट्रेसपॉइंट को सक्षम करते हैं जब कोई अपवाद उठाया जाता है, तो पहला "रिटर्न" ईवेंट उस विधि से होगा जिसने अपवाद उठाया था।
हम इस जानकारी का उपयोग अपने रहस्य को सुलझाने के लिए कर सकते हैं। हमारा मूल RuntimeError
एक ActionView::Template::Error
में कनवर्ट किया जा रहा है handle_render_error
. द्वारा template.rb की लाइन 310 पर विधि।
इस तकनीक की अच्छी बात यह है कि इसका रेल से कोई लेना-देना नहीं है। आप इसे किसी भी समय उपयोग कर सकते हैं जब आपको अधिक विस्तार से समझने की आवश्यकता हो कि कौन से अपवाद उठाए जा रहे हैं और हुड के तहत पकड़े गए हैं।