Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared recordings 2: exposing recording_id in C and C++ SDKs #4384

Merged
merged 7 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions crates/re_sdk/src/recording_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,23 @@ impl RecordingStreamBuilder {
self
}

/// Set the `RecordingId` for this context.
///
/// If you're logging from multiple processes and want all the messages to end up in the same
/// recording, you must make sure that they all set the same `RecordingId` using this function.
///
/// Note that many stores can share the same [`ApplicationId`], but they all have
/// unique `RecordingId`s.
///
/// The default is to use a random `RecordingId`.
pub fn recording_id(mut self, recording_id: impl Into<String>) -> Self {
self.store_id = Some(StoreId::from_string(
StoreKind::Recording,
recording_id.into(),
));
self
}

/// Set the [`StoreId`] for this context.
///
/// If you're logging from multiple processes and want all the messages to end up as the same
Expand Down
12 changes: 12 additions & 0 deletions crates/rerun_c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ pub struct CStoreInfo {
/// The user-chosen name of the application doing the logging.
pub application_id: CStringView,

/// The user-chosen name of the recording being logged to.
///
/// Defaults to a random ID if unspecified.
pub recording_id: CStringView,

pub store_kind: CStoreKind,
}

Expand Down Expand Up @@ -258,6 +263,7 @@ fn rr_recording_stream_new_impl(

let CStoreInfo {
application_id,
recording_id,
store_kind,
} = *store_info;

Expand All @@ -269,6 +275,12 @@ fn rr_recording_stream_new_impl(
.store_source(re_log_types::StoreSource::CSdk)
.default_enabled(default_enabled);

if !(recording_id.is_null() || recording_id.is_empty()) {
teh-cmc marked this conversation as resolved.
Show resolved Hide resolved
if let Ok(recording_id) = recording_id.as_str("recording_id") {
rec_builder = rec_builder.recording_id(recording_id);
}
}

if store_kind == CStoreKind::Blueprint {
rec_builder = rec_builder.blueprint();
}
Expand Down
5 changes: 5 additions & 0 deletions crates/rerun_c/src/rerun.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ typedef struct rr_store_info {
/// The user-chosen name of the application doing the logging.
rr_string application_id;

/// The user-chosen name of the recording being logged to.
///
/// Defaults to a random ID if unspecified.
rr_string recording_id;

/// `RR_STORE_KIND_RECORDING` or `RR_STORE_KIND_BLUEPRINT`
rr_store_kind store_kind;
} rr_store_info;
Expand Down
1 change: 1 addition & 0 deletions examples/c/minimal/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ int main(void) {
rr_error error = {0};
const rr_store_info store_info = {
.application_id = rr_make_string("c-example-app"),
.recording_id = rr_make_string(NULL),
.store_kind = RR_STORE_KIND_RECORDING,
};
rr_recording_stream rec = rr_recording_stream_new(&store_info, true, &error);
Expand Down
7 changes: 5 additions & 2 deletions examples/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
add_subdirectory(clock)
add_subdirectory(custom_collection_adapter)
add_subdirectory(dna)
add_subdirectory(shared_recording)
add_subdirectory(minimal)
add_subdirectory(spawn_viewer)
add_subdirectory(custom_collection_adapter)

add_custom_target(examples)

add_dependencies(examples example_clock)
add_dependencies(examples example_custom_collection_adapter)
add_dependencies(examples example_dna)
add_dependencies(examples example_shared_recording)
add_dependencies(examples example_minimal)
add_dependencies(examples example_spawn_viewer)
add_dependencies(examples example_custom_collection_adapter)
32 changes: 32 additions & 0 deletions examples/cpp/shared_recording/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.16...3.27)

# If you use the example outside of the Rerun SDK you need to specify
# where the rerun_c build is to be found by setting the `RERUN_CPP_URL` variable.
# This can be done by passing `-DRERUN_CPP_URL=<path to rerun_sdk_cpp zip>` to cmake.
if(DEFINED RERUN_REPOSITORY)
add_executable(example_shared_recording main.cpp)
rerun_strict_warning_settings(example_shared_recording)
else()
project(example_shared_recording LANGUAGES CXX)

add_executable(example_shared_recording main.cpp)

# Set the path to the rerun_c build.
set(RERUN_CPP_URL "https://github.com/rerun-io/rerun/releases/latest/download/rerun_cpp_sdk.zip" CACHE STRING "URL to the rerun_cpp zip.")
option(RERUN_FIND_PACKAGE "Whether to use find_package to find a preinstalled rerun package (instead of using FetchContent)." OFF)

if(RERUN_FIND_PACKAGE)
find_package(rerun_sdk REQUIRED)
else()
# Download the rerun_sdk
include(FetchContent)
FetchContent_Declare(rerun_sdk URL ${RERUN_CPP_URL})
FetchContent_MakeAvailable(rerun_sdk)
endif()

# Rerun requires at least C++17, but it should be compatible with newer versions.
set_property(TARGET example_shared_recording PROPERTY CXX_STANDARD 17)
endif()

# Link against rerun_sdk.
target_link_libraries(example_shared_recording PRIVATE rerun_sdk)
26 changes: 26 additions & 0 deletions examples/cpp/shared_recording/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: Shared Recording
rust: https://github.com/rerun-io/rerun/tree/latest/examples/rust/shared_recording/src/main.rs?speculative-link
cpp: https://github.com/rerun-io/rerun/tree/latest/examples/cpp/shared_recording/main.cpp?speculative-link
---

<picture>
<img src="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/full.png" alt="">
<source media="(max-width: 480px)" srcset="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/480w.png">
<source media="(max-width: 768px)" srcset="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/768w.png">
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/1024w.png">
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/1200w.png">
</picture>

This example demonstrates how to use `RecordingId`s to create a single shared recording across multiple processes.

To build it from a checkout of the repository (requires a Rust toolchain):
```bash
cmake .
cmake --build . --target example_shared_recording
```

Run the following multiple times, and you'll see that each invocation adds data to the existing recording rather than creating a new one:
```bash
./examples/cpp/shared_recording/example_shared_recording
```
24 changes: 24 additions & 0 deletions examples/cpp/shared_recording/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <iostream>
#include <sstream>

#if defined(WIN32)
#include <process.h>
#define getpid _getpid
#else
#include <unistd.h>
#endif

#include <rerun.hpp>
#include <rerun/demo_utils.hpp>

using rerun::demo::grid3d;

int main() {
const auto rec =
rerun::RecordingStream("rerun_example_shared_recording", "my_shared_recording");
rec.spawn().exit_on_failure();

rec.log("updates", rerun::TextLog(std::string("Hello from ") + std::to_string(getpid())));

std::cout << "Run me again to append more data to the recording!" << std::endl;
}
10 changes: 10 additions & 0 deletions examples/rust/shared_recording/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "shared_recording"
version = "0.12.0-alpha.1+dev"
edition = "2021"
rust-version = "1.72"
license = "MIT OR Apache-2.0"
publish = false

[dependencies]
rerun = { path = "../../../crates/rerun" }
19 changes: 19 additions & 0 deletions examples/rust/shared_recording/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: Shared Recording
rust: https://github.com/rerun-io/rerun/tree/latest/examples/python/shared_recording/main.py?speculative-link
---

<picture>
<img src="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/full.png" alt="">
<source media="(max-width: 480px)" srcset="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/480w.png">
<source media="(max-width: 768px)" srcset="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/768w.png">
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/1024w.png">
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/shared_recording/c3da85f1d4c158b8c7afb6bd3278db000b58049d/1200w.png">
</picture>

This example demonstrates how to use `RecordingId`s to create a single shared recording across multiple processes.

Run the following multiple times, and you'll see that each invocation adds data to the existing recording rather than creating a new one:
```bash
cargo run
```
14 changes: 14 additions & 0 deletions examples/rust/shared_recording/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Demonstrates how to use `RecordingId`s to build a single recording from multiple processes.

fn main() -> Result<(), Box<dyn std::error::Error>> {
let rec = rerun::RecordingStreamBuilder::new("rerun_example_shared_recording")
.recording_id("my_shared_recording")
.spawn()?;

rec.log(
"updates",
&rerun::TextLog::new(format!("hello from process #{}", std::process::id())),
)?;

Ok(())
}
5 changes: 5 additions & 0 deletions rerun_cpp/src/rerun/c/rerun.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion rerun_cpp/src/rerun/recording_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ namespace rerun {
return RR_STORE_KIND_RECORDING;
}

RecordingStream::RecordingStream(std::string_view app_id, StoreKind store_kind)
RecordingStream::RecordingStream(
std::string_view app_id, std::string_view recording_id, StoreKind store_kind
)
: _store_kind(store_kind) {
check_binary_and_header_version_match().handle();

rr_store_info store_info;
store_info.application_id = detail::to_rr_string(app_id);
store_info.recording_id = detail::to_rr_string(recording_id);
store_info.store_kind = store_kind_to_c(store_kind);

rr_error status = {};
Expand Down
6 changes: 5 additions & 1 deletion rerun_cpp/src/rerun/recording_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,12 @@ namespace rerun {
/// Creates a new recording stream to log to.
///
/// \param app_id The user-chosen name of the application doing the logging.
/// \param recording_id The user-chosen name of the recording being logged to.
/// \param store_kind Whether to log to the recording store or the blueprint store.
RecordingStream(std::string_view app_id, StoreKind store_kind = StoreKind::Recording);
RecordingStream(
std::string_view app_id, std::string_view recording_id = std::string_view(),
StoreKind store_kind = StoreKind::Recording
);
~RecordingStream();

/// \private
Expand Down
9 changes: 5 additions & 4 deletions rerun_cpp/tests/recording_stream.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <array>
#include <filesystem>
#include <optional>
#include <vector>

#include <arrow/buffer.h>
Expand Down Expand Up @@ -73,7 +74,7 @@ SCENARIO("RecordingStream can be created, destroyed and lists correct properties
AND_GIVEN("a valid application id") {
THEN("creating a new stream does not log an error") {
rerun::RecordingStream stream = check_logged_error([&] {
return rerun::RecordingStream("rerun_example_test", kind);
return rerun::RecordingStream("rerun_example_test", std::string_view(), kind);
});

AND_THEN("it does not crash on destruction") {}
Expand All @@ -99,7 +100,7 @@ SCENARIO("RecordingStream can be created, destroyed and lists correct properties
AND_GIVEN("invalid utf8 character sequence for the application id") {
THEN("creating a new stream logs an invalid string argument error") {
check_logged_error(
[&] { rerun::RecordingStream stream("\xc3\x28", kind); },
[&] { rerun::RecordingStream stream("\xc3\x28", std::string_view(), kind); },
rerun::ErrorCode::InvalidStringArgument
);
}
Expand All @@ -123,7 +124,7 @@ SCENARIO("RecordingStream can be set as global and thread local", TEST_TAG) {
}

WHEN("creating a new stream") {
rerun::RecordingStream stream("test", kind);
rerun::RecordingStream stream("test", std::string_view(), kind);

THEN("it can be set as global") {
stream.set_global();
Expand All @@ -146,7 +147,7 @@ SCENARIO("RecordingStream can be used for logging archetypes and components", TE
for (auto kind : std::array{rerun::StoreKind::Recording, rerun::StoreKind::Blueprint}) {
GIVEN("a store kind" << kind) {
WHEN("creating a new stream") {
rerun::RecordingStream stream("test", kind);
rerun::RecordingStream stream("test", std::string_view(), kind);

// We can make single components work, but this would make error messages a lot
// worse since we'd have to implement the base `AsComponents` template for this.
Expand Down
Loading