2010-02-08 23 views
28

मुझे रूबी कोड का एक बड़ा ढेर विरासत में मिला है, जो स्पष्ट रूप से, मेरे जैसे प्राणघातक को समझने के लिए असंभव है। यह वास्तव में रुपयेपीसी इकाई परीक्षण कोड है, लेकिन संरचना अच्छी तरह से रखने के लिए "बेहद असामान्य" है।रूबी प्रोग्राम में कॉल की जाने वाली हर विधि को मैं कैसे लॉग करूं?

क्या मैं निम्नलिखित जानकारी कहीं लॉग इन किया है करने के लिए कोड चलता है सक्षम होने के लिए, और चाहते हैं:

  • हर विधि है कि लागू किया जाता है वर्ग पद्धति निर्धारित करता है के नाम भी शामिल हैं, और फ़ाइल नाम जहां आविष्कार विधि परिभाषित की गई है (हाँ, हमें एक ही कक्षा/विधि को कई अलग-अलग फाइलों में परिभाषित किया गया है, और यह जानना मुश्किल है कि कौन सा आह्वान किया जा रहा है)
  • (वैकल्पिक रूप से) प्रत्येक विधि को पारित पैरामीटर

के साथ कि, मैं इसे पुन: सक्रिय करने की कोशिश करना शुरू कर सकता था। इसके बिना, कोड बेस (20k + यूनिट टेस्ट केस) के आकार के कारण, इसे सीधे प्राप्त करने के लिए यह एक बहुत ही मुश्किल काम होगा।

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

क्या कोड आधार में थोक परिवर्तन किए बिना इस स्तर के विस्तार को लॉग करने का कोई तरीका है? मैंने रूबी प्रोफाइलर को यह देखने के लिए देखा है कि क्या यह मदद कर सकता है, और शायद यह हो सकता है; यदि कोई बेहतर तरीका है (विशेष रूप से आवेदित विधि वाले फ़ाइल नाम को लॉगिंग करना) तो मैं उत्सुक हूं।

अग्रिम

+0

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

+0

मुझे यकीन है कि डॉक्सिजन रूबी का समर्थन नहीं करता है - अगर ऐसा होता है, तो यह निश्चित रूप से मेरे लिए उपयोगी होगा, लेकिन मुझे रूक्सी का समर्थन करने वाले डॉक्सीजन के बारे में कोई जानकारी नहीं मिल रही है। मैं कुछ ऐसा करना चाहता हूं जो वास्तव में कोड चलाता है, मुख्य रूप से जिस क्रम में संसाधित होने की आवश्यकता होती है, वह प्रभावित करेगा कि किसी दिए गए विधि की एकाधिक (गैर-समान) परिभाषाओं का उपयोग किया जाएगा। जैसा कि मैंने कहा, यह एक बदसूरत कोड बेस है ... – monch1962

उत्तर

58

धन्यवाद यह निश्चित रूप से संभव है - वास्तव में, यहां तक ​​कि इसके लिए एक विधि!

set_trace_func proc { |event, file, line, id, binding, classname| 
    printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname 
} 

आप चाहते हैं गुप्त सॉस के रूप में ऊपर वर्णित है, Kernel#set_trace_func से आता है:: बस बात यह है कि आप प्रवेश बातें शुरू करना चाहते से पहले अपने कोड में यह कहीं न कहीं जोड़ने

  • set_trace_func (proc) => proc
  • set_trace_func (शून्य) => शून्य

proc को ट्रेसिंग के लिए हैंडलर के रूप में स्थापित करता है, या पैरामीटर nil पर ट्रेसिंग अक्षम करता है। proc तक छह पैरामीटर लेते हैं: एक ईवेंट नाम, एक फ़ाइल नाम, एक पंक्ति संख्या, एक ऑब्जेक्ट आईडी, बाध्यकारी, और एक वर्ग का नाम। जब भी कोई घटना होती है तो proc आक्रमण किया जाता है। घटनाक्रम हैं: c-call (सी-भाषा दिनचर्या को कॉल करें), c-return (सी-भाषा दिनचर्या से वापस), call (रूबी विधि को कॉल करें), class (कक्षा या मॉड्यूल परिभाषा शुरू करें), end (कक्षा या मॉड्यूल परिभाषा को समाप्त करें), line (एक नई लाइन पर कोड निष्पादित करें), raise (अपवाद बढ़ाएं), और return (रूबी विधि से वापस)। ट्रेसिंग proc के संदर्भ में अक्षम है।

class Test 
    def test 
    a = 1 
    b = 2 
    end 
end 

set_trace_func proc { |event, file, line, id, binding, classname| 
    printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname 
} 

t = Test.new 
t.test 

(नोट::। irb में इस कोशिश मत करो जब तक आप पाठ की एक बड़ी स्क्रॉल स्क्रीन चाहते हैं) जिसके परिणामस्वरूप उत्पादन होता है:

line test.rb:11    false 
    c-call test.rb:11  new Class 
    c-call test.rb:11 initialize Object 
c-return test.rb:11 initialize Object 
c-return test.rb:11  new Class 
    line test.rb:12    false 
    call test.rb:2  test  Test 
    line test.rb:3  test  Test 
    line test.rb:4  test  Test 
    return test.rb:4  test  Test 

यहाँ एक आसान उदाहरण है

आप केवल उन परिणामों को प्राप्त करने के लिए उपरोक्त स्वरूपण स्ट्रिंग के साथ खेल सकते हैं जिन्हें आप लॉग करना चाहते हैं (उदाहरण के लिए, ऐसा लगता है कि आप केवल call ईवेंट में रूचि रखते हैं)। उम्मीद है कि उन सभी यूनिट परीक्षणों के माध्यम से छंटनी के साथ मदद करता है, और शुभकामनाएँ!

+0

वाह - यह है ... बिल्कुल वही है जो मैं उम्मीद कर रहा था। धन्यवाद जॉन! – monch1962

+0

कोई समस्या नहीं है। रूबी इस प्रकार के स्विस-आर्मी-चाकू सामान के साथ काफी आसान साबित हुआ। आईआरबी चेतावनी के लिए –

+1

+1। –

4

मैं सेकंड पास्ट मिनट घटना के साथ ही कितनी देर तक प्रत्येक कार्य

start = DateTime.now.strftime('%Q').to_i/1000.0 
set_trace_func proc { |event, file, line, id, binding, classname| 
    now_ms = DateTime.now.strftime('%Q').to_i/1000.0 
    duration = '%.3f' % (now_ms - start) 
    start = DateTime.now.strftime('%Q').to_i/1000.0 
    printf "%s %s %8s %s:%-2d %10s %8s\n", DateTime.now.strftime("%S.%L"), duration, event, file, line, id, classname 
} 

AdminUser.create(password: "password", password_confirmation: "password", email: email) 

set_trace_func nil 

मैं डिबग करने के लिए कोशिश कर रहा था कि ऐसा क्यों ताकि उपयोगकर्ताओं को बनाने के लिए बहुत अधिक समय लगा में खर्च किया गया था पर happend शामिल करना चाहता और ActiveAdmin में लॉग इन करें।

05.761 0.000 c-return /Users/nperry/.rvm/gems/[email protected]/gems/bcrypt-3.1.7/lib/bcrypt/engine.rb:51  to_s String 
05.761 0.000 c-call /Users/nperry/.rvm/gems/[email protected]/gems/bcrypt-3.1.7/lib/bcrypt/engine.rb:51 __bc_crypt BCrypt::Engine 
09.736 63.975 c-return /Users/nperry/.rvm/gems/[email protected]/gems/bcrypt-3.1.7/lib/bcrypt/engine.rb:51 __bc_crypt BCrypt::Engine 
09.736 0.000 return /Users/nperry/.rvm/gems/[email protected]/gems/bcrypt-3.1.7/lib/bcrypt/engine.rb:59 hash_secret BCrypt::Engine 
09.736 0.000 c-call /Users/nperry/.rvm/gems/[email protected]/gems/bcrypt-3.1.7/lib/bcrypt/password.rb:46  new Class 

और से मैं रूबी पता है कि __bc_crypt में एक मिनट से भी अधिक खर्च किया।

+1

लगता है जैसे आपके पास एक सुंदर उच्च BCrypt 'cost' है। टी.जे. शक [यह एक अच्छा वीडियो समझा रहा है] (http://rubyvideos.com/presenters/t-j-schuck) (पहले 15 मिनट या तो)। – jwadsack

+0

मुझे विश्वास है कि हमने उस समय इस मुद्दे को हल किया था और मुद्दा निश्चित रूप से बीक्रिप्ट था। – Nate

3

हाल ही में, set_trace_func पदावनत किया गया था:

नोट: इस विधि अप्रचलित है, TracePoint बजाय का उपयोग करें।

हम TracePoint, जो set_trace_func पीठ, बजाय का उपयोग कर सकते हैं:

trace = TracePoint.new(:call) do |tp| 
    puts "#{tp.defined_class}##{tp.method_id} got called (#{tp.path}:#{tp.lineno})" 
end 

trace.enable 
# do stuff here 
trace.disable 

यह वास्तव में भी set_trace_func से अधिक शक्तिशाली है क्योंकि आप को सक्षम और अपनी सुविधानुसार निष्क्रिय कर सकते हैं। आप चुनिंदा निम्न इवेंट में हुक कर सकते हैं: :line, :class, :end, :call, :return, :c_call, :c_return, :raise, :b_call, :b_return, :thread_begin, :thread_end

यहाँ एक पूर्ण उदाहरण:

class MyClass 
    def initialize 
    end 
    def y 
    z 
    end 
    def z 
    1 + 1 
    end 
end 

trace = TracePoint.new(:call) do |tp| 
    puts "#{tp.defined_class}##{tp.method_id} got called (#{tp.path}:#{tp.lineno})" 
end 

trace.enable # note 
MyClass.new.y 
trace.disable 
    # MyClass#initialize got called (./trace.rb:4) 
    # MyClass#y got called (./trace.rb:7) 
    # MyClass#z got called (./trace.rb:10) 
संबंधित मुद्दे