Skip to content

Commit 8a1a4b0

Browse files
committed
Record one cli.command telemetry event per run
Built from the run_record the foundation change already collects, so no call site changes here: telemetry_event chooses each field from the record under its privacy rules, and telemetry_sink delivers the line (to a local file for now, through dated_jsonl). run_record::finish hands the record to telemetry.
1 parent 8a3c120 commit 8a1a4b0

9 files changed

Lines changed: 1328 additions & 5 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ that may never merge. They are not releases and are not listed here.
1919

2020
## Unreleased
2121

22+
- Each run records one `cli.command` telemetry event, appended to
23+
`~/.mapbox/.telemetry/<date>.jsonl` and kept for 7 days. Nothing is sent
24+
anywhere by default. It never touches stdout, the exit code or how long a
25+
command takes, so a script sees no difference; a CI job does find a
26+
`.mapbox/.telemetry` directory it didn't before. `MAPBOX_CLI_NO_TELEMETRY=1`
27+
turns it off.
28+
2229
- `MAPBOX_CLI_EXTRA_QUERY` appends raw query parameters to every request, in
2330
the same `k1=v1&k2=v2` shape as a URL's own query string — for an API
2431
parameter this CLI's specs don't declare a flag for.

‎README.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ Every request sends `User-Agent: mapbox-cli/<version>` and nothing else
204204
about you or your machine. `MAPBOX_CLI_NO_TELEMETRY=1` keeps even future markers
205205
out of that header.
206206

207+
Each run also appends one event to `~/.mapbox/.telemetry/<date>.jsonl`
208+
(kept for 7 days): the command's name, its options (a value only when it
209+
comes from a fixed list, otherwise just its length or size), how it ended,
210+
and how long it took — never a token, a file path or free text you typed.
211+
It stays on this machine. `MAPBOX_CLI_NO_TELEMETRY=1` turns it off.
212+
207213
### Agent skills
208214

209215
```sh

‎src/main.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ mod schema;
3333
mod skill_dest;
3434
mod spec;
3535
mod telemetry;
36+
mod telemetry_event;
37+
mod telemetry_sink;
3638
mod tilesets_cli;
3739
mod uninstall;
3840
mod update_check;

‎src/run_record.rs‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
//! the bytes on stdout, the error — and `main` calls [`finish`] once on the
55
//! way out. `set_*` functions overwrite a field, last call wins; `add_*`
66
//! functions accumulate. Nothing is written before [`finish`], which hands
7-
//! the finished [`Record`] to each consumer. There are none yet: command
8-
//! history and the telemetry event are built from it in the changes stacked
9-
//! on this one, so that neither has to touch a call site.
7+
//! the finished [`Record`] to each consumer: [`crate::telemetry_event`].
8+
//! Consumers are built from the record rather than from call sites of their
9+
//! own, so adding one touches no call site.
1010
//!
1111
//! The record holds raw facts — the command line, URLs, error messages —
1212
//! because a local diagnostic log wants them. It never leaves this process. A consumer
@@ -18,7 +18,8 @@
1818
//! nothing here can change a command's output, its exit code, or how long
1919
//! it takes to return.
2020
21-
// Read by the consumers stacked on this change; nothing reads the record yet.
21+
// Some facts are read only by consumers not in this tree yet (command
22+
// history, a diagnostic log).
2223
#![allow(dead_code)]
2324

2425
use std::ffi::OsString;
@@ -29,7 +30,7 @@ use clap::parser::ValueSource;
2930
use clap::{ArgMatches, Command};
3031

3132
use crate::spec::ServiceSpec;
32-
use crate::{auth, completion, confirm, executor, http, output, tilesets_cli};
33+
use crate::{auth, completion, confirm, executor, http, output, telemetry_event, tilesets_cli};
3334

3435
const TILESETS: &str = tilesets_cli::COMMAND;
3536

@@ -348,6 +349,7 @@ fn finish_locked(record: &mut Record, exit_code: Option<u32>) {
348349
record.finished = true;
349350
record.duration = STARTED.get().map_or(Duration::ZERO, Instant::elapsed);
350351
record.exit_code = exit_code;
352+
telemetry_event::deliver(record);
351353
}
352354

353355
fn uuid_v4(mut bytes: [u8; 16]) -> String {

‎src/telemetry.rs‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ fn arch_marker() -> String {
5151
format!("arch/{}", spelled_arch(std::env::consts::ARCH))
5252
}
5353

54+
/// The CPU architecture as the event's `env.arch` spells it.
55+
pub(crate) fn arch() -> &'static str {
56+
spelled_arch(std::env::consts::ARCH)
57+
}
58+
59+
/// Whether this run is in CI, by the same rule as the `env/ci` marker.
60+
pub(crate) fn in_ci() -> bool {
61+
ci_marker().is_some()
62+
}
63+
64+
/// For `crate::telemetry_event`, which may not reach for stdout itself.
65+
pub(crate) fn stdout_is_terminal() -> bool {
66+
std::io::stdout().is_terminal()
67+
}
68+
5469
fn spelled_arch(arch: &str) -> &str {
5570
match arch {
5671
"aarch64" => "arm64",

0 commit comments

Comments
 (0)