Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Theo dõi phương thức Ruby với TracePoint: Hướng dẫn thực chiến

Ruby có hệ thống theo dõi tích hợp sẵn mà bạn có thể truy cập thông qua lớp TracePoint. Một số thứ bạn có thể theo dõi bao gồm gọi phương thức, luồng mới và ngoại lệ.

Tại sao bạn muốn dùng tính năng này?

Nó có thể hữu ích nếu bạn muốn theo dõi việc thực thi của một phương thức cụ thể. Bạn sẽ thấy được các phương thức khác đang được gọi và giá trị trả về của chúng.

Hãy cùng xem một vài ví dụ!

Theo dõi gọi phương thức

Phần lớn thời gian bạn sẽ muốn TracePoint theo dõi mã ứng dụng thay vì các phương thức tích hợp sẵn (như puts, size, v.v.).

Bạn có thể làm điều này bằng sự kiện call.

Ví dụ:

def the_method; other_method; end
def other_method; end
def start_trace
  trace = TracePoint.new(:call) { |tp| p [tp.path, tp.lineno, tp.event, tp.method_id] }
  trace.enable
  yield
  trace.disable
end
start_trace { the_method }

Đoạn mã này in ra đường dẫn tệp, số dòng, tên sự kiện và tên phương thức.

["test.rb", 1, :call, :the_method]
["test.rb", 2, :call, :other_method]

Nếu bạn không chỉ định sự kiện nào, Ruby sẽ gọi block của bạn cho tất cả các sự kiện, dẫn đến nhiều đầu ra hơn. Vì vậy, tôi khuyên bạn nên tập trung vào các sự kiện cụ thể để tìm thấy thứ bạn cần nhanh hơn 🙂

Dưới đây là bảng các sự kiện của TracePoint:

Tên sự kiện Mô tả
call Phương thức ứng dụng
c_call Phương thức cấp C (như puts)
return Trả về phương thức (để theo dõi giá trị trả về và độ sâu gọi)
b_call Gọi block
b_return Trả về block
raise Ngoại lệ được ném ra
thread_begin Luồng mới
thread_end Luồng kết thúc

TracePoint + Graphviz

Nhiều phương thức sẽ thực hiện nhiều hơn 3 lần gọi phương thức, đặc biệt trong mã framework, nên đầu ra từ TracePoint có thể khó hình dung.

Vì vậy tôi tạo了一個 gem cho phép bạn tạo biểu đồ gọi trực quan như thế này:

require 'visual_call_graph'
VisualCallGraph.trace { "Your method call here..." }

Điều này tạo ra tệp call_graph.png với kết quả.

Theo dõi phương thức Ruby với TracePoint: Hướng dẫn thực chiến

Hãy nhớ rằng đây không phải là phân tích tĩnh, nó sẽ thực sự gọi phương thức!

Hiển thị đường dẫn tệp

Bạn có muốn biết các phương thức này được định nghĩa ở đâu không?

Đừng lo, tôi đã lo cho bạn! Tôi đã thêm một tùy chọn bạn có thể bật để hiển thị đường dẫn tệp cho mỗi lần gọi phương thức.

VisualCallGraph.trace(show_path: true) { Foo.aaa }

Kết quả là:

Theo dõi phương thức Ruby với TracePoint: Hướng dẫn thực chiến

Nếu bạn muốn xem các biểu đồ gọi khổng lồ, chỉ cần theo dõi một số phương thức Rails 😉

Giá trị trả về

Trong phần mở đầu tôi đã nhắc đến việc bạn cũng có thể lấy giá trị trả về...

Để làm điều này, bạn sẽ cần theo dõi sự kiện return và sử dụng phương thức return_value.

Ví dụ:

def the_method; "A" * 10; end
trace = TracePoint.new(:return) { |tp| puts "Return value for #{tp.method_id} is #{tp.return_value}." }
trace.enable
the_method
trace.disable

Điều này sẽ in ra:

Return value for the_method is AAAAAAAAAA.

Sự kiện xảy ra trước

Có ai đó hỏi trên Reddit làm thế nào để tránh in từ "bar" khi gọi phương thức foo trong mã sau:

class Thing
  def foo
    puts "foo"
    bar
  end
  def bar
    puts "bar"
  end
end
# your code here
t = Thing.new
t.foo

Có nhiều cách để đạt được điều này, như prepend một module, chuyển hướng $stdout hoặc định nghĩa lại phương thức bar.

Nếu bạn cảm thấy sáng tạo, hãy bình luận vào bài viết này với ý tưởng của bạn!

Nhưng tôi thấy một câu trả lời đặc biệt thú vị vì nó sử dụng lớp TracePoint.

Đây là nó:

TracePoint.trace(:call) { |tp| exit if tp.method_id == :bar }

Đoạn mã này sẽ gọi exit khi phương thức bar được gọi, ngăn chặn việc in chuỗi bằng cách kết thúc chương trình.

Có lẽ không phải điều bạn muốn dùng trong mã thực tế, nhưng nó chứng minh một điều về TracePoint: Sự kiện được kích hoạt trước khi chúng xảy ra.

Điều cần nhớ nếu bạn định xây dựng某种工具 dựa trên này 🙂

Tóm tắt

Trong bài viết này, bạn đã học về lớp TracePoint, cho phép bạn theo dõi một số sự kiện như gọi phương thức hoặc luồng mới. Điều này có thể hữu ích như công cụ gỡ lỗi hoặc khám phá mã.

Hãy nhớ chia sẻ bài viết này để nhiều người hơn có thể tận hưởng nó 🙂