blob: f53d804ccf8137028c1ba2c3393c66b3aea93ea0 [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package telemetry
import (
"bytes"
"log"
"os"
"path/filepath"
)
// Common types and directories used by multple packages.
// An UploadConfig controls what data is uploaded.
type UploadConfig struct {
GOOS []string
GOARCH []string
GoVersion []string // how does this get changed with new releases?
Programs []*ProgramConfig
Version string // version of this config. Is this needed?
}
type ProgramConfig struct {
// the counter names may have to be
// repeated for each program. (e.g., if the counters are in a package
// that is used in more than one program.)
Name string
Versions []string // where do these come from
Counters []CounterConfig
Stacks []CounterConfig
}
type CounterConfig struct {
Name string
Rate float64 // If X < Rate, report this counter
Depth int // for stack counters
}
// A Report is what's uploaded (or saved locally)
type Report struct {
Week string // first day this report covers (YYYY-MM-DD)
LastWeek string // Week field from latest previous report uploaded
X float64 // A random proability used to determine which counters are uploaded
Programs []*ProgramReport
Config string // version of UploadConfig used
}
type ProgramReport struct {
Program string
Version string
GoVersion string
GOOS string
GOARCH string
Counters map[string]int64
Stacks map[string]int64
}
var (
// directory containing count files and local (not to be uploaded) reports
LocalDir string
// directory containing uploaded reports
UploadDir string
// whether telemetry is enabled
Enabled bool
)
// init() sets LocalDir and UploadDir. Users must not change these.
// If the directories cannot be found or set, telemetry is disabled.
func init() {
env, err := os.UserConfigDir()
if err != nil {
log.Print(err)
return
}
env = filepath.Join(env, "go", "telemetry")
l := filepath.Join(env, "local")
u := filepath.Join(env, "upload")
if err := os.MkdirAll(l, 0755); err != nil {
log.Printf("no local directory %v", err)
return
}
if err := os.MkdirAll(u, 0755); err != nil {
log.Printf("no upload directory %v", err)
return
}
LocalDir = l
UploadDir = u
env = readVar("GOTELEMETRY")
Enabled = env != "off"
}
func readVar(name string) string {
env := os.Getenv(name)
if env == "" {
env = readGoEnv(name + "=")
}
return env
}
func readGoEnv(key string) string {
dir, err := os.UserConfigDir()
if err != nil {
return ""
}
data, err := os.ReadFile(filepath.Join(dir, "go/env"))
if err != nil {
return ""
}
for data != nil {
line, rest, _ := bytes.Cut(data, []byte("\n"))
data = rest
if bytes.HasPrefix(line, []byte(key)) {
return string(line[len(key):])
}
}
return ""
}