কখনও কখনও ব্যতিক্রমগুলির সাথে কী ঘটছে তা বোঝা সত্যিই কঠিন হতে পারে - বিশেষ করে বড় অ্যাপগুলিতে৷ কল্পনা করুন যে আপনি একটি বিদ্যমান প্রকল্পের ভিতরে কিছু কোডে কাজ করছেন। আপনি একটি ব্যতিক্রম উত্থাপন, তারপর অদ্ভুত কিছু ঘটবে. হয়তো ব্যতিক্রম গিলেছে। হয়তো একটি পরিবেশ পরিবর্তনশীল পরিবর্তন করা হয়. হয়তো আপনার ব্যতিক্রম অন্য একটি ব্যতিক্রমের মধ্যে মোড়ানো হবে।
আমি আপনাকে আপনার অ্যাপে ব্যতিক্রমগুলি সম্পর্কে আরও কিছু তথ্য পেতে TracePoints ব্যবহার করার একটি সহজ উপায় দেখাতে যাচ্ছি - এমনকি যদি সেই ব্যতিক্রমগুলি গ্রাস করা হয়।
একটি সুবিধাজনক উদাহরণ
রেলের কন্ট্রোলার এবং ভিউয়ের মধ্যে সীমানা এমন একটি জায়গা যেখানে ব্যতিক্রম যুক্তিকে অস্বীকার করে। এটা নিজের জন্য দেখতে সহজ. শুধু একটি দৃশ্যে একটি ব্যতিক্রম উত্থাপন করুন এবং এটি একটি নিয়ামক থেকে উদ্ধার করার চেষ্টা করুন। আপনি দেখতে পাবেন যে আপনি কন্ট্রোলার থেকে টেমপ্লেট ত্রুটি উদ্ধার করতে পারবেন না!
# pages_controller.rb
def index
render
rescue
# this will never run
logger.debug "someone raised the roof"
end
# index.haml
- raise "the roof"
WTF!?! আমি ভেবেছিলাম আমি এটাকে উদ্ধার করেছি!
এটা স্পষ্ট যে সেখানে কিছু জটিল হচ্ছে। দেখা যাক এটা কি তা আমরা বের করতে পারি কিনা।
ট্রেসপয়েন্ট দিয়ে সব ব্যতিক্রম লগ করা
ট্রেসপয়েন্টস একটি সত্যিই শক্তিশালী আত্মদর্শন টুল যা রুবি 2.0 থেকে চলে আসছে। তারা আপনাকে বিভিন্ন ধরণের রানটাইম ইভেন্টের জন্য কলব্যাক সংজ্ঞায়িত করার অনুমতি দেয়। উদাহরণস্বরূপ, যখনই একটি ক্লাস সংজ্ঞায়িত করা হয়, যখনই একটি পদ্ধতি বলা হয় বা যখনই একটি ব্যতিক্রম উত্থাপিত হয় তখন আপনাকে অবহিত করা যেতে পারে। আরও ইভেন্টের জন্য ট্রেসপয়েন্ট ডকুমেন্টেশন দেখুন।
আসুন একটি ট্রেসপয়েন্ট যোগ করে শুরু করি যাকে বলা হয় যখনই একটি ব্যতিক্রম উত্থাপিত হয় এবং লগে এটির একটি সারাংশ লেখা হয়৷
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
পদ্ধতি, আমি কালারাইজ মণি ব্যবহার করছি। এটি আউটপুটে ANSI কালার কোড যোগ করে।
এখন যখন আমি গিয়ে আমার পৃষ্ঠাটি রিফ্রেশ করি, আমার লগগুলি নীচের স্ক্রিনশটের মতো দেখায়৷ একটি আকর্ষণীয় বিষয় যা আপনি লক্ষ্য করতে পারেন যে দুটি পৃথক ব্যতিক্রম রয়েছে এবং তাদের প্রত্যেকটি দুবার উত্থাপিত হয়েছে। প্রতিটি লাইনের শুরুতে সেই দীর্ঘ সংখ্যাটি হল ব্যতিক্রমের অবজেক্ট আইডি। এভাবেই আমরা জানি যে দুটি ব্যতিক্রম বস্তু আছে, চারটি নয়।
এই লগটি 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
যখন আমি আমার ব্রাউজার রিফ্রেশ করি, আমি দেখতে পাই নিম্নলিখিত লাইনগুলি লগটিতে যোগ করা হয়েছে:
প্রতিটি "বাড়ানো" ইভেন্টের উপরে দেখানো হয়েছে যে পদ্ধতিটি এটি ঘটিয়েছে
যেহেতু আমরা শুধুমাত্র "রিটার্ন" ট্রেসপয়েন্ট সক্রিয় করি যখন একটি ব্যতিক্রম উত্থাপিত হয়, প্রথম "রিটার্ন" ইভেন্টটি সেই পদ্ধতি থেকে হতে চলেছে যা ব্যতিক্রম উত্থাপন করেছে৷
আমরা আমাদের রহস্য সমাধান করতে এই তথ্য ব্যবহার করতে পারেন. আমাদের আসল RuntimeError
একটি ActionView::Template::Error
এ রূপান্তরিত হচ্ছে handle_render_error
দ্বারা template.rb.
এই কৌশল সম্পর্কে চমৎকার জিনিস হল যে এটি রেলের সাথে কিছু করার নেই। কোন ব্যতিক্রমগুলি উত্থাপন করা হচ্ছে এবং হুডের নীচে ধরা হচ্ছে তা আরও বিশদভাবে বোঝার জন্য আপনি যেকোনো সময় এটি ব্যবহার করতে পারেন৷