diff --git a/cmd/gotelemetry/doc.go b/cmd/gotelemetry/doc.go index 6956664..9630607 100644 --- a/cmd/gotelemetry/doc.go +++ b/cmd/gotelemetry/doc.go @@ -12,8 +12,9 @@ // // The commands are: // -// on enable telemetry uploading -// off disable telemetry uploading +// on enable telemetry collection and uploading +// local enable telemetry collection but disable uploading +// off disable telemetry collection and uploading // view run a web viewer for local telemetry data // env print the current telemetry environment // diff --git a/cmd/gotelemetry/main.go b/cmd/gotelemetry/main.go index 41865d6..0a871c1 100644 --- a/cmd/gotelemetry/main.go +++ b/cmd/gotelemetry/main.go @@ -41,25 +41,39 @@ var ( normalCommands = []*command{ { usage: "on", - short: "enable telemetry uploading", - long: `Gotelemetry on enables telemetry uploading. + short: "enable telemetry collection and uploading", + long: `Gotelemetry on enables telemetry collection and uploading. -When telemetry is enabled, telemetry data is periodically sent to https://telemetry.go.dev/. Uploaded data is used to help improve the Go toolchain and related tools, and it will be published as part of a public dataset. +When telemetry is enabled, telemetry data is written to the local file system and periodically sent to https://telemetry.go.dev/. Uploaded data is used to help improve the Go toolchain and related tools, and it will be published as part of a public dataset. For more details, see https://telemetry.go.dev/privacy. This data is collected in accordance with the Google Privacy Policy (https://policies.google.com/privacy). -To disable telemetry uploading, run “gotelemetry off”`, +To disable telemetry uploading, but keep local data collection, run “gotelemetry local”. +To disable both collection and uploading, run “gotelemetry off“. +`, run: runOn, }, + { + usage: "local", + short: "enable telemetry collection but disable uploading", + long: `Gotelemetry local enables telemetry collection but not uploading. + +When telemetry is in local mode, counter data is written to the local file system, but will not be uploaded to remote servers. + +To enable telemetry uploading, run “gotelemetry on”. +To disable both collection and uploading, run “gotelemetry off”`, + run: runLocal, + }, { usage: "off", - short: "disable telemetry uploading", - long: `Gotelemetry off disables telemetry uploading. + short: "disable telemetry collection and uploading", + long: `Gotelemetry off disables telemetry collection and uploading. -When telemetry uploading is off, local counters data will still be written to the local file system, but will not be uploaded to remove servers. +When telemetry is disabled, local counter data is neither collected nor uploaded. -To enable telemetry uploading, run “gotelemetry on”`, +To enable local collection (but not uploading) of telemetry data, run “gotelemetry local“. +To enable both collection and uploading, run “gotelemetry on”.`, run: runOff, }, { @@ -199,6 +213,15 @@ This data is collected in accordance with the Google Privacy Policy (https://pol To disable telemetry uploading, run “gotelemetry off”.` } +func runLocal(_ []string) { + if old, _ := it.Mode(); old == "local" { + return + } + if err := it.SetMode("local"); err != nil { + failf("Failed to set the telemetry mode to local: %v", err) + } +} + func runOff(_ []string) { if old, _ := it.Mode(); old == "off" { return diff --git a/internal/counter/file.go b/internal/counter/file.go index c7c1db0..d95073e 100644 --- a/internal/counter/file.go +++ b/internal/counter/file.go @@ -111,6 +111,9 @@ func (f *file) lookup(name string) counterPtr { return counterPtr{current, ptr} } +// ErrDisabled is the error returned when telemetry is disabled. +var ErrDisabled = errors.New("counter: disabled by GOTELEMETRY=off") + var ( errNoBuildInfo = errors.New("counter: missing build info") errCorrupt = errors.New("counter: corrupt counter file") @@ -122,6 +125,10 @@ func (f *file) init(begin, end time.Time) { f.err = errNoBuildInfo return } + if mode, _ := telemetry.Mode(); mode == "off" { + f.err = ErrDisabled + return + } dir := telemetry.LocalDir if err := os.MkdirAll(dir, 0777); err != nil { diff --git a/internal/telemetry/mode.go b/internal/telemetry/mode.go index 5e2b811..b461389 100644 --- a/internal/telemetry/mode.go +++ b/internal/telemetry/mode.go @@ -42,7 +42,7 @@ func init() { } // SetMode updates the telemetry mode with the given mode. -// Acceptable values for mode are "on" or "off". +// Acceptable values for mode are "on", "off", or "local". // // SetMode always writes the mode file, and explicitly records the date at // which the modefile was updated. This means that calling SetMode with "on" @@ -60,7 +60,7 @@ func (m ModeFilePath) SetMode(mode string) error { func (m ModeFilePath) SetModeAsOf(mode string, asofTime time.Time) error { mode = strings.TrimSpace(mode) switch mode { - case "on", "off": + case "on", "off", "local": default: return fmt.Errorf("invalid telemetry mode: %q", mode) } @@ -97,7 +97,7 @@ func (m ModeFilePath) Mode() (string, time.Time) { } data, err := os.ReadFile(fname) if err != nil { - return "off", time.Time{} // default + return "local", time.Time{} // default } mode := string(data) mode = strings.TrimSpace(mode) diff --git a/internal/telemetry/mode_test.go b/internal/telemetry/mode_test.go index b80d5f3..ebde64b 100644 --- a/internal/telemetry/mode_test.go +++ b/internal/telemetry/mode_test.go @@ -35,7 +35,7 @@ func TestTelemetryModeWithNoModeConfig(t *testing.T) { modefile ModeFilePath want string }{ - {ModeFilePath(filepath.Join(tmp, "mode")), "off"}, + {ModeFilePath(filepath.Join(tmp, "mode")), "local"}, {"", "off"}, } for _, tt := range tests { @@ -53,7 +53,7 @@ func TestSetMode(t *testing.T) { }{ {"on", false}, {"off", false}, - {"local", true}, // golang/go#63143: local mode is no longer supported + {"local", false}, {"https://mytelemetry.com", true}, {"http://insecure.com", true}, {"bogus", true}, diff --git a/internal/upload/reports.go b/internal/upload/reports.go index 4010303..be8c9b7 100644 --- a/internal/upload/reports.go +++ b/internal/upload/reports.go @@ -29,6 +29,9 @@ var ( // reports generates reports from inactive count files func reports(todo *work) ([]string, error) { + if mode, _ := it.Mode(); mode == "off" { + return nil, nil // no reports + } today := thisInstant.Format("2006-01-02") lastWeek := latestReport(todo.uploaded) if lastWeek >= today { //should never happen diff --git a/mode.go b/mode.go index 46c461b..f7c27d4 100644 --- a/mode.go +++ b/mode.go @@ -10,16 +10,17 @@ import ( // Mode returns the current telemetry mode. // -// The telemetry mode is a global value that controls the -// uploading of telemetry data. Possible mode values are: -// - "on": uploading is enabled -// - "off": uploading is disabled +// The telemetry mode is a global value that controls both the local collection +// and uploading of telemetry data. Possible mode values are: +// - "on": both collection and uploading is enabled +// - "local": collection is enabled, but uploading is disabled +// - "off": both collection and uploading are disabled // -// When mode is "off", local data is still written to the local file system and -// may be inspected with the [gotelemetry] command. +// When mode is "on", or "local", telemetry data is written to the local file +// system and may be inspected with the [gotelemetry] command. // // If an error occurs while reading the telemetry mode from the file system, -// Mode returns the default value "off". +// Mode returns the default value "local". // // [gotelemetry]: https://pkg.go.dev/golang.org/x/telemetry/cmd/gotelemetry func Mode() string {