Rotoscope is a high-performance logger of Ruby method invocations.
Rotoscope is subject to breaking changes in minor versions until 1.0 is available.
require'rotoscope'classDogdefbarkNoisemaker.speak('woof!')endendclassNoisemakerdefself.speak(str)puts(str)endendlog_file=File.expand_path('dog_trace.log')puts"Writing to #{log_file}..."Rotoscope::CallLogger.trace(log_file)dodog1=Dog.newdog1.barkendThe resulting method calls are saved in the specified dest in the order they were received.
Sample output:
entity,method_name,method_level,filepath,lineno,caller_entity,caller_method_name,caller_method_level
Dog,new,class,example/dog.rb,19,<ROOT>,<UNKNOWN>,<UNKNOWN>
Dog,initialize,instance,example/dog.rb,19,Dog,new,class
Dog,bark,instance,example/dog.rb,20,<ROOT>,<UNKNOWN>,<UNKNOWN>
Noisemaker,speak,class,example/dog.rb,5,Dog,bark,instance
Noisemaker,puts,class,example/dog.rb,11,Noisemaker,speak,class
IO,puts,instance,example/dog.rb,11,Noisemaker,puts,class
IO,write,instance,example/dog.rb,11,IO,puts,instance
IO,write,instance,example/dog.rb,11,IO,puts,instance
Rotoscope ships with a default logger, Rotoscope::CallLogger. This provides a simple-to-use interface to the tracing engine that maintains performance as much as possible.
Writes all calls of methods to dest, except for those whose filepath contains any entry in excludelist. dest is either a filename or an IO. Methods invoked at the top of the trace will have a caller entity of <ROOT> and a caller method name of <UNKNOWN>.
Rotoscope::CallLogger.trace(dest){ |call| ... }# or...Rotoscope::CallLogger.trace(dest,excludelist: ["/.gem/"]){ |call| ... }Same interface as Rotoscope::CallLogger::trace, but returns a Rotoscope::CallLogger instance, allowing fine-grain control via Rotoscope::CallLogger#start_trace and Rotoscope::CallLogger#stop_trace.
rs=Rotoscope::CallLogger.new(dest)# or...rs=Rotoscope::CallLogger.new(dest,excludelist: ["/.gem/"])Similar to Rotoscope::CallLogger::trace, but does not need to create a file handle on invocation.
rs=Rotoscope::CallLogger.new(dest)rs.tracedo |rotoscope|
# code to trace...endBegins writing method calls to the dest specified in the initializer.
rs=Rotoscope::CallLogger.new(dest)rs.start_trace# code to trace...rs.stop_traceStops writing method invocations to the dest. Subsequent calls to Rotoscope::CallLogger#start_trace may be invoked to resume tracing.
rs=Rotoscope::CallLogger.new(dest)rs.start_trace# code to trace...rs.stop_traceInserts a marker '--- ' to divide output. Useful for segmenting multiple blocks of code that are being profiled. If str is provided, the line will be prefixed by '--- ', followed by the string passed.
rs=Rotoscope::CallLogger.new(dest)rs.start_trace# code to trace...rs.mark('Something goes wrong here')# produces `--- Something goes wrong here` in the output# more code ...rs.stop_traceFlushes the buffer and closes the file handle. Once this is invoked, no more writes can be performed on the Rotoscope::CallLogger object. Sets state to :closed.
rs=Rotoscope::CallLogger.new(dest)rs.trace{ |rotoscope| ... }rs.closeReturns the current state of the Rotoscope::CallLogger object. Valid values are :open, :tracing and :closed.
rs=Rotoscope::CallLogger.new(dest)rs.state# :openrs.tracedors.state# :tracingendrs.closers.state# :closedShorthand to check if the state is set to :closed.
rs=Rotoscope::CallLogger.new(dest)rs.closed?# falsers.closers.closed?# trueFor those who prefer to define their own logging logic, Rotoscope also provides a low-level API. This is the same one used by Rotoscope::CallLogger internally. Users may specify a block that is invoked on each detected method call.
.new#trace#start_trace#stop_trace#tracing?#receiver#receiver_class#receiver_class_name#method_name#singleton_method?#caller_object#caller_class#caller_class_name#caller_method_name#caller_singleton_method?#caller_path#caller_lineno
Creates a new instance of the Rotoscope class. The block argument is invoked on every call detected by Rotoscope. The block is passed the same instance returned by Rotoscope#new allowing the low-level methods to be called.
rs=Rotoscope.newdo |call|
# We likely don't want to record calls to Rotoscopereturnifself == call.receiver
...
endThe equivalent of calling Rotoscope#start_trace and then Rotoscope#stop_trace. The call to #stop_trace is within an ensure block so it is always called when the block terminates.
rs=Rotoscope.newdo |call|
...
endrs.tracedo# call some codeendBegins detecting method calls invoked after this point.
rs=Rotoscope.newdo |call|
...
endrs.start_trace# Calls after this points invoke the# block passed to `Rotoscope.new`Disables method call detection invoked after this point.
rs=Rotoscope.newdo |call|
...
endrs.start_trace
...
rs.stop_trace# Calls after this points will no longer# invoke the block passed to `Rotoscope.new`Identifies whether the Rotoscope object is actively tracing method calls.
rs=Rotoscope.newdo |call|
...
endrs.tracing?# => falsers.start_tracers.tracing?# => trueReturns the object that the method is being called against.
rs=Rotoscope.newdo |call|
call.receiver# => #<Foo:0x00007fa3d2197c10>endReturns the class of the object that the method is being called against.
rs=Rotoscope.newdo |call|
call.receiver_class# => FooendReturns the stringified class of the object that the method is being called against.
rs=Rotoscope.newdo |call|
call.receiver_class_name# => "Foo"endReturns the name of the method being invoked.
rs=Rotoscope.newdo |call|
call.method_name# => "bar"endReturns true if the method called is defined at the class level. If the call is to an instance method, this returns false.
rs=Rotoscope.newdo |call|
call.singleton_method?# => falseendReturns the object whose context we invoked the call from.
rs=Rotoscope.newdo |call|
call.caller_object# => #<SomeClass:0x00008aa6d2cd91b61>endReturns the class of the object whose context we invoked the call from.
rs=Rotoscope.newdo |call|
call.caller_class# => SomeClassendReturns the tringified class of the object whose context we invoked the call from.
rs=Rotoscope.newdo |call|
call.caller_class_name# => "SomeClass"endReturns the stringified class of the object whose context we invoked the call from.
rs=Rotoscope.newdo |call|
call.caller_method_name# => "call_foobar"endReturns true if the method invoking the call is defined at the class level. If the call is to an instance method, this returns false.
rs=Rotoscope.newdo |call|
call.caller_singleton_method?# => trueendReturns the path to the file where the call was invoked.
rs=Rotoscope.newdo |call|
call.caller_path# => "/rotoscope_test.rb"endReturns the line number corresponding to the #caller_path where the call was invoked. If unknown, returns -1.
rs=Rotoscope.newdo |call|
call.caller_lineno# => 113end