Skip to content

Commit 06211a7

Browse files
authored
feat(telemetry): add run and repo events (#6876)
### Description Adds events for repo and run.
1 parent 64b2cba commit 06211a7

File tree

12 files changed

+213
-35
lines changed

12 files changed

+213
-35
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/turborepo-ci/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,7 @@ impl Vendor {
8383
None
8484
}
8585

86-
#[allow(dead_code)]
87-
fn get_name() -> Option<&'static str> {
86+
pub fn get_name() -> Option<&'static str> {
8887
Self::infer().map(|v| v.name)
8988
}
9089

crates/turborepo-env/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ pub enum ResolvedEnvMode {
2121
Strict,
2222
}
2323

24+
impl std::fmt::Display for ResolvedEnvMode {
25+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26+
match self {
27+
ResolvedEnvMode::Loose => write!(f, "loose"),
28+
ResolvedEnvMode::Strict => write!(f, "strict"),
29+
}
30+
}
31+
}
32+
2433
#[derive(Clone, Debug, Error)]
2534
pub enum Error {
2635
#[error("Failed to parse regex: {0}")]

crates/turborepo-ffi/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ pub extern "C" fn get_package_file_hashes(buffer: Buffer) -> Buffer {
250250
};
251251
let inputs = req.inputs.as_slice();
252252
let hasher = turborepo_scm::SCM::new(&turbo_root);
253-
let response = match hasher.get_package_file_hashes(&turbo_root, &package_path, inputs) {
253+
let response = match hasher.get_package_file_hashes(&turbo_root, &package_path, inputs, None) {
254254
Ok(hashes) => {
255255
let mut to_return = HashMap::new();
256256
for (filename, hash) in hashes {

crates/turborepo-lib/src/run/mod.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use itertools::Itertools;
2222
use rayon::iter::ParallelBridge;
2323
use tracing::debug;
2424
use turborepo_analytics::{start_analytics, AnalyticsHandle, AnalyticsSender};
25-
use turborepo_api_client::{APIAuth, APIClient};
25+
use turborepo_api_client::{APIAuth, APIClient, Client};
2626
use turborepo_cache::{AsyncCache, RemoteCacheOpts};
2727
use turborepo_ci::Vendor;
2828
use turborepo_env::EnvironmentVariableMap;
@@ -32,6 +32,10 @@ use turborepo_repository::{
3232
package_json::PackageJson,
3333
};
3434
use turborepo_scm::SCM;
35+
use turborepo_telemetry::events::{
36+
generic::{DaemonInitStatus, GenericEventBuilder},
37+
repo::{RepoEventBuilder, RepoType},
38+
};
3539
use turborepo_ui::{cprint, cprintln, ColorSelector, BOLD_GREY, GREY};
3640

3741
use self::task_id::TaskName;
@@ -170,6 +174,8 @@ impl<'a> Run<'a> {
170174
let package_json_path = self.base.repo_root.join_component("package.json");
171175
let root_package_json = PackageJson::load(&package_json_path)?;
172176
let mut opts = self.opts()?;
177+
let run_telemetry = GenericEventBuilder::new();
178+
let repo_telemetry = RepoEventBuilder::new(&self.base.repo_root.to_string());
173179

174180
let config = self.base.config()?;
175181

@@ -184,16 +190,28 @@ impl<'a> Run<'a> {
184190
// value
185191
opts.cache_opts.skip_remote = !enabled;
186192
}
187-
193+
run_telemetry.track_is_linked(is_linked);
194+
// we only track the remote cache if we're linked because this defaults to
195+
// Vercel
196+
if is_linked {
197+
run_telemetry.track_remote_cache(api_client.base_url());
198+
}
188199
let _is_structured_output = opts.run_opts.graph.is_some()
189200
|| matches!(opts.run_opts.dry_run, Some(DryRunMode::Json));
190201

191202
let is_single_package = opts.run_opts.single_package;
203+
repo_telemetry.track_type(if is_single_package {
204+
RepoType::SinglePackage
205+
} else {
206+
RepoType::Monorepo
207+
});
192208

193209
let is_ci_or_not_tty = turborepo_ci::is_ci() || !std::io::stdout().is_terminal();
210+
run_telemetry.track_ci(turborepo_ci::Vendor::get_name());
194211

195212
let daemon = match (is_ci_or_not_tty, opts.run_opts.daemon) {
196213
(true, None) => {
214+
run_telemetry.track_daemon_init(DaemonInitStatus::Skipped);
197215
debug!("skipping turbod since we appear to be in a non-interactive context");
198216
None
199217
}
@@ -207,16 +225,19 @@ impl<'a> Run<'a> {
207225

208226
match connector.connect().await {
209227
Ok(client) => {
228+
run_telemetry.track_daemon_init(DaemonInitStatus::Started);
210229
debug!("running in daemon mode");
211230
Some(client)
212231
}
213232
Err(e) => {
233+
run_telemetry.track_daemon_init(DaemonInitStatus::Failed);
214234
debug!("failed to connect to daemon {e}");
215235
None
216236
}
217237
}
218238
}
219239
(_, Some(false)) => {
240+
run_telemetry.track_daemon_init(DaemonInitStatus::Disabled);
220241
debug!("skipping turbod since --no-daemon was passed");
221242
None
222243
}
@@ -236,6 +257,10 @@ impl<'a> Run<'a> {
236257
.build()
237258
.await?;
238259

260+
repo_telemetry.track_package_manager(pkg_dep_graph.package_manager().to_string());
261+
repo_telemetry.track_size(pkg_dep_graph.len());
262+
run_telemetry.track_run_type(opts.run_opts.dry_run.is_some());
263+
239264
let root_turbo_json =
240265
TurboJson::load(&self.base.repo_root, &root_package_json, is_single_package)?;
241266

@@ -366,6 +391,7 @@ impl<'a> Run<'a> {
366391
workspaces,
367392
engine.task_definitions(),
368393
&self.base.repo_root,
394+
&run_telemetry,
369395
)?;
370396

371397
if opts.run_opts.parallel {

crates/turborepo-lib/src/task_graph/visitor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ impl<'a> Visitor<'a> {
190190
EnvMode::Strict => ResolvedEnvMode::Strict,
191191
EnvMode::Loose => ResolvedEnvMode::Loose,
192192
};
193+
package_task_event.track_env_mode(&task_env_mode.to_string());
193194

194195
let dependency_set = engine.dependencies(&info).ok_or(Error::MissingDefinition)?;
195196

crates/turborepo-lib/src/task_hash.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use turborepo_cache::CacheHitMetadata;
1212
use turborepo_env::{BySource, DetailedMap, EnvironmentVariableMap, ResolvedEnvMode};
1313
use turborepo_repository::package_graph::{WorkspaceInfo, WorkspaceName};
1414
use turborepo_scm::SCM;
15-
use turborepo_telemetry::events::task::PackageTaskEventBuilder;
15+
use turborepo_telemetry::events::{
16+
generic::GenericEventBuilder, task::PackageTaskEventBuilder, EventBuilder,
17+
};
1618

1719
use crate::{
1820
engine::TaskNode,
@@ -71,6 +73,7 @@ impl PackageInputsHashes {
7173
workspaces: HashMap<&WorkspaceName, &WorkspaceInfo>,
7274
task_definitions: &HashMap<TaskId<'static>, TaskDefinition>,
7375
repo_root: &AbsoluteSystemPath,
76+
telemetry: &GenericEventBuilder,
7477
) -> Result<PackageInputsHashes, Error> {
7578
tracing::trace!(scm_manual=%scm.is_manual(), "scm running in {} mode", if scm.is_manual() { "manual" } else { "git" });
7679

@@ -91,7 +94,11 @@ impl PackageInputsHashes {
9194
Ok(def) => def,
9295
Err(err) => return Some(Err(err)),
9396
};
97+
let package_task_event =
98+
PackageTaskEventBuilder::new(task_id.package(), task_id.task())
99+
.with_parent(telemetry);
94100

101+
package_task_event.track_scm_mode(if scm.is_manual() { "manual" } else { "git" });
95102
let workspace_name = task_id.to_workspace_name();
96103

97104
let pkg = match workspaces
@@ -107,10 +114,12 @@ impl PackageInputsHashes {
107114
.parent()
108115
.unwrap_or_else(|| AnchoredSystemPath::new("").unwrap());
109116

117+
let scm_telemetry = package_task_event.child();
110118
let mut hash_object = match scm.get_package_file_hashes(
111119
repo_root,
112120
package_path,
113121
&task_definition.inputs,
122+
Some(scm_telemetry),
114123
) {
115124
Ok(hash_object) => hash_object,
116125
Err(err) => return Some(Err(err.into())),

crates/turborepo-scm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ sha1 = "0.10.5"
2121
thiserror = { workspace = true }
2222
tracing = { workspace = true }
2323
turbopath = { workspace = true }
24+
turborepo-telemetry = { path = "../turborepo-telemetry" }
2425
wax = { workspace = true }
2526
which = { workspace = true }
2627

crates/turborepo-scm/src/package_deps.rs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::collections::HashMap;
33
use itertools::{Either, Itertools};
44
use tracing::debug;
55
use turbopath::{AbsoluteSystemPath, AnchoredSystemPath, PathError, RelativeUnixPathBuf};
6+
use turborepo_telemetry::events::task::{FileHashMethod, PackageTaskEventBuilder};
67

78
use crate::{hash_object::hash_objects, Error, Git, SCM};
89

@@ -28,26 +29,44 @@ impl SCM {
2829
turbo_root: &AbsoluteSystemPath,
2930
package_path: &AnchoredSystemPath,
3031
inputs: &[S],
32+
telemetry: Option<PackageTaskEventBuilder>,
3133
) -> Result<GitHashes, Error> {
3234
match self {
33-
SCM::Manual => crate::manual::get_package_file_hashes_from_processing_gitignore(
34-
turbo_root,
35-
package_path,
36-
inputs,
37-
),
38-
SCM::Git(git) => git
39-
.get_package_file_hashes(turbo_root, package_path, inputs)
40-
.or_else(|e| {
41-
debug!(
42-
"failed to use git to hash files: {}. Falling back to manual",
43-
e
44-
);
45-
crate::manual::get_package_file_hashes_from_processing_gitignore(
46-
turbo_root,
47-
package_path,
48-
inputs,
49-
)
50-
}),
35+
SCM::Manual => {
36+
if let Some(telemetry) = telemetry {
37+
telemetry.track_file_hash_method(FileHashMethod::Manual);
38+
}
39+
crate::manual::get_package_file_hashes_from_processing_gitignore(
40+
turbo_root,
41+
package_path,
42+
inputs,
43+
)
44+
}
45+
SCM::Git(git) => {
46+
let result = git.get_package_file_hashes(turbo_root, package_path, inputs);
47+
match result {
48+
Ok(hashes) => {
49+
if let Some(telemetry) = telemetry {
50+
telemetry.track_file_hash_method(FileHashMethod::Git);
51+
}
52+
Ok(hashes)
53+
}
54+
Err(err) => {
55+
debug!(
56+
"failed to use git to hash files: {}. Falling back to manual",
57+
err
58+
);
59+
if let Some(telemetry) = telemetry {
60+
telemetry.track_file_hash_method(FileHashMethod::Manual);
61+
}
62+
crate::manual::get_package_file_hashes_from_processing_gitignore(
63+
turbo_root,
64+
package_path,
65+
inputs,
66+
)
67+
}
68+
}
69+
}
5170
}
5271
}
5372

@@ -272,7 +291,12 @@ mod tests {
272291
repo_root.join_component(".git").remove_dir_all().unwrap();
273292
let pkg_path = repo_root.anchor(&my_pkg_dir).unwrap();
274293
let hashes = git
275-
.get_package_file_hashes::<&str>(&repo_root, &pkg_path, &[])
294+
.get_package_file_hashes::<&str>(
295+
&repo_root,
296+
&pkg_path,
297+
&[],
298+
Some(PackageTaskEventBuilder::new("my-pkg", "test")),
299+
)
276300
.unwrap();
277301
let mut expected = GitHashes::new();
278302
expected.insert(

crates/turborepo-telemetry/src/events/generic.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ use uuid::Uuid;
55
use super::{Event, EventBuilder, EventType, Identifiable};
66
use crate::{config::TelemetryConfig, telem};
77

8+
pub enum DaemonInitStatus {
9+
// skipped due to context (running in CI etc)
10+
Skipped,
11+
/// daemon was started
12+
Started,
13+
/// daemon failed to start
14+
Failed,
15+
/// daemon was manually disabled by user
16+
Disabled,
17+
}
18+
819
#[derive(Debug, Clone, Serialize, Deserialize)]
920
pub struct GenericEventBuilder {
1021
id: String,
@@ -119,4 +130,58 @@ impl GenericEventBuilder {
119130
});
120131
self
121132
}
133+
134+
// run data
135+
136+
pub fn track_is_linked(&self, is_linked: bool) -> &Self {
137+
self.track(Event {
138+
key: "is_linked".to_string(),
139+
value: if is_linked { "true" } else { "false" }.to_string(),
140+
is_sensitive: EventType::NonSensitive,
141+
});
142+
self
143+
}
144+
145+
pub fn track_remote_cache(&self, cache_url: &str) -> &Self {
146+
self.track(Event {
147+
key: "remote_cache_url".to_string(),
148+
value: cache_url.to_string(),
149+
is_sensitive: EventType::NonSensitive,
150+
});
151+
self
152+
}
153+
154+
pub fn track_ci(&self, ci: Option<&'static str>) -> &Self {
155+
if let Some(ci) = ci {
156+
self.track(Event {
157+
key: "ci".to_string(),
158+
value: ci.to_string(),
159+
is_sensitive: EventType::NonSensitive,
160+
});
161+
}
162+
self
163+
}
164+
165+
pub fn track_run_type(&self, is_dry: bool) -> &Self {
166+
self.track(Event {
167+
key: "run_type".to_string(),
168+
value: if is_dry { "dry" } else { "full" }.to_string(),
169+
is_sensitive: EventType::NonSensitive,
170+
});
171+
self
172+
}
173+
174+
pub fn track_daemon_init(&self, status: DaemonInitStatus) -> &Self {
175+
self.track(Event {
176+
key: "daemon_status".to_string(),
177+
value: match status {
178+
DaemonInitStatus::Skipped => "skipped".to_string(),
179+
DaemonInitStatus::Started => "started".to_string(),
180+
DaemonInitStatus::Failed => "failed".to_string(),
181+
DaemonInitStatus::Disabled => "disabled".to_string(),
182+
},
183+
is_sensitive: EventType::NonSensitive,
184+
});
185+
self
186+
}
122187
}

0 commit comments

Comments
 (0)