-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Eyal Bukchin <[email protected]>
- Loading branch information
Showing
24 changed files
with
519 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,18 @@ | ||
# Telemetry | ||
# Telemetry / Analytics | ||
|
||
mirrord sends anonymous usage statistics to our systems. The information sent is: | ||
1. mirrord version. | ||
2. cli/extension. | ||
3. platform (linux, macos). | ||
mirrord sends anonymous usage statistics to our systems. | ||
We don't store IP addresses, and we don't create any unique identifier for the user. | ||
|
||
In our databases, we don't store IP, and we don't create any unique identifier for the user. | ||
Data collected is session duration and what features were used (steal/mirror/fs mode, etc). | ||
This helps us to improve the product and by better understanding our users. | ||
Types of data sent: | ||
1. Feature on/off | ||
2. Feature enum value (steal/mirror, read/write) | ||
3. Feature count (how many ports in listen_ports) | ||
|
||
## Disabling | ||
|
||
### CLI | ||
You can disable telemetry by specifying `--no-telemetry`. | ||
|
||
### Extension | ||
In the settings of the extension. | ||
Telemetry can be disabled by specifying the following in the mirrord config file: | ||
```json | ||
{"telemetry": false} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Added new analytics, see TELEMETRY.md for more details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
[package] | ||
name = "mirrord-analytics" | ||
version.workspace = true | ||
authors.workspace = true | ||
description.workspace = true | ||
documentation.workspace = true | ||
readme.workspace = true | ||
homepage.workspace = true | ||
repository.workspace = true | ||
license.workspace = true | ||
keywords.workspace = true | ||
categories.workspace = true | ||
publish.workspace = true | ||
edition.workspace = true | ||
|
||
|
||
[dependencies] | ||
|
||
serde.workspace = true | ||
reqwest.workspace = true | ||
tracing.workspace = true | ||
|
||
[dev-dependencies] | ||
serde_json.workspace = true | ||
assert-json-diff = "2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
use std::collections::HashMap; | ||
|
||
use serde::{Deserialize, Serialize}; | ||
use tracing::info; | ||
|
||
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION"); | ||
|
||
/// Possible values for analytic data | ||
/// This is strict so we won't send sensitive data by accident. | ||
/// (Don't add strings) | ||
#[derive(Debug, Serialize, Deserialize)] | ||
#[serde(untagged)] | ||
pub enum AnalyticValue { | ||
Bool(bool), | ||
Number(u32), | ||
Nested(Analytics), | ||
} | ||
|
||
/// Struct to store analytics data. | ||
/// Example usage that would output the following json | ||
/// ```json | ||
/// { | ||
/// "a": true, | ||
/// "b": false, | ||
/// "c": 3, | ||
/// "extra": { | ||
/// "d": true, | ||
/// "e": true | ||
/// } | ||
/// } | ||
/// ``` | ||
/// ``` | ||
/// use mirrord_analytics::{Analytics, CollectAnalytics}; | ||
/// let mut analytics = Analytics::default(); | ||
/// analytics.add("a", true); | ||
/// analytics.add("b", false); | ||
/// analytics.add("c", 3); | ||
/// | ||
/// struct A {} | ||
/// impl CollectAnalytics for A { | ||
/// fn collect_analytics(&self, analytics: &mut Analytics) { | ||
/// analytics.add("d", true); | ||
/// } | ||
/// } | ||
/// | ||
/// struct B {} | ||
/// impl CollectAnalytics for B { | ||
/// fn collect_analytics(&self, analytics: &mut Analytics) { | ||
/// let a = A {}; | ||
/// a.collect_analytics(analytics); | ||
/// analytics.add("e", true); | ||
/// } | ||
/// } | ||
/// let b = B {}; | ||
/// analytics.add("extra", b); | ||
/// ``` | ||
#[derive(Debug, Default, Serialize, Deserialize)] | ||
pub struct Analytics { | ||
#[serde(flatten)] | ||
data: HashMap<String, AnalyticValue>, | ||
} | ||
|
||
impl Analytics { | ||
pub fn add<Key: ToString, Value: Into<AnalyticValue>>(&mut self, key: Key, value: Value) { | ||
self.data.insert(key.to_string(), value.into()); | ||
} | ||
} | ||
|
||
/// Structs that collect analytics about themselves should implement this trait | ||
pub trait CollectAnalytics { | ||
/// Write analytics data to the given `Analytics` struct | ||
fn collect_analytics(&self, analytics: &mut Analytics); | ||
} | ||
|
||
impl From<bool> for AnalyticValue { | ||
fn from(b: bool) -> Self { | ||
AnalyticValue::Bool(b) | ||
} | ||
} | ||
|
||
impl From<u32> for AnalyticValue { | ||
fn from(n: u32) -> Self { | ||
AnalyticValue::Number(n) | ||
} | ||
} | ||
|
||
impl From<usize> for AnalyticValue { | ||
fn from(n: usize) -> Self { | ||
AnalyticValue::Number(u32::try_from(n).unwrap_or(u32::MAX)) | ||
} | ||
} | ||
|
||
impl From<Analytics> for AnalyticValue { | ||
fn from(analytics: Analytics) -> Self { | ||
AnalyticValue::Nested(analytics) | ||
} | ||
} | ||
|
||
impl<T: CollectAnalytics> From<T> for AnalyticValue { | ||
fn from(other: T) -> Self { | ||
let mut analytics = Analytics::default(); | ||
other.collect_analytics(&mut analytics); | ||
analytics.into() | ||
} | ||
} | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
struct AnalyticsReport { | ||
event_properties: Analytics, | ||
platform: String, | ||
duration: u32, | ||
version: String, | ||
operator: bool, | ||
} | ||
|
||
pub async fn send_analytics(analytics: Analytics, duration: u32, operator: bool) { | ||
let report = AnalyticsReport { | ||
event_properties: analytics, | ||
platform: std::env::consts::OS.to_string(), | ||
version: CURRENT_VERSION.to_string(), | ||
duration, | ||
operator, | ||
}; | ||
|
||
let client = reqwest::Client::new(); | ||
let res = client | ||
.post("https://analytics.metalbear.co/api/v1/event") | ||
.json(&report) | ||
.send() | ||
.await; | ||
if let Err(e) = res { | ||
info!("Failed to send analytics: {e}"); | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use assert_json_diff::assert_json_eq; | ||
use serde_json::json; | ||
|
||
use super::*; | ||
/// this tests creates a struct that is flatten and one that is nested | ||
/// serializes it and verifies it's correct | ||
#[test] | ||
fn happy_flow() { | ||
let mut analytics = Analytics::default(); | ||
analytics.add("a", true); | ||
analytics.add("b", false); | ||
analytics.add("c", 3); | ||
|
||
struct A {} | ||
impl CollectAnalytics for A { | ||
fn collect_analytics(&self, analytics: &mut Analytics) { | ||
analytics.add("d", true); | ||
} | ||
} | ||
|
||
struct B {} | ||
impl CollectAnalytics for B { | ||
fn collect_analytics(&self, analytics: &mut Analytics) { | ||
let a = A {}; | ||
a.collect_analytics(analytics); | ||
analytics.add("e", true); | ||
} | ||
} | ||
let b = B {}; | ||
analytics.add("extra", b); | ||
|
||
assert_json_eq!( | ||
analytics, | ||
json!({ | ||
"a": true, | ||
"b": false, | ||
"c": 3, | ||
"extra": { | ||
"d": true, | ||
"e": true | ||
} | ||
}) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.