Recording and Replay

AstuteDDS provides DataLogTool (<astutedds/dcps/record_replay.hpp>) for capturing raw DDS payload streams to disk and replaying them later, preserving the original inter-sample timing.

Use Cases

  • System-level regression testing: Record production traffic, replay against new software versions.
  • Simulation and training: Pre-record realistic sensor feeds and replay on demand.
  • Debugging: Capture anomalous behaviour for offline analysis.
  • Interop logging: Archive DDS traffic for certification evidence.

Data Structures

struct astutedds::dcps::LoggedSample
{
    uint64_t    relative_timestamp_ns{0};  // nanoseconds since first sample
    std::string topic_name;
    std::vector<uint8_t> payload;          // raw XCDR-serialised bytes
};

Recording

Collect samples from DataReaders and build the LoggedSample list, then write them to a binary .addslog file:

#include <astutedds/dcps/record_replay.hpp>

std::vector<astutedds::dcps::LoggedSample> samples;
auto t0 = std::chrono::steady_clock::now();

// In your DataReader read/take loop:
for (auto& raw : raw_samples)
{
    auto elapsed = std::chrono::steady_clock::now() - t0;
    samples.push_back({
        static_cast<uint64_t>(
            std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count()),
        "MyTopic",
        raw.serialized_payload      // XCDR bytes from the sample info
    });
}

// Write to disk
auto rc = astutedds::dcps::DataLogTool::write_samples("capture.addslog", samples);
if (rc != astutedds::dcps::ReturnCode_t::RETCODE_OK)
    std::cerr << "Failed to write log\n";

The file format uses an ADDSRPL1 magic header and FORMAT_VERSION = 1. It is designed for forward compatibility.

Playback

Step 1 — Read the log

std::vector<astutedds::dcps::LoggedSample> samples;
auto rc = astutedds::dcps::DataLogTool::read_samples("capture.addslog", samples);
if (rc != astutedds::dcps::ReturnCode_t::RETCODE_OK)
{
    std::cerr << "Failed to read log\n";
    return 1;
}

Step 2 — Replay through a DomainParticipant

#include <astutedds/dcps/domain_participant.hpp>

auto participant = astutedds::dcps::DomainParticipantFactory::create_participant(0);

// Samples are replayed with the original inter-sample spacing preserved
auto rc = astutedds::dcps::DataLogTool::replay_samples(*participant, samples);

replay_samples() drives DomainParticipant::send_data() for each sample, sleeping between samples to honour the relative_timestamp_ns deltas. Samples must be sorted with monotonically non-decreasing timestamps; RETCODE_BAD_PARAMETER is returned otherwise.

File Size Limits

The following limits are enforced when reading log files to prevent resource exhaustion:

Limit Value
Maximum topic name 1 024 bytes
Maximum payload size 32 MiB per sample
Maximum sample count 1 000 000 samples

Combining Recording with XML QoS

Configure writers and readers from an XML profile, then record:

#include <astutedds/dcps/xml_config.hpp>
#include <astutedds/dcps/record_replay.hpp>

astutedds::dcps::XmlQosLoader loader;
loader.load_file("profiles.xml");

astutedds::dcps::DataReaderQos rqos;
loader.get_datareader_qos("MyLib::ReliableProfile", rqos);

auto reader = subscriber->create_datareader(topic, rqos);
// … record samples as above …