Gazebo Transport

API Reference

12.2.2
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.

Gazebo Transport provides two mechanisms for logging: a C++ API and a set of command line utilities as part of the optional gz CLI tool (available via Gazebo 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 ~/gz_transport_tutorial
cd ~/gz_transport_tutorial

Record

Download the record.cc file within the gz_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;
}
// 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]);
{
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.

// 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 gz_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;
}
// 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.

// 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 gz_transport_tutorial folder.

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

mkdir build
cd build

Run cmake and build the code.

# Linux and MacOS
cmake ..
make
# Windows
cmake --build . --config Release

Running the examples

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

From terminal 1:

# Linux and MacOS
./log_record tutorial.tlog
# Windows
.\Release\log_record.exe tutorial.tlog
Press Ctrl+C to finish recording.
Recording...

From terminal 2, publish a message using gz:

gz topic -t /foo -m gz.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:

gz topic -t /foo -e

And from terminal 1, playback your log file:

# Linux and MacOS
./log_playback tutorial.tlog
# Windows
.\Release\log_playback.exe tutorial.tlog

You should receive one message in terminal 2:

data: "Hello log"

Using gz for recording and playing back

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

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

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

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

gz log playback --file tutorial.tlog

For further options, try running:

gz log record -h

and

gz log playback -h