मैं छंटनी के बजाय एक पूर्ण बैकट्रेस प्रिंट करने के लिए रूबी कैसे प्राप्त करूं?


170

जब मुझे अपवाद मिलते हैं, तो यह अक्सर कॉल स्टैक के भीतर गहरे से होता है। जब ऐसा होता है, तो अधिक बार नहीं, कोड की वास्तविक अपमानजनक रेखा मुझसे छिपाई जाती है:

tmp.rb:7:in `t': undefined method `bar' for nil:NilClass (NoMethodError)
        from tmp.rb:10:in `s'
        from tmp.rb:13:in `r'
        from tmp.rb:16:in `q'
        from tmp.rb:19:in `p'
        from tmp.rb:22:in `o'
        from tmp.rb:25:in `n'
        from tmp.rb:28:in `m'
        from tmp.rb:31:in `l'
         ... 8 levels...
        from tmp.rb:58:in `c'
        from tmp.rb:61:in `b'
        from tmp.rb:64:in `a'
        from tmp.rb:67

कि "... 8 स्तर ..." छंटनी मुझे बहुत परेशानी का कारण बन रही है। मुझे इस एक के लिए बहुत सफलता नहीं मिल रही है: मैं रूबी को कैसे बताऊं कि मैं डंप को पूर्ण स्टैक शामिल करना चाहता हूं?


2
क्या इसके बजाय कमांड लाइन से ऐसा करने का कोई तरीका है?
एंड्रयू ग्रिम

जवाबों:


241

अपवाद # बैकट्रेस में संपूर्ण स्टैक है:

def do_division_by_zero; 5 / 0; end
begin
  do_division_by_zero
rescue => exception
  puts exception.backtrace
  raise # always reraise
end

(पीटर कूपर की रूबी इनसाइड ब्लॉग से प्रेरित )


15
मैं अपवाद को कम करता हूं, कम से कम उदाहरणों की पूर्णता के लिए।
रीटो

13
आप को कहने के लिए सिर्फ कहने की जरूरत है raise। स्पष्ट रूप से उस निष्पादन को स्पष्ट रूप से निर्दिष्ट करने की आवश्यकता नहीं है जिसे आप उठाना चाहते हैं।
टिमो

अच्छा, मैंने हमेशा सोचा था कि आपको उठाने के लिए पिछले अपवाद को पारित करना होगा। मुझे एहसास नहीं था कि यह पिछले अपवाद को बचाया गया है।
अनफॉलो जूल

क्या होगा यदि आपका कोड अपवाद नहीं फेंकता है, तो आप बस यह देखना चाहते हैं कि यह कहाँ गया था?
एलेक्स लेविन

170

आप यह भी कर सकते हैं यदि आप एक साधारण लाइनर चाहते हैं:

puts caller

2
बहुत बढ़िया चाल। बहुत बहुत धन्यवाद। मुझे नहीं पता था कि raiseइसका उपयोग बिना किसी तर्क के किया जा सकता है। न ही मुझे पता था कि rescueवन-लाइनर के रूप में सही ढंग से व्यवहार किया जाएगा। मैं उन वैश्विक संस्करणों को भी पूरी तरह से नजरअंदाज कर देता हूं $!
दमित्री नागिरन्याक

11
उठाने / बचाव की कोई आवश्यकता नहीं है, आप सिर्फ कर्नेल # कॉलर का उपयोग कर सकते हैं, जैसे:puts "this line was reached by #{caller.join("\n")}"
स्टीफन सी

आह, मुझे इस उत्तर को पोस्ट करने के तुरंत बाद पता चला और इसे अपडेट करना भूल गया। साभार
गुमनाम कायर

मैं y callerजावा स्टैक ट्रेस जैसे आउटपुट को प्रिंट करने के लिए उपयोग करता हूं ।
so_mv

caller(0,2)स्टैकट्रेस में दो नवीनतम प्रविष्टियाँ लौटाएगा। संक्षिप्‍त संख्‍याओं के उत्‍पादन के लिए अच्‍छा है।
मैग्ने

100

यह त्रुटि विवरण और अच्छा साफ, इंडेंट किए गए स्टैकट्रेस का उत्पादन करता है:

begin               
 # Some exception throwing code
rescue => e
  puts "Error during processing: #{$!}"
  puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
end

49

आईआरबी के पास इस भयानक "सुविधा" के लिए एक सेटिंग है, जिसे आप अनुकूलित कर सकते हैं।

एक फ़ाइल बनाएँ ~/.irbrcजिसमें निम्न पंक्ति शामिल हो:

IRB.conf[:BACK_TRACE_LIMIT] = 100

इससे आप 100 स्टैक फ्रेम देख पाएंगे irb कम से कम । मैं गैर-संवादात्मक रनटाइम के लिए एक समान सेटिंग खोजने में सक्षम नहीं हूं।

आईआरबी अनुकूलन के बारे में विस्तृत जानकारी पिकैक्स पुस्तक में पाई जा सकती है ।


3
यह स्वीकृत उत्तर होना चाहिए, क्योंकि यह इस सवाल को संबोधित करता है कि "... एक्स स्तर ..." के बजाय बैकट्रेस को अधिक कैसे दिखाया जाए।
निक

13

कॉलस्टैक के लिए एक लाइनर:

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace; end

सभी रत्नों के बिना कॉलस्टैक के लिए एक लाइनर:

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//); end

सभी रत्नों के बिना कॉलस्टैक के लिए एक लाइनर और वर्तमान निर्देशिका के सापेक्ष

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//).map { |l| l.gsub(`pwd`.strip + '/', '') }; end

2
एक-लाइनर वास्तव में एक बुरी बात है जब आपके पास कई कथन हैं।
nurettin

3
@nurettin यह त्वरित डिबगिंग उद्देश्य के लिए है इसलिए इसे एक पंक्ति बनाने से पेस्ट करने में आसानी होती है, ज्यादातर इंटरेक्टिव गोले में
डोरियन

@ डोरियन आपको एक प्रश्न के बारे में याद दिलाता हूं जो मेरे पास था: "इंटरैक्टिव गोले उपयोगी क्यों हैं? (शैल-स्क्रिप्ट को छोड़कर)"।
Sapphire_Brick

9

यह आधिकारिक रूबी ट्रेस करता है, अगर यह आपके लिए महत्वपूर्ण है।

begin
  0/0  # or some other nonsense
rescue => e
  puts e.backtrace.join("\n\t")
       .sub("\n\t", ": #{e}#{e.class ? " (#{e.class})" : ''}\n\t")
end

स्पष्ट रूप से, यह 'अनहैंडल्ड अपवाद' को ठीक से हैंडल नहीं करता है, इसे 'RuntimeError' के रूप में रिपोर्ट करता है, लेकिन स्थान सही है।


मुझे खेद है कि मेरे पास आपके उत्तर के लिए देने के लिए एक अपवोट है। मैं इसे हर जगह जोड़ता हूं
Dbz

4

अपने परीक्षण वातावरण (रेक टेस्ट या ऑटोटेस्ट के माध्यम से) को लोड करने की कोशिश करते समय मुझे ये त्रुटियां हो रही थीं और आईआरबी के सुझावों ने मदद नहीं की। मैंने अपनी पूरी परीक्षा / test_helper.rb को एक शुरुआत / बचाव ब्लॉक में लपेटकर समाप्त कर दिया और यह तय हो गया।

begin
  class ActiveSupport::TestCase
    #awesome stuff
  end
rescue => e
  puts e.backtrace
end

0

[अपराधी को खोजने के लिए सभी थ्रेड्स की जांच करें]
यहां तक ​​कि पूरी तरह से विस्तारित कॉल स्टैक तब भी आप से कोड की वास्तविक आक्रामक रेखा को छिपा सकते हैं जब आप एक से अधिक धागे का उपयोग करते हैं!

उदाहरण: एक धागा रूबी हैश को पुन: प्रसारित कर रहा है, अन्य धागा इसे संशोधित करने का प्रयास कर रहा है। बूम! अपवाद! और 'व्यस्त' हैश को संशोधित करने का प्रयास करते समय आपके द्वारा प्राप्त किए गए स्टैक ट्रेस के साथ समस्या यह है कि यह आपको उस स्थान पर नीचे फ़ंक्शन की श्रृंखला दिखाता है जहां आप हैश को संशोधित करने का प्रयास कर रहे हैं, लेकिन यह नहीं दिखाता है कि वर्तमान में कौन इसे समानांतर में पुनरावृत्त कर रहा है ( जो इसका मालिक है)! यहां यह पता लगाने का तरीका है कि वर्तमान में चल रहे थ्रेड्स के लिए स्टैक ट्रेसिंग प्रिंट करके। यहां बताया गया है कि आप यह कैसे करते हैं:

# This solution was found in comment by @thedarkone on https://github.com/rails/rails/issues/24627
rescue Object => boom

    thread_count = 0
    Thread.list.each do |t|
      thread_count += 1
      err_msg += "--- thread #{thread_count} of total #{Thread.list.size} #{t.object_id} backtrace begin \n"
      # Lets see if we are able to pin down the culprit
      # by collecting backtrace for all existing threads:
      err_msg += t.backtrace.join("\n")
      err_msg += "\n---thread #{thread_count} of total #{Thread.list.size} #{t.object_id} backtrace end \n"
    end

    # and just print it somewhere you like:
    $stderr.puts(err_msg)

    raise # always reraise
end

उपरोक्त कोड स्निपेट केवल शैक्षिक उद्देश्यों के लिए भी उपयोगी है क्योंकि यह आपको दिखा सकता है (जैसे एक्स-रे) आपके पास वास्तव में कितने धागे हैं (बनाम आपने कितने सोचा है - अक्सर उन दो अलग-अलग संख्याएं हैं;)


0

तुम भी उपयोग कर सकते हैं पश्व-अनुरेखन रूबी मणि (मैं लेखक हूँ):

require 'backtrace'
begin
  # do something dangerous
rescue StandardError => e
  puts Backtrace.new(e)
end

4
क्या आप कम से कम यह समझा सकते हैं कि हम आपके मणि का उपयोग क्यों करना चाहते हैं? क्या आप कुछ नमूना आउटपुट दिखा सकते हैं?
ioquatix
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.