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

Analytics: register SDK language and data source #1371

Merged
merged 14 commits into from
Feb 22, 2023
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions crates/re_analytics/src/config_web.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::todo, clippy::unused_self)]

use std::collections::HashMap;

use uuid::Uuid;
Expand Down
6 changes: 6 additions & 0 deletions crates/re_analytics/src/pipeline_web.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#![allow(
clippy::needless_pass_by_value,
clippy::unnecessary_wraps,
clippy::unused_self
)]

use std::time::Duration;

use crate::{Config, Event, PostHogSink};
Expand Down
1 change: 1 addition & 0 deletions crates/re_data_store/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ serde = ["dep:serde", "re_log_types/serde"]
re_arrow_store.workspace = true
re_log_types.workspace = true
re_log.workspace = true
re_smart_channel.workspace = true
re_string_interner.workspace = true

ahash = "0.8"
Expand Down
5 changes: 5 additions & 0 deletions crates/re_data_store/src/log_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ pub struct LogDb {
/// that are created after they were logged.
timeless_message_ids: Vec<MsgId>,

/// Set by whomever created this [`LogDb`].
pub data_source: Option<re_smart_channel::Source>,

/// Comes in a special message, [`LogMsg::BeginRecordingMsg`].
recording_info: Option<RecordingInfo>,

/// Where we store the entities.
Expand Down Expand Up @@ -266,6 +270,7 @@ impl LogDb {
chronological_message_ids,
log_messages,
timeless_message_ids,
data_source: _,
recording_info: _,
entity_db,
} = self;
Expand Down
2 changes: 1 addition & 1 deletion crates/re_log_types/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ fn test_encode_decode() {
recording_id: crate::RecordingId::random(),
is_official_example: true,
started: Time::now(),
recording_source: crate::RecordingSource::PythonSdk,
recording_source: crate::RecordingSource::RustSdk,
},
})];

Expand Down
39 changes: 37 additions & 2 deletions crates/re_log_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,44 @@ pub struct RecordingInfo {
pub recording_source: RecordingSource,
}

#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct PythonVersion {
/// e.g. 3
pub major: u8,

/// e.g. 11
pub minor: u8,

/// e.g. 0
pub patch: u8,

/// e.g. `a0` for alpha releases.
pub suffix: String,
}

impl std::fmt::Display for PythonVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self {
major,
minor,
patch,
suffix,
} = self;
write!(f, "{}.{}.{}{}", major, minor, patch, suffix)
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum RecordingSource {
Unknown,

/// The official Rerun Python Logging SDK
PythonSdk,
PythonSdk(PythonVersion),

/// The official Rerun Rust Logging SDK
RustSdk,

/// Perhaps from some manual data ingestion?
Other(String),
Expand All @@ -229,7 +262,9 @@ pub enum RecordingSource {
impl std::fmt::Display for RecordingSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::PythonSdk => "Python SDK".fmt(f),
Self::Unknown => "Unknown".fmt(f),
Self::PythonSdk(version) => write!(f, "Python {version} SDK"),
Self::RustSdk => "Rust SDK".fmt(f),
Self::Other(string) => format!("{string:?}").fmt(f), // put it in quotes
}
}
Expand Down
31 changes: 27 additions & 4 deletions crates/re_sdk/src/session.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::net::SocketAddr;

use re_log_types::{
ApplicationId, BeginRecordingMsg, LogMsg, MsgId, PathOp, RecordingId, RecordingInfo, Time,
TimePoint,
ApplicationId, BeginRecordingMsg, LogMsg, MsgId, PathOp, RecordingId, RecordingInfo,
RecordingSource, Time, TimePoint,
};

/// This is the main object you need to create to use the Rerun SDK.
Expand All @@ -14,6 +14,8 @@ pub struct Session {
/// If not, all calls into it are ignored!
enabled: bool,

recording_source: RecordingSource,

#[cfg(feature = "web")]
tokio_rt: tokio::runtime::Runtime,

Expand Down Expand Up @@ -101,6 +103,8 @@ impl Session {
Self {
enabled,

recording_source: RecordingSource::RustSdk,

#[cfg(feature = "web")]
tokio_rt: tokio::runtime::Runtime::new().unwrap(),

Expand Down Expand Up @@ -157,6 +161,12 @@ impl Session {
}
}

/// Set where the recording is coming from.
/// The default is [`RecordingSource::RustSdk`].
pub fn set_recording_source(&mut self, recording_source: RecordingSource) {
self.recording_source = recording_source;
}

/// Send log data to a remote server.
///
/// Send all currently buffered messages.
Expand Down Expand Up @@ -317,7 +327,7 @@ impl Session {
recording_id,
is_official_example: self.is_official_example.unwrap_or_default(),
started: Time::now(),
recording_source: re_log_types::RecordingSource::PythonSdk,
recording_source: self.recording_source.clone(),
},
}
.into(),
Expand Down Expand Up @@ -384,6 +394,17 @@ impl Session {

#[cfg(feature = "re_viewer")]
impl Session {
fn app_env(&self) -> re_viewer::AppEnvironment {
match &self.recording_source {
RecordingSource::PythonSdk(python_version) => {
re_viewer::AppEnvironment::PythonSdk(python_version.clone())
}
RecordingSource::Unknown | RecordingSource::RustSdk | RecordingSource::Other(_) => {
re_viewer::AppEnvironment::RustSdk
}
}
}

/// Drains all pending log messages and starts a Rerun viewer to visualize everything that has
/// been logged so far.
pub fn show(&mut self) -> re_viewer::external::eframe::Result<()> {
Expand All @@ -394,7 +415,7 @@ impl Session {

let log_messages = self.drain_log_messages_buffer();
let startup_options = re_viewer::StartupOptions::default();
re_viewer::run_native_viewer_with_messages(startup_options, log_messages)
re_viewer::run_native_viewer_with_messages(self.app_env(), startup_options, log_messages)
}

/// Starts a Rerun viewer on the current thread and migrates the given callback, along with
Expand Down Expand Up @@ -426,6 +447,7 @@ impl Session {
}

self.sender = Sender::NativeViewer(tx);
let app_env = self.app_env();

// NOTE: Forget the handle on purpose, leave that thread be.
_ = std::thread::spawn(move || run(self));
Expand All @@ -437,6 +459,7 @@ impl Session {
let rx = re_viewer::wake_up_ui_thread_on_each_msg(rx, cc.egui_ctx.clone());
let startup_options = re_viewer::StartupOptions::default();
Box::new(re_viewer::App::from_receiver(
app_env,
startup_options,
re_ui,
cc.storage,
Expand Down
55 changes: 28 additions & 27 deletions crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,20 +95,11 @@ pub struct App {
impl App {
/// Create a viewer that receives new log messages over time
pub fn from_receiver(
app_env: crate::AppEnvironment,
startup_options: StartupOptions,
re_ui: re_ui::ReUi,
storage: Option<&dyn eframe::Storage>,
rx: Receiver<LogMsg>,
) -> Self {
Self::new(startup_options, re_ui, storage, rx, Default::default())
}

fn new(
startup_options: StartupOptions,
re_ui: re_ui::ReUi,
storage: Option<&dyn eframe::Storage>,
rx: Receiver<LogMsg>,
log_db: LogDb,
) -> Self {
#[cfg(not(target_arch = "wasm32"))]
let ctrl_c = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
Expand All @@ -128,25 +119,19 @@ impl App {
.expect("Error setting Ctrl-C handler");
}

let mut state: AppState = storage
let state: AppState = storage
.and_then(|storage| eframe::get_value(storage, eframe::APP_KEY))
.unwrap_or_default();

let mut log_dbs = IntMap::default();
if !log_db.is_empty() {
state.selected_rec_id = log_db.recording_id();
log_dbs.insert(log_db.recording_id(), log_db);
}

let analytics = ViewerAnalytics::new();
analytics.on_viewer_started();
let mut analytics = ViewerAnalytics::new();
analytics.on_viewer_started(app_env);

Self {
startup_options,
re_ui,
component_ui_registry: Default::default(),
rx,
log_dbs,
log_dbs: Default::default(),
state,
#[cfg(not(target_arch = "wasm32"))]
ctrl_c,
Expand Down Expand Up @@ -609,18 +594,31 @@ impl App {
let start = instant::Instant::now();

while let Ok(msg) = self.rx.try_recv() {
if let LogMsg::BeginRecordingMsg(msg) = &msg {
re_log::debug!("Beginning a new recording: {:?}", msg.info);
let is_new_recording = if let LogMsg::BeginRecordingMsg(msg) = &msg {
re_log::debug!("Opening a new recording: {:?}", msg.info);
self.state.selected_rec_id = msg.info.recording_id;

self.analytics.on_new_recording(msg);
}
true
} else {
false
};

let log_db = self.log_dbs.entry(self.state.selected_rec_id).or_default();

if log_db.data_source.is_none() {
log_db.data_source = Some(self.rx.source().clone());
}

if let Err(err) = log_db.add(msg) {
re_log::error!("Failed to add incoming msg: {err}");
};

if is_new_recording {
// Do analytics after ingesting the new message,
// because thats when the `log_db.recording_info` is set,
// which we use in the analytics call.
self.analytics.on_open_recording(log_db);
}

if start.elapsed() > instant::Duration::from_millis(10) {
egui_ctx.request_repaint(); // make sure we keep receiving messages asap
break; // don't block the main thread for too long
Expand Down Expand Up @@ -746,6 +744,7 @@ impl App {
}

fn show_log_db(&mut self, log_db: LogDb) {
self.analytics.on_open_recording(&log_db);
self.state.selected_rec_id = log_db.recording_id();
self.log_dbs.insert(log_db.recording_id(), log_db);
}
Expand Down Expand Up @@ -1622,8 +1621,9 @@ fn load_file_path(path: &std::path::Path) -> Option<LogDb> {
re_log::info!("Loading {path:?}…");

match load_file_path_impl(path) {
Ok(new_log_db) => {
Ok(mut new_log_db) => {
re_log::info!("Loaded {path:?}");
new_log_db.data_source = Some(re_smart_channel::Source::File { path: path.into() });
Some(new_log_db)
}
Err(err) => {
Expand All @@ -1641,8 +1641,9 @@ fn load_file_path(path: &std::path::Path) -> Option<LogDb> {
#[must_use]
fn load_file_contents(name: &str, read: impl std::io::Read) -> Option<LogDb> {
match load_rrd_to_log_db(read) {
Ok(log_db) => {
Ok(mut log_db) => {
re_log::info!("Loaded {name:?}");
log_db.data_source = Some(re_smart_channel::Source::File { path: name.into() });
Some(log_db)
}
Err(err) => {
Expand Down
19 changes: 19 additions & 0 deletions crates/re_viewer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod viewer_analytics;

pub use self::misc::color_map;
pub(crate) use misc::{mesh_loader, Item, TimeControl, TimeView, ViewerContext};
use re_log_types::PythonVersion;
pub(crate) use ui::{event_log_view, memory_panel, selection_panel, time_panel, UiVerbosity};

pub use app::{App, StartupOptions};
Expand Down Expand Up @@ -68,6 +69,24 @@ macro_rules! profile_scope {

// ---------------------------------------------------------------------------

/// Where is this App running in?
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AppEnvironment {
/// Created from the Rerun Python SDK.
PythonSdk(PythonVersion),

/// Created from the Rerun Rust SDK.
RustSdk,

/// Running the Rust `rerun` binary from the CLI.
RerunCli,

/// We are a web-viewer running in a browser as Wasm.
Web,
}

// ---------------------------------------------------------------------------

#[allow(dead_code)]
const APPLICATION_NAME: &str = "Rerun Viewer";

Expand Down
2 changes: 2 additions & 0 deletions crates/re_viewer/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub fn run_native_app(app_creator: AppCreator) -> eframe::Result<()> {
}

pub fn run_native_viewer_with_messages(
app_env: crate::AppEnvironment,
startup_options: crate::StartupOptions,
log_messages: Vec<LogMsg>,
) -> eframe::Result<()> {
Expand All @@ -49,6 +50,7 @@ pub fn run_native_viewer_with_messages(
}
run_native_app(Box::new(move |cc, re_ui| {
Box::new(crate::App::from_receiver(
app_env,
startup_options,
re_ui,
cc.storage,
Expand Down
Loading