TracePoint
TracePoint (코드 실행 추적)
TracePoint는 Ruby 코드의 실행 지점(이벤트)을 추적하는 기능이에요. 특정 이벤트(메서드 호출, 라인 실행, 클래스 정의, 예외 발생 등)가 발생할 때마다 콜백을 받아볼 수 있어요. 디버깅이나 프로파일링, 동적 분석에 유용해요. trace_point를 require 해서 사용해요.
출처: Ruby 3.3 API
본문
TracePoint.new(*events) { |obj| block } → obj
기본적으로 활성화되지 않은 새 TracePoint 객체를 돌려줘요. 다음으로 트레이스를 활성화하려면 TracePoint#enable을 사용해야 해요.
trace = TracePoint.new(:call) do |tp|
p [tp.lineno, tp.defined_class, tp.method_id, tp.event]
end
#=> #<TracePoint:...>
trace.enable #=> false
puts "Hello, TracePoint!"
# ...
# [48, IRB::Notifier::AbstractNotifier, :printf, :call]
# ...
# trace를 비활성화하려면 TracePoint#disable
trace.disable
블록은 반드시 주어야 하며, 주지 않으면 ArgumentError가 발생해요. 트레이스할 메서드가 주어진 이벤트 필터에 포함되지 않으면 RuntimeError가 발생해요.
TracePoint.trace(*events) { |obj| block } → obj
TracePoint.new의 편의 메서드로, 트레이스를 자동으로 활성화해요.
trace = TracePoint.trace(:call) { |tp| [tp.lineno, tp.event] }
#=> #<TracePoint:...>
trace.enabled? #=> true
TracePoint.stat → obj
TracePoint 내부 정보를 돌려줘요. 반환값의 내용은 구현 세부 사항이라 미래에 바뀔 수 있어요. 이 메서드는 TracePoint 자체를 디버깅할 때만 사용하는 메서드예요.
allow_reentry { block }
일반적으로 TracePoint 콜백이 실행되는 동안 재진입(reentrance)으로 인한 혼란을 피하려고 다른 등록된 콜백은 호출되지 않아요. 이 메서드는 주어진 블록 안에서 재진입을 허용해요. 조심해서 사용해야 해요. 그렇지 않으면 콜백이 쉽게 무한히 호출될 수 있어요. 이미 재진입이 허용된 상태에서 이 메서드를 호출하면 RuntimeError가 발생해요.
allow_reentry는 TracePoint 클래스 자체(싱글턴) 메서드로도, 인스턴스의 참조를 통해 (TracePoint.allow_reentry { ... } 형태로 블록) 사용할 수 있어요.
enable(target: nil, target_line: nil, target_thread: nil) → true or false
트레이스를 활성화해요. 활성화돼 있으면 true, 아니면 false를 돌려줘요. 블록을 주면 그 블록 호출 동안에만 짧게 트레이스가 활성화돼요. target과 target_line이 둘 다 nil인데 블록이 주어지면, target_thread는 기본값으로 현재 스레드가 돼요.
disable → true or false · disable { block } → obj
트레이스를 비활성화해요. 트레이스가 활성화돼 있었으면 true, 아니었으면 false를 돌려줘요. 블록을 주면 블록의 스코프 안에서만 트레이스가 비활성화돼요. 주의: 블록 안에서는 이벤트 훅에 접근할 수 없어요. (예: trace.disable { p tp.lineno } → RuntimeError: access from outside)
enabled? → true or false
트레이스의 현재 상태를 돌려줘요.
이벤트 접근자(인스턴스 메서드)
event()- 이벤트 타입.lineno()- 이벤트의 라인 번호.path()- 실행 중인 파일의 경로.method_id()- 호출되는 메서드의 정의 이름.callee_id()- 호출되는 메서드의 호출 이름.defined_class()- 호출되는 메서드가 정의된 클래스 또는 모듈.parameters()- 현재 훅이 속한 메서드/블록의 파라미터 정의. 형식은Method#parameters와 같아요.binding()- 이벤트에서 생성된 binding 객체.:c_call과:c_return이벤트에서는 C 메서드에는 binding이 없으므로nil을 돌려줘요.self()- 이벤트 동안의 트레이스 객체.:c_call/:c_return에 대해 올바른 객체(메서드 수신자)를 돌려주는 점을 빼면trace.binding.eval('self')와 같아요.return_value()-:return,:c_return,:b_return이벤트의 반환값.raised_exception()-:raise이벤트에서 던져지거나:rescue이벤트에서 구출된 예외.eval_script()-:script_compiled이벤트에서 *eval 메서드의 컴파일된 소스 코드(String). 파일에서 로드했다면nil을 돌려줘요.instruction_sequence()-:script_compiled이벤트에서RubyVM::InstructionSequence인스턴스로 표현된 컴파일된 명령 시퀀스. 이 메서드는 MRI 특정(구현 의존)이에요.inspect → string- 사람이 읽을 수 있는TracePoint상태 문자열을 돌려줘요.
defined_class 예시
class C; def foo; end; end
trace = TracePoint.new(:call) do |tp|
p tp.defined_class #=> C
end.enable do
C.new.foo
end
메서드가 모듈로 정의되면 그 모듈이 돌려줘요.
module M; def foo; end; end
class C; include M; end
trace = TracePoint.new(:call) do |tp|
p tp.defined_class #=> M
end.enable do
C.new.foo
end
defined_class는 싱글턴 클래스를 돌려준다는 점에 주의하세요. Kernel#set_trace_func의 6번째 블록 파라미터는 싱글턴 클래스에 붙은 원래 클래스를 전달하는데, 이게 Kernel#set_trace_func와 TracePoint의 차이예요.