Gazebo Transport

API Reference

11.4.1
Logging

Next Tutorial: Environment Variables Previous Tutorial: Relay

Overview

In this tutorial, we are going to describe the process of recording and playing back a collection of messages.

Ignition Transport provides two mechanisms for logging: a C++ API and a set of command line utilities as part of the optional ign CLI tool (available via Ignition Tools). We use SQLite3 to create a file containing all the messages recorded during a session. You can imagine it as a container where all the original messages have been efficiently stored and timestamped.

Let's create a directory for compiling and running our examples:

mkdir ~/ign_transport_tutorial
cd ~/ign_transport_tutorial

Record

Download the record.cc file within the ign_transport_tutorial folder and open it with your favorite editor:

#include <cstdint>
#include <iostream>
#include <regex>
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " OUTPUT.tlog\n";
return -1;
}
gz::transport::log::Recorder recorder;
// Record all topics
const int64_t addTopicResult = recorder.AddTopic(std::regex(".*"));
if (addTopicResult < 0)
{
std::cerr << "An error occurred when trying to add topics: "
<< addTopicResult << "\n";
return -1;
}
// Begin recording, saving received messages to the given file
const auto result = recorder.Start(argv[1]);
if (gz::transport::log::RecorderError::SUCCESS != result)
{
std::cerr << "Failed to start recording: " << static_cast<int64_t>(result)
<< "\n";
return -2;
}
std::cout << "Press Ctrl+C to finish recording.\n Recording... "
// Wait until the interrupt signal is sent.
recorder.Stop();
std::cout << "\nRecording finished!" << std::endl;
}

Walkthrough

The Recorder.hh header contains all the recording functionality. Make sure that is included in your source code.

gz::transport::log::Recorder recorder;
// Record all topics
const int64_t addTopicResult = recorder.AddTopic(std::regex(".*"));
if (addTopicResult < 0)
{
std::cerr << "An error occurred when trying to add topics: "
<< addTopicResult << "\n";
return -1;
}

The next step requires instantiation of a log::Recorder object and specification of the topics that we're interested in logging. The AddTopic() function accepts a regular expression to set the appropriate topic filter. In our example, we are recording all topics.

// Begin recording, saving received messages to the given file
const auto result = recorder.Start(argv[1]);

The Start() method starts recording messages. Note that the function accepts a parameter with the name of the log file.

// Wait until the interrupt signal is sent.
recorder.Stop();

In our example, we are logging messages until the user hits CTRL-C. The function gz::transport::waitForShutdown() captures the appropriate signal and blocks the execution until that event occurs. Then, recorder.Stop() stops the log recording as expected.

Play back

Download the playback.cc file within the ign_transport_tutorial folder and open it with your favorite editor:

#include <cstdint>
#include <iostream>
#include <regex>
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " INPUT.tlog\n";
return -1;
}
gz::transport::log::Playback player(argv[1]);
// Playback all topics
const int64_t addTopicResult = player.AddTopic(std::regex(".*"));
if (addTopicResult == 0)
{
std::cout << "No topics to play back\n";
return 0;
}
else if (addTopicResult < 0)
{
std::cerr << "Failed to advertise topics: " << addTopicResult
<< "\n";
return -1;
}
// Begin playback
const auto handle = player.Start();
if (!handle)
{
std::cerr << "Failed to start playback\n";
return -2;
}
// Wait until the player stops on its own
std::cout << "Playing all messages in the log file\n";
handle->WaitUntilFinished();
}

Walkthrough

The Playback.hh header contains all the log play back functionality. Make sure that is included in your source code.

gz::transport::log::Playback player(argv[1]);
// Playback all topics
const int64_t addTopicResult = player.AddTopic(std::regex(".*"));
}

The next step requires to instantiate a log::Playback object and to specify the path to the file containing the log. The AddTopic() function accepts a regular expression to set the appropriate topic filter. In our example, we are playing back all messages.

const auto handle = player.Start();

The Start() method starts message playback. Note that this is an asynchronous function, the messages will be published without blocking the current thread.

handle->WaitUntilFinished();

In this example we are not interested in doing anything else, besides playing back messages. Therefore, we can use WaitUntilFinished() to block the current thread until all messages have been published.

Building the code

Download the CMakeLists.txt file within the ign_transport_tutorial folder.

Once you have all your files, go ahead and create a build/ directory within the ign_transport_tutorial directory.

mkdir build
cd build

Run cmake and build the code.

cmake ..
make

Running the examples

Open two new terminals and from your build/ directory run the recorder.

From terminal 1:

./log_record tutorial.tlog
Press Ctrl+C to finish recording.
Recording...

From terminal 2, publish a message using ign:

ign topic -t /foo -m ignition.msgs.StringMsg -p 'data:"Hello log"'

From terminal 1, hit CTRL-C in your recorder terminal to stop the recording.

Moving back to terminal 2, run a subscriber:

ign topic -t /foo -e

And from terminal 1, playback your log file:

./log_playback tutorial.tlog

You should receive one message in terminal 2:

data: "Hello log"

Using <tt>ign</tt> for recording and playing back

As an alternative to the C++ API, we could use the ign suite of command line tools for recording and playing back messages.

Next is how you can record a set of messages using ign:

ign log record --force --file tutorial.tlog

And here's how you can play back the previous log file using ign:

ign log playback --file tutorial.tlog

For further options, try running:

ign log record -h

and

ign log playback -h
void waitForShutdown()
Block the current thread until a SIGINT or SIGTERM is received. Note that this function registers a s...
T endl(T... args)