the Robot Construction Kit

Replay Log Data

Orocos::Log::Replay is a Ruby class which eases common tasks on log files. It provides methods to access, filter and replay the data inside Ruby scripts, or into oroGen components.

Note: See also Displaying Log Files if you want to visualize the logged samples.


The Replay class provides a range of features:

  • log file loading
  • time synchronous replay
  • step by step replay
  • seeking
  • user-specific log data filtering
  • log file abstraction, i.e. in Ruby scripts, log files behave like instances of Orocos::TaskContext

This functionality requires the orocos.rb package to be installed, which is contained in the Rock toolchain.

See this page for a description of the mapping from the C++ types in Ruby


The replayed log files can either be specified when initializing a Orocos::Log::Replay object, or later on by using the #load method.

replay =,folder0,...)

So far it is not possible to load multiple log files from the same component at the same time because of overlapping names.

After loading, the class offers an interface to log files that mimicks the Orocos::TaskContext API. This assumes that the log streams are called ‘task_name.port_name’ – which is the case if you are using the Orocos.log_all_ports setup method.

To access all streams from a particular task context, do

task1 =
task2 = replay.task('camera')

The equivalent call for live components is Orocos.name_service.get

Then, each log stream is mapped to a port-like object:

# Accesses the data logged from the port 'frame' of the 
# task 'camera'
output_port =

They are accessed through a reader or directly via the method read. The only difference between the two ways is the method ‘read’ will always return the last replayed data sample, while the behavior of the reader depends on the applied connection policy.

reader = output_port.reader :type => :data
puts                    #no different between both
puts               #reads
reader = output_port.reader :type => :buffer,:size => 1
puts                    #=> last replayed sample
puts                    #=> nil
puts               #=> last replayed sample
puts               #=> last replayed sample

If you wish to feed logged data into a running RTT component, you can use the normal connect_to method: rtt_task.frame

If you wish to transform the data before it gets fed to the task, you can specify a filtering block: rtt_task.frame do |sample|
  # the sample gets transformed here
  sample # return the modified value

Moreover, to make simple setups straightforward, the Replay class can autoconnect log streams to component ports. For each port of the target task, an equivalent port (same name and same type) is searched for in the logged data. If the name differs, a name mapping can be provided.

# performs an auto connect
replay.connect_to rtt_task
# Connects matching ports between the log data and a running 
# RTT component
# When looking for matching names, 'frame' (on logged 
# side) will be replaced by "iframe" (on component side).
replay.connect_to rtt_task, :frame => :iframe

Once the replay network is properly set up, you start replaying by calling #run#.         # replay all logged data as fast as possible,1) # replay as fast as the data were recorded
replay.step        # replay one data sample

Only ports are replayed which are connected to RTT components, for which a reader has been created or a filter was specified. If you want to specify that one particular stream should be replayed, set its #tracked# property to true:

# Forces the log stream to be replayed = true

Understanding time in log files

Rock’s log file format embeds two times per sample one logical time and one real time. Currently, these two times correspond to the time at which the logger received a sample (logical time) and the time it wrote it to disk (real time).

However, when visualizing or replaying data, one usually wants to consider the time of the sample as the replay time (i.e. the time stored in the sample’s timestamp field, if there is one). In most cases, the logical time will do the trick. However, it won’t be the case if the computer on the robot is overloaded (either because the disk is too slow or the CPU load too high).

In the future, the logical time will be the sample time. However, the current implementation of Rock’s logger component does not allow that, so one needs to use some options on Rock’s log replay tooling.

The following methods are limited for data types that have a ‘time’ field of type /base/Time. The replay algorithm will fall back to the logical time for streams do not fit this.

On the command line, one can use the --time-source option to rock-replay:

rock-replay --use-sample-time mylogfile.0.log

In Ruby scripts, one can use the time_source attribute on the Replay class

replay =,folder0,...)
replay.use_sample_time = true

Finally, one can process log files offline to store the sample time in place of the logical time using rock-convert. This is very useful when the same logfile is going to be processed multiple times, as it will remove the need to add the use_sample_time option to the other tools

rock-convert --use-sample-time LOGFILE

Example: Loading and accessing log data:

#!/usr/bin/env ruby

require 'orocos/log'
include Orocos

replay ='camera.0.log') do |frame|
  puts frame.time

#replay as fast as possible 

Example: Loading and replaying log data

#!/usr/bin/env ruby

require 'orocos/log'
include Orocos

replay ='camera.0.log') 'deployment_x' do
  task_x = Orocos.name_service.get('task_x')

  #auto connect
  replay.connect_to task_x 

Example: Filtering log data

#!/usr/bin/env ruby

require 'orocos/log'
include Orocos

replay ='camera.0.log') 'deployment_x' do
  task_x = Orocos.name_service.get('task_x')
  replay.connect_to task_x 

  #the filter is applied on each frame
  #before it is written to ports or readers = do |frame|
    frame.time =


Example: Advanced

#!/usr/bin/env ruby

require 'orocos/log'
include Orocos

replay ='camera.0.log','sonar.0.log') 'deployment_x','deployment_y' do
  task_x = Orocos.name_service.get('task_x')
  task_y = Orocos.name_service.get('task_y')
  replay.connect_to task_x 
  #port mapping
  replay.connect_to task_y, "sonar.frame" => "iframe"
  #get a reader 
  #Be careful. Here is a filter applied on the reader
  #if the original frame is changed in the filter all 
  #readers for the same frame which are created after this 
  #reader are affected as well.
  reader = do |frame|
    puts frame.time

  #display all ports of type /base/samples/frame/Frame
  ports = replay.find_all_ports('/base/samples/frame/Frame')
  ports.each do |port|


  replay.step(false)                    #replay one step
  replay.step(false)                    #replay one step

  puts    #display current 
                                        #frame time stamp
  puts                 #should be the same
  replay.rewind                         #rewind log data

  #the code block is called for each message on all
  #ports do |port,data|
    puts data.time if == 'frame'