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

fix(2775): send metrics to posthog #2776

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
123 changes: 123 additions & 0 deletions Cargo.lock

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

8 changes: 6 additions & 2 deletions src/cli/tc/run.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::Result;
use chrono::Utc;
use clap::Parser;
use convert_case::{Case, Casing};
use dotenvy::dotenv;
Expand All @@ -22,12 +23,15 @@

// Initialize ping event every 60 seconds
let _ = TRACKER
.init_ping(tokio::time::Duration::from_secs(60))
.init_ping(tokio::time::Duration::from_secs(60), Utc::now())

Check warning on line 26 in src/cli/tc/run.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/tc/run.rs#L26

Added line #L26 was not covered by tests
.await;

// Dispatch the command as an event
let _ = TRACKER
.dispatch(cli.command.to_string().to_case(Case::Snake).as_str())
.dispatch(
cli.command.to_string().to_case(Case::Snake).as_str(),
Utc::now(),
)

Check warning on line 34 in src/cli/tc/run.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/tc/run.rs#L31-L34

Added lines #L31 - L34 were not covered by tests
.await;

run_command(cli, config_reader, runtime).await
Expand Down
5 changes: 4 additions & 1 deletion tailcall-tracker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ lazy_static = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
machineid-rs = "1.2.4"
tokio = { workspace = true }
tokio = { workspace = true, features = ["rt", "macros"] }
tracing = { workspace = true }
sysinfo = "0.31.0"
tailcall-version = { path = "../tailcall-version" }
posthog-rs = "0.2.2"
async-trait = "0.1.81"
chrono = "0.4.38"
62 changes: 62 additions & 0 deletions tailcall-tracker/src/collect/ga.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use chrono::{DateTime, Utc};
use reqwest::header::{HeaderName, HeaderValue};

use super::super::Result;
use crate::ga_event::GaEvent;
use crate::tracker::EventCollector;

const GA_TRACKER_URL: &str = "https://www.google-analytics.com";
const GA_TRACKER_API_SECRET: &str = "GVaEzXFeRkCI9YBIylbEjQ";
const GA_TRACKER_MEASUREMENT_ID: &str = "G-JEP3QDWT0G";

pub struct GaTracker {
base_url: String,
api_secret: String,
measurement_id: String,
}

impl GaTracker {
pub fn default() -> Self {
Self {
base_url: GA_TRACKER_URL.to_string(),
api_secret: GA_TRACKER_API_SECRET.to_string(),
measurement_id: GA_TRACKER_MEASUREMENT_ID.to_string(),
}
}
fn create_request(
&self,
event_name: &str,
start_time: DateTime<Utc>,
) -> Result<reqwest::Request> {
let event = GaEvent::new(event_name, start_time);
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)?));

Check warning on line 45 in tailcall-tracker/src/collect/ga.rs

View check run for this annotation

Codecov / codecov/patch

tailcall-tracker/src/collect/ga.rs#L19-L45

Added lines #L19 - L45 were not covered by tests

Ok(request)
}

Check warning on line 48 in tailcall-tracker/src/collect/ga.rs

View check run for this annotation

Codecov / codecov/patch

tailcall-tracker/src/collect/ga.rs#L47-L48

Added lines #L47 - L48 were not covered by tests
}

#[async_trait::async_trait]
impl EventCollector for GaTracker {
async fn dispatch(&self, event_name: &str, start_time: DateTime<Utc>) -> Result<()> {
let request = self.create_request(event_name, start_time)?;
let client = reqwest::Client::new();
let response = client.execute(request).await?;
let status = response.status();
let text = response.text().await?;
tracing::debug!("Collector: {}, message: {:?}", status.as_str(), text);
Ok(())
}

Check warning on line 61 in tailcall-tracker/src/collect/ga.rs

View check run for this annotation

Codecov / codecov/patch

tailcall-tracker/src/collect/ga.rs#L53-L61

Added lines #L53 - L61 were not covered by tests
}
2 changes: 2 additions & 0 deletions tailcall-tracker/src/collect/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod ga;
pub mod posthog;
beelchester marked this conversation as resolved.
Show resolved Hide resolved
43 changes: 43 additions & 0 deletions tailcall-tracker/src/collect/posthog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use chrono::{DateTime, Utc};
use tailcall_version::VERSION;

use super::super::Result;
use crate::helpers::{get_client_id, get_cpu_cores, get_os_name, get_uptime};
use crate::tracker::EventCollector;

const POSTHOG_API_KEY: &str = "phc_CWdKhSxlSsKceZhhnSJ1LfkaGxgYhZLh4Fx7ssjrkRf";

pub struct PostHogTracker {
api_secret: String,
}

impl PostHogTracker {
pub fn default() -> Self {
Self { api_secret: POSTHOG_API_KEY.to_string() }
}

Check warning on line 17 in tailcall-tracker/src/collect/posthog.rs

View check run for this annotation

Codecov / codecov/patch

tailcall-tracker/src/collect/posthog.rs#L15-L17

Added lines #L15 - L17 were not covered by tests
}

#[async_trait::async_trait]
impl EventCollector for PostHogTracker {
async fn dispatch(&self, event_name: &str, start_time: DateTime<Utc>) -> Result<()> {
let api_secret = self.api_secret.clone();
let event_name = event_name.to_string();

let handle_posthog = tokio::task::spawn_blocking(move || -> Result<()> {
let client = posthog_rs::client(api_secret.as_str());
let mut event = posthog_rs::Event::new(event_name.clone(), get_client_id());
event.insert_prop("cpu_cores", get_cpu_cores())?;
event.insert_prop("os_name", get_os_name())?;
event.insert_prop("app_version", VERSION.as_str())?;
event.insert_prop("start_time", start_time.to_string())?;
if event_name == "ping" {
event.insert_prop("uptime", get_uptime(start_time))?;
}
client.capture(event)?;
Ok(())
})
.await;
handle_posthog??;
Ok(())
}

Check warning on line 42 in tailcall-tracker/src/collect/posthog.rs

View check run for this annotation

Codecov / codecov/patch

tailcall-tracker/src/collect/posthog.rs#L22-L42

Added lines #L22 - L42 were not covered by tests
}
8 changes: 8 additions & 0 deletions tailcall-tracker/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@

#[debug(fmt = "Url Parser Error: {}", _0)]
UrlParser(url::ParseError),

#[debug(fmt = "PostHog Error: {}", _0)]
PostHog(posthog_rs::Error),

#[debug(fmt = "Tokio Join Error: {}", _0)]
TokioJoin(tokio::task::JoinError),
}

impl Display for Error {
Expand All @@ -25,6 +31,8 @@
Error::InvalidHeaderValue(error) => write!(f, "Invalid Header Value: {}", error),
Error::SerdeJson(error) => write!(f, "Serde JSON Error: {}", error),
Error::UrlParser(error) => write!(f, "Url Parser Error: {}", error),
Error::PostHog(error) => write!(f, "PostHog Error: {}", error),
Error::TokioJoin(error) => write!(f, "Tokio Join Error: {}", error),

Check warning on line 35 in tailcall-tracker/src/error.rs

View check run for this annotation

Codecov / codecov/patch

tailcall-tracker/src/error.rs#L34-L35

Added lines #L34 - L35 were not covered by tests
}
}
}
Expand Down
Loading
Loading