-
Notifications
You must be signed in to change notification settings - Fork 259
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: Tushar Mathur <[email protected]>
- Loading branch information
1 parent
e77b43e
commit 756a56f
Showing
9 changed files
with
499 additions
and
9 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
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
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,17 @@ | ||
[package] | ||
name = "tailcall-tracker" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
reqwest = { version = "0.11", features = ["json", "rustls-tls"] } | ||
anyhow = "1.0.82" | ||
lazy_static = "1.4.0" | ||
serde = { version = "1.0.200", features = ["derive"] } | ||
serde_json = { version = "1.0.82", features = ["preserve_order"] } | ||
machineid-rs = "1.2.4" | ||
tokio = { version = "1.0.1", features = ["rt", "time"] } | ||
tracing = "0.1.40" | ||
sysinfo = "0.30.12" |
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,52 @@ | ||
use std::env; | ||
|
||
const LONG_ENV_FILTER_VAR_NAME: &str = "TAILCALL_TRACKER"; | ||
const SHORT_ENV_FILTER_VAR_NAME: &str = "TC_TRACKER"; | ||
const VERSION: &str = match option_env!("APP_VERSION") { | ||
Some(version) => version, | ||
_ => "0.1.0-dev", | ||
}; | ||
|
||
/// Checks if tracking is enabled | ||
pub fn check_tracking() -> bool { | ||
let is_prod = !VERSION.contains("dev"); | ||
let usage_enabled = env::var(LONG_ENV_FILTER_VAR_NAME) | ||
.or(env::var(SHORT_ENV_FILTER_VAR_NAME)) | ||
.map(|v| !v.eq_ignore_ascii_case("false")) | ||
.ok(); | ||
check_tracking_inner(is_prod, usage_enabled) | ||
} | ||
|
||
fn check_tracking_inner(is_prod_build: bool, tracking_enabled: Option<bool>) -> bool { | ||
if let Some(usage_enabled) = tracking_enabled { | ||
usage_enabled | ||
} else { | ||
is_prod_build | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
#[test] | ||
fn usage_enabled_true() { | ||
assert!(check_tracking_inner(true, Some(true))); | ||
assert!(check_tracking_inner(false, Some(true))); | ||
} | ||
|
||
#[test] | ||
fn usage_enabled_false() { | ||
assert!(!check_tracking_inner(true, Some(false))); | ||
assert!(!check_tracking_inner(false, Some(false))); | ||
} | ||
|
||
#[test] | ||
fn usage_enabled_none_is_prod_true() { | ||
assert!(check_tracking_inner(true, None)); | ||
} | ||
|
||
#[test] | ||
fn usage_enabled_none_is_prod_false() { | ||
assert!(!check_tracking_inner(false, None)); | ||
} | ||
} |
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,52 @@ | ||
use machineid_rs::{Encryption, HWIDComponent, IdBuilder}; | ||
use serde::{Deserialize, Serialize}; | ||
use sysinfo::System; | ||
|
||
const PARAPHRASE: &str = "tc_key"; | ||
const DEFAULT_CLIENT_ID: &str = "<anonymous>"; | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
struct Params { | ||
cpu_cores: String, | ||
os_name: String, | ||
} | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
struct EventValue { | ||
name: String, | ||
params: Params, | ||
} | ||
|
||
impl EventValue { | ||
fn new(name: &str) -> EventValue { | ||
let sys = System::new_all(); | ||
let cores = sys.physical_core_count().unwrap_or(2).to_string(); | ||
let os_name = System::long_os_version().unwrap_or("Unknown".to_string()); | ||
EventValue { | ||
name: name.to_string(), | ||
params: Params { cpu_cores: cores, os_name }, | ||
} | ||
} | ||
} | ||
|
||
/// Event structure to be sent to GA | ||
#[derive(Debug, Serialize, Deserialize)] | ||
pub struct Event { | ||
client_id: String, | ||
events: Vec<EventValue>, | ||
} | ||
|
||
impl Event { | ||
pub fn new(name: &str) -> Self { | ||
let mut builder = IdBuilder::new(Encryption::SHA256); | ||
builder | ||
.add_component(HWIDComponent::SystemID) | ||
.add_component(HWIDComponent::CPUCores); | ||
|
||
let id = builder | ||
.build(PARAPHRASE) | ||
.unwrap_or(DEFAULT_CLIENT_ID.to_string()); | ||
|
||
Self { client_id: id, events: vec![EventValue::new(name)] } | ||
} | ||
} |
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,4 @@ | ||
mod check_tracking; | ||
mod event; | ||
mod tracker; | ||
pub use tracker::Tracker; |
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,76 @@ | ||
use reqwest::header::{HeaderName, HeaderValue}; | ||
|
||
use crate::check_tracking::check_tracking; | ||
use crate::event::Event; | ||
|
||
const API_SECRET: &str = "GVaEzXFeRkCI9YBIylbEjQ"; | ||
const MEASUREMENT_ID: &str = "G-JEP3QDWT0G"; | ||
const BASE_URL: &str = "https://www.google-analytics.com"; | ||
|
||
/// | ||
/// Base structure to track usage of the CLI application | ||
#[derive(Debug, Clone)] | ||
pub struct Tracker { | ||
base_url: String, | ||
api_secret: String, | ||
measurement_id: String, | ||
is_tracking: bool, | ||
} | ||
|
||
impl Default for Tracker { | ||
fn default() -> Self { | ||
Self { | ||
base_url: BASE_URL.to_string(), | ||
api_secret: API_SECRET.to_string(), | ||
measurement_id: MEASUREMENT_ID.to_string(), | ||
is_tracking: check_tracking(), | ||
} | ||
} | ||
} | ||
|
||
impl Tracker { | ||
/// Initializes the ping event to be sent after the provided duration | ||
pub async fn init_ping(&'static self, duration: tokio::time::Duration) { | ||
if self.is_tracking { | ||
let mut interval = tokio::time::interval(duration); | ||
tokio::task::spawn(async move { | ||
loop { | ||
interval.tick().await; | ||
let _ = self.dispatch("ping").await; | ||
} | ||
}); | ||
} | ||
} | ||
|
||
fn create_request(&self, event_name: &str) -> anyhow::Result<reqwest::Request> { | ||
let event = Event::new(event_name); | ||
tracing::debug!("Sending event: {:?}", event); | ||
let mut url = reqwest::Url::parse(self.base_url.as_str())?; | ||
url.set_path("/mp/collect"); | ||
url.query_pairs_mut() | ||
.append_pair("api_secret", self.api_secret.as_str()) | ||
.append_pair("measurement_id", self.measurement_id.as_str()); | ||
let mut request = reqwest::Request::new(reqwest::Method::POST, url); | ||
let header_name = HeaderName::from_static("content-type"); | ||
let header_value = HeaderValue::from_str("application/json")?; | ||
request.headers_mut().insert(header_name, header_value); | ||
|
||
let _ = request | ||
.body_mut() | ||
.insert(reqwest::Body::from(serde_json::to_string(&event)?)); | ||
Ok(request) | ||
} | ||
|
||
pub async fn dispatch(&'static self, name: &str) -> anyhow::Result<()> { | ||
if self.is_tracking { | ||
let request = self.create_request(name)?; | ||
let client = reqwest::Client::new(); | ||
let response = client.execute(request).await?; | ||
let status = response.status(); | ||
let text = response.text().await?; | ||
tracing::debug!("Tracker: {}, message: {:?}", status.as_str(), text); | ||
} | ||
|
||
Ok(()) | ||
} | ||
} |
756a56f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running 30s test @ http://localhost:8000/graphql
4 threads and 100 connections
432376 requests in 30.00s, 2.17GB read
Requests/sec: 14410.55
Transfer/sec: 73.96MB