আমি কীভাবে ছাঁটাইয়ের পরিবর্তে একটি পূর্ণ ব্যাকট্রেস মুদ্রণ করতে রুবি পেতে পারি?


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
পরিবর্তে কমান্ড লাইন থেকে এটি করার কোনও উপায় আছে?
অ্যান্ড্রু গ্রিম 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
আমি ব্যতিক্রমটি আবার সংশোধন করব, কমপক্ষে উদাহরণগুলির সম্পূর্ণতার জন্য।
reto

13
পুনরুদ্ধার করার জন্য আপনাকে কেবল বলতে হবে raise। আপনি যে এক্সিকিউশনটি উত্থাপন করতে চান তা স্পষ্টভাবে নির্দিষ্ট করার দরকার নেই।
টিমো

ভাল, আমি সবসময় ভেবেছিলাম উত্থাপনের জন্য আপনাকে পূর্ববর্তী ব্যতিক্রম করতে হবে। আমি বুঝতে পারি নি যে এটি উদ্ধারকৃত সর্বশেষ ব্যতিক্রমের ডিফল্ট।
22:25

যদি আপনার কোডটি একটি ব্যতিক্রম না ছুঁড়ে, আপনি কেবল কোথায় গিয়েছিলেন তার স্ট্যাক ট্রেস দেখতে চান?
অ্যালেক্স লেভিন

170

আপনি যদি একটি সাধারণ ওলাইনার চান তবে এটি করতেও পারেন:

puts caller

2
দুর্দান্ত কৌশল অনেক ধন্যবাদ. আমি জানতাম না যে raiseকোনও যুক্তি ছাড়াই ব্যবহার করা যেতে পারে। আমিও জানতাম না যে rescueওয়ান-লাইনার হিসাবে সঠিকভাবে বিবেচিত হবে। আমি যেমন বিশ্বব্যাপী যুদ্ধগুলি সম্পূর্ণ উপেক্ষা করি $!
Dmytrii নাগিরনিয়াক

11
বাঁচানোর / উদ্ধার করার দরকার নেই, আপনি ঠিক যেমন কার্নেল # কলার ব্যবহার করতে পারেন:puts "this line was reached by #{caller.join("\n")}"
স্টিফেন সি

আহ, আমি এই উত্তরটি পোস্ট করার পরেই এটি সম্পর্কে জানতে পেরেছিলাম এবং এটি আপডেট করতে ভুলে গিয়েছি। ধন্যবাদ
বেনামে কাপুরুষ

আমি y callerজাভা স্ট্যাক ট্রেস এর মতো আউটপুট প্রিন্ট করতে ব্যবহার করি ।
so_mv

caller(0,2)স্ট্যাকট্রেসে সর্বশেষ দুটি এন্ট্রি ফিরিয়ে দেবে। সংক্ষিপ্ত স্ট্যাকট্রেসগুলি আউটপুট দেওয়ার জন্য দুর্দান্ত N
ম্যাগনে

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

সমস্ত রত্ন ছাড়াই কলস্ট্যাকের জন্য একটি লাইনার এবং বর্তমান ডিরেক্টরি সম্পর্কিত relative

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

2
যখন আপনার একাধিক বক্তব্য থাকে তখন ওয়ান-লাইনারটি আসলে একটি খারাপ জিনিস।
নুরেটিন

3
@ নুরেটিন এটি দ্রুত ডিবাগিংয়ের উদ্দেশ্যে, সুতরাং এটির একটি লাইন তৈরি করা এটিকে অনুলিপি করে আটকানো সহজ করে তোলে, বেশিরভাগ ইন্টারেক্টিভ শেলগুলিতে
ডোরিয়ান

@ ডোরিয়ান আপনি আমাকে একটি প্রশ্ন সম্পর্কে স্মরণ করিয়ে দিয়েছেন যে: "ইন্টারেক্টিভ শেলগুলি কীভাবে কার্যকর? (শেল-স্ক্রিপ্ট বাদে)" "।
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

মজাদারভাবে, এটি 'আনইন্ডলড ব্যতিক্রম' সঠিকভাবে পরিচালনা করে না, এটি 'রানটাইম’রর হিসাবে রিপোর্ট করে তবে অবস্থানটি সঠিক।


আমি আফসোস করছি যে আপনার উত্তরটি দেওয়ার জন্য আমার কেবল একটি উত্সাহ আছে। আমি এটিকে
যেকোন

4

আমার পরীক্ষার পরিবেশটি (রেক টেস্ট বা অটোস্টেস্টের মাধ্যমে) লোড করার চেষ্টা করার সময় আমি এই ত্রুটিগুলি পেয়েছি এবং আইআরবি পরামর্শগুলি সাহায্য করেনি। আমি আমার সম্পূর্ণ পরীক্ষা / টেস্ট_হেল্পার.আরবিটিকে একটি প্রারম্ভিক / উদ্ধারকৃত ব্লকে মোড়ানো শেষ করেছিলাম এবং এটি স্থির করে রেখেছি।

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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.