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

Refactor analytics #1368

Merged
merged 10 commits into from
Feb 21, 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
12 changes: 2 additions & 10 deletions crates/re_analytics/examples/end_to_end.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,8 @@ fn main() {
tracing_subscriber::fmt::init(); // log to stdout

let mut analytics = Analytics::new(Duration::from_secs(3)).unwrap();
analytics.default_append_props_mut().extend([
(
"application_id".into(),
"end_to_end_example".to_owned().into(),
),
(
"recording_id".into(),
uuid::Uuid::new_v4().to_string().into(),
),
]);
analytics.register_append_property("application_id", "end_to_end_example".to_owned());
analytics.register_append_property("recording_id", uuid::Uuid::new_v4().to_string());

println!("any non-empty line written here will be sent as an analytics datapoint");
loop {
Expand Down
4 changes: 2 additions & 2 deletions crates/re_analytics/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub fn clear() -> Result<(), CliError> {

pub fn set(props: impl IntoIterator<Item = (String, Property)>) -> Result<(), CliError> {
let mut config = Config::load()?;
config.metadata.extend(props);
config.opt_in_metadata.extend(props);
config.save().map_err(Into::into)
}

Expand Down Expand Up @@ -82,7 +82,7 @@ const DETAILS: &str = "

What data is collected?
- The exact set of analytics events and parameters can be found here:
https://github.com/rerun-io/rerun/blob/GIT_HASH/crates/re_analytics/src/events.rs
https://github.com/rerun-io/rerun/blob/GIT_HASH/crates/re_viewer/src/viewer_analytics.rs
- We collect high level events about the usage of the Rerun Viewer. For example:
- The event 'Viewer Opened' helps us estimate how often Rerun is used.
- The event 'Data Source Connected' helps us understand if users tend to use live
Expand Down
8 changes: 6 additions & 2 deletions crates/re_analytics/src/config_native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ pub struct Config {
#[serde(skip, default = "::uuid::Uuid::new_v4")]
pub session_id: Uuid,

/// Opt-in meta-data you can set via `rerun analytics`.
///
/// For instance Rerun employees are encouraged to set `rerun analytics email`.
/// For real users, this is always empty.
#[serde(rename = "metadata", default)]
pub metadata: HashMap<String, Property>,
pub opt_in_metadata: HashMap<String, Property>,

/// The path of the config file.
#[serde(rename = "config_file_path")]
Expand Down Expand Up @@ -69,7 +73,7 @@ impl Config {
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Config {
analytics_id: Uuid::new_v4().to_string(),
analytics_enabled: true,
metadata: Default::default(),
opt_in_metadata: Default::default(),
session_id: Uuid::new_v4(),
is_first_run: true,
config_file_path: config_path,
Expand Down
44 changes: 0 additions & 44 deletions crates/re_analytics/src/events.rs

This file was deleted.

123 changes: 68 additions & 55 deletions crates/re_analytics/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,46 @@
//! Rerun's analytics SDK.
//!
//! All the event we collect analytics about can be found in [`events`].
//! We never collect any personal identifiable information, and you can always opt-out with `rerun analytics disable`.
//!
//! All the data we collect can be found in
//! <https://github.com/rerun-io/rerun/blob/latest/crates/re_viewer/src/viewer_analytics.rs>.

#[cfg(not(target_arch = "wasm32"))]
mod config_native;
#[cfg(not(target_arch = "wasm32"))]
use self::config_native::{Config, ConfigError};

#[cfg(target_arch = "wasm32")]
mod config_web;
#[cfg(target_arch = "wasm32")]
use self::config_web::{Config, ConfigError};

#[cfg(not(target_arch = "wasm32"))]
mod pipeline_native;
#[cfg(not(target_arch = "wasm32"))]
use self::pipeline_native::{Pipeline, PipelineError};

// TODO(cmc): web pipeline
#[cfg(target_arch = "wasm32")]
mod pipeline_web;
#[cfg(target_arch = "wasm32")]
use self::pipeline_web::{Pipeline, PipelineError};

#[cfg(not(target_arch = "wasm32"))]
mod sink_native;
#[cfg(not(target_arch = "wasm32"))]
use self::sink_native::{PostHogSink, SinkError};

// TODO(cmc): web sink
#[cfg(target_arch = "wasm32")]
mod sink_web;
#[cfg(target_arch = "wasm32")]
use self::sink_web::{PostHogSink, SinkError};

#[cfg(not(target_arch = "wasm32"))]
pub mod cli;

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

use std::borrow::Cow;
use std::collections::HashMap;
Expand All @@ -10,7 +50,18 @@ use std::time::Duration;
use re_log::trace;
use time::OffsetDateTime;

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

/// What target triplet (os, cpu) `re_analytics` was compiled for.
pub const TARGET_TRIPLET: &str = env!("__RERUN_TARGET_TRIPLE");

/// What git hash of the Rerun repository we were compiled in.
///
/// If we are not in the Rerun repository, this will be set
/// to the `re_analytics` crate version (`CARGO_PKG_VERSION`) instead.
pub const GIT_HASH: &str = env!("__RERUN_GIT_HASH");

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

#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum EventKind {
Expand Down Expand Up @@ -152,79 +203,41 @@ impl Analytics {
let sink = PostHogSink::default();
let pipeline = Pipeline::new(&config, tick, sink)?;

if let Some(pipeline) = pipeline.as_ref() {
pipeline.record(Event::update_metadata(config.metadata.clone()));
}

Ok(Self {
config,
default_append_props: Default::default(),
pipeline,
event_id: AtomicU64::new(1),
event_id: AtomicU64::new(1), // we skip 0 just to be explicit (zeroes can often be implicit)
})
}

pub fn config(&self) -> &Config {
&self.config
}

pub fn default_append_props_mut(&mut self) -> &mut HashMap<Cow<'static, str>, Property> {
&mut self.default_append_props
/// Register a property that will be included in all [`EventKind::Append`].
pub fn register_append_property(&mut self, name: &'static str, prop: impl Into<Property>) {
self.default_append_props.insert(name.into(), prop.into());
}

/// Record an event.
///
/// It will be extended with an `event_id` and, if this is an [`EventKind::Append`],
/// any properties registered with [`Self::register_append_property`].
pub fn record(&self, mut event: Event) {
if let Some(pipeline) = self.pipeline.as_ref() {
// Insert default props
if event.kind == EventKind::Append {
// Insert default props
event.props.extend(self.default_append_props.clone());
}

// Insert event ID
event.props.insert(
"event_id".into(),
(self.event_id.fetch_add(1, Ordering::Relaxed) as i64).into(),
);
// Insert event ID
event.props.insert(
"event_id".into(),
(self.event_id.fetch_add(1, Ordering::Relaxed) as i64).into(),
);
}

pipeline.record(event);
}
}
}

// ---

#[cfg(not(target_arch = "wasm32"))]
mod config_native;
#[cfg(not(target_arch = "wasm32"))]
use self::config_native::{Config, ConfigError};

#[cfg(target_arch = "wasm32")]
mod config_web;
#[cfg(target_arch = "wasm32")]
use self::config_web::{Config, ConfigError};

#[cfg(not(target_arch = "wasm32"))]
mod pipeline_native;
#[cfg(not(target_arch = "wasm32"))]
use self::pipeline_native::{Pipeline, PipelineError};

// TODO(cmc): web pipeline
#[cfg(target_arch = "wasm32")]
mod pipeline_web;
#[cfg(target_arch = "wasm32")]
use self::pipeline_web::{Pipeline, PipelineError};

#[cfg(not(target_arch = "wasm32"))]
mod sink_native;
#[cfg(not(target_arch = "wasm32"))]
use self::sink_native::{PostHogSink, SinkError};

// TODO(cmc): web sink
#[cfg(target_arch = "wasm32")]
mod sink_web;
#[cfg(target_arch = "wasm32")]
use self::sink_web::{PostHogSink, SinkError};

#[cfg(not(target_arch = "wasm32"))]
pub mod cli;

pub mod events;
53 changes: 5 additions & 48 deletions crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
app_icon::setup_app_icon,
misc::{AppOptions, Caches, RecordingConfig, ViewerContext},
ui::{data_ui::ComponentUiRegistry, Blueprint},
viewer_analytics::ViewerAnalytics,
};

#[cfg(not(target_arch = "wasm32"))]
Expand Down Expand Up @@ -86,10 +87,7 @@ pub struct App {
pending_commands: Vec<Command>,
cmd_palette: re_ui::CommandPalette,

// NOTE: Optional because it is possible to have the `analytics` feature flag enabled while at
// the same time opting out of analytics at run-time.
#[cfg(all(not(target_arch = "wasm32"), feature = "analytics"))]
analytics: Option<re_analytics::Analytics>,
analytics: ViewerAnalytics,

icon_status: AppIconStatus,
}
Expand Down Expand Up @@ -140,17 +138,8 @@ impl App {
log_dbs.insert(log_db.recording_id(), log_db);
}

#[cfg(all(not(target_arch = "wasm32"), feature = "analytics"))]
let analytics = match re_analytics::Analytics::new(std::time::Duration::from_secs(2)) {
Ok(analytics) => {
analytics.record(re_analytics::Event::viewer_started());
Some(analytics)
}
Err(err) => {
re_log::error!(%err, "failed to initialize analytics SDK");
None
}
};
let analytics = ViewerAnalytics::new();
analytics.on_viewer_started();

Self {
startup_options,
Expand All @@ -174,7 +163,6 @@ impl App {
pending_commands: Default::default(),
cmd_palette: Default::default(),

#[cfg(all(not(target_arch = "wasm32"), feature = "analytics"))]
analytics,

icon_status: AppIconStatus::NotSetTryAgain,
Expand Down Expand Up @@ -625,38 +613,7 @@ impl App {
re_log::debug!("Beginning a new recording: {:?}", msg.info);
self.state.selected_rec_id = msg.info.recording_id;

#[cfg(all(not(target_arch = "wasm32"), feature = "analytics"))]
if let Some(analytics) = self.analytics.as_mut() {
use re_analytics::Property;
analytics.default_append_props_mut().extend([
("application_id".into(), {
let prop: Property = msg.info.application_id.0.clone().into();
if msg.info.is_official_example {
prop
} else {
prop.hashed()
}
}),
("recording_id".into(), {
let prop: Property = msg.info.recording_id.to_string().into();
if msg.info.is_official_example {
prop
} else {
prop.hashed()
}
}),
(
"recording_source".into(),
msg.info.recording_source.to_string().into(),
),
(
"is_official_example".into(),
msg.info.is_official_example.into(),
),
]);

analytics.record(re_analytics::Event::data_source_opened());
}
self.analytics.on_new_recording(msg);
}

let log_db = self.log_dbs.entry(self.state.selected_rec_id).or_default();
Expand Down
1 change: 1 addition & 0 deletions crates/re_viewer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod math;
mod misc;
mod remote_viewer_app;
mod ui;
mod viewer_analytics;

pub use self::misc::color_map;
pub(crate) use misc::{mesh_loader, Item, TimeControl, TimeView, ViewerContext};
Expand Down
Loading