mirror of
https://github.com/golang/go.git
synced 2025-05-22 16:09:37 +00:00
cmd/go: add file with list of all counters we collect
Maintain a list of counters we collect and test that it hasn't changed. If it has, fail a test and have the user update the list. The update process will print a reminder to update the list of collected counters. Also run go mod vendor to pull in golang.org/x/telemetry/counter/countertest. For #58894 Change-Id: I661a9c3d67cb33f42a5519f4639af7aa05c3821d Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/564555 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
de487d5616
commit
c8718f6a3d
89
src/cmd/go/counters_test.go
Normal file
89
src/cmd/go/counters_test.go
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright 2024 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 main_test
|
||||
|
||||
import (
|
||||
"cmd/go/internal/base"
|
||||
"flag"
|
||||
"internal/diff"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var update = flag.Bool("update", false, "if true update testdata/counternames.txt")
|
||||
|
||||
func TestCounterNamesUpToDate(t *testing.T) {
|
||||
if !*update {
|
||||
t.Parallel()
|
||||
}
|
||||
|
||||
var counters []string
|
||||
// -C is a special case because it's handled by handleChdirFlag rather than
|
||||
// standard flag processing with FlagSets.
|
||||
// cmd/go/subcommand:unknown is also a special case: it's used when the subcommand
|
||||
// doesn't match any of the known commands.
|
||||
counters = append(counters, "cmd/go/flag:C", "cmd/go/subcommand:unknown")
|
||||
counters = append(counters, flagscounters("cmd/go/flag:", *flag.CommandLine)...)
|
||||
|
||||
for _, cmd := range base.Go.Commands {
|
||||
counters = append(counters, cmdcounters(nil, cmd)...)
|
||||
}
|
||||
cstr := []byte(strings.Join(counters, "\n") + "\n")
|
||||
|
||||
const counterNamesFile = "testdata/counters.txt"
|
||||
old, err := os.ReadFile(counterNamesFile)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading %s: %v", counterNamesFile, err)
|
||||
}
|
||||
diff := diff.Diff(counterNamesFile, old, "generated counter names", cstr)
|
||||
if diff == nil {
|
||||
t.Logf("%s is up to date.", counterNamesFile)
|
||||
return
|
||||
}
|
||||
|
||||
if *update {
|
||||
if err := os.WriteFile(counterNamesFile, cstr, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("wrote %d bytes to %s", len(cstr), counterNamesFile)
|
||||
t.Logf("don't forget to file a proposal to update the list of collected counters")
|
||||
} else {
|
||||
t.Logf("\n%s", diff)
|
||||
t.Errorf("%s is stale. To update, run 'go generate cmd/go'.", counterNamesFile)
|
||||
}
|
||||
}
|
||||
|
||||
func flagscounters(prefix string, flagSet flag.FlagSet) []string {
|
||||
var counters []string
|
||||
flagSet.VisitAll(func(f *flag.Flag) {
|
||||
counters = append(counters, prefix+f.Name)
|
||||
})
|
||||
return counters
|
||||
}
|
||||
|
||||
func cmdcounters(previous []string, cmd *base.Command) []string {
|
||||
const subcommandPrefix = "cmd/go/subcommand:"
|
||||
const flagPrefix = "cmd/go/flag:"
|
||||
var counters []string
|
||||
previousComponent := strings.Join(previous, "-")
|
||||
if len(previousComponent) > 0 {
|
||||
previousComponent += "-"
|
||||
}
|
||||
if cmd.Runnable() {
|
||||
counters = append(counters, subcommandPrefix+previousComponent+cmd.Name())
|
||||
}
|
||||
counters = append(counters, flagscounters(flagPrefix+previousComponent+cmd.Name()+"-", cmd.Flag)...)
|
||||
if len(previous) != 0 {
|
||||
counters = append(counters, subcommandPrefix+previousComponent+"help-"+cmd.Name())
|
||||
}
|
||||
counters = append(counters, subcommandPrefix+"help-"+previousComponent+cmd.Name())
|
||||
|
||||
for _, subcmd := range cmd.Commands {
|
||||
counters = append(counters, cmdcounters(append(slices.Clone(previous), cmd.Name()), subcmd)...)
|
||||
}
|
||||
return counters
|
||||
}
|
@ -44,6 +44,8 @@ import (
|
||||
"cmd/internal/sys"
|
||||
|
||||
cmdgo "cmd/go"
|
||||
|
||||
"golang.org/x/telemetry/counter/countertest"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -153,6 +155,15 @@ func TestMain(m *testing.M) {
|
||||
web.EnableTestHooks(interceptors)
|
||||
}
|
||||
|
||||
cmdgo.TelemetryStart = func() {
|
||||
// TODO(matloob): we'll ideally want to call telemetry.Start here
|
||||
// but it calls counter.Open, which we don't want to do because
|
||||
// we want to call countertest.Open.
|
||||
if telemetryDir := os.Getenv("TESTGO_TELEMETRY_DIR"); telemetryDir != "" {
|
||||
countertest.Open(telemetryDir)
|
||||
}
|
||||
}
|
||||
|
||||
cmdgo.Main()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go test cmd/go -v -run=^TestDocsUpToDate$ -fixdocs
|
||||
//go:generate go test cmd/go -v -run=^TestCounterNamesUpToDate$ -update
|
||||
|
||||
package main
|
||||
|
||||
@ -91,7 +92,7 @@ var _ = go11tag
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
counter.Open() // Open the telemetry counter file so counters can be written to it.
|
||||
TelemetryStart() // Open the telemetry counter file so counters can be written to it.
|
||||
handleChdirFlag()
|
||||
toolchain.Select()
|
||||
|
||||
@ -153,7 +154,6 @@ func main() {
|
||||
|
||||
cmd, used := lookupCmd(args)
|
||||
cfg.CmdName = strings.Join(args[:used], " ")
|
||||
counter.Inc("cmd/go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-"))
|
||||
if len(cmd.Commands) > 0 {
|
||||
if used >= len(args) {
|
||||
help.PrintUsage(os.Stderr, cmd)
|
||||
@ -162,6 +162,7 @@ func main() {
|
||||
}
|
||||
if args[used] == "help" {
|
||||
// Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'.
|
||||
counter.Inc("cmd/go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-") + "-" + strings.Join(args[used:], "-"))
|
||||
help.Help(os.Stdout, append(slices.Clip(args[:used]), args[used+1:]...))
|
||||
base.Exit()
|
||||
}
|
||||
@ -173,10 +174,12 @@ func main() {
|
||||
if cmdName == "" {
|
||||
cmdName = args[0]
|
||||
}
|
||||
counter.Inc("cmd/go/subcommand:unknown")
|
||||
fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cmdName, helpArg)
|
||||
base.SetExitStatus(2)
|
||||
base.Exit()
|
||||
}
|
||||
counter.Inc("cmd/go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-"))
|
||||
invoke(cmd, args[used-1:])
|
||||
base.Exit()
|
||||
}
|
||||
@ -241,7 +244,7 @@ func invoke(cmd *base.Command, args []string) {
|
||||
} else {
|
||||
base.SetFromGOFLAGS(&cmd.Flag)
|
||||
cmd.Flag.Parse(args[1:])
|
||||
counter.CountFlags("cmd/go/flag:"+cmd.Name()+"-", cmd.Flag)
|
||||
counter.CountFlags("cmd/go/flag:"+strings.ReplaceAll(cfg.CmdName, " ", "-")+"-", cmd.Flag)
|
||||
args = cmd.Flag.Args()
|
||||
}
|
||||
|
||||
@ -326,7 +329,7 @@ func handleChdirFlag() {
|
||||
_, dir, _ = strings.Cut(a, "=")
|
||||
os.Args = slices.Delete(os.Args, used, used+1)
|
||||
}
|
||||
counter.Inc("cmd/go:flag-C")
|
||||
counter.Inc("cmd/go/flag:C")
|
||||
|
||||
if err := os.Chdir(dir); err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
_ "embed"
|
||||
"flag"
|
||||
"internal/testenv"
|
||||
"internal/txtar"
|
||||
@ -21,6 +22,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -29,6 +31,8 @@ import (
|
||||
"cmd/go/internal/script"
|
||||
"cmd/go/internal/script/scripttest"
|
||||
"cmd/go/internal/vcweb/vcstest"
|
||||
|
||||
"golang.org/x/telemetry/counter/countertest"
|
||||
)
|
||||
|
||||
var testSum = flag.String("testsum", "", `may be tidy, listm, or listall. If set, TestScript generates a go.sum file at the beginning of each test and updates test files if they pass.`)
|
||||
@ -124,7 +128,7 @@ func TestScript(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
initScriptDirs(t, s)
|
||||
telemetryDir := initScriptDirs(t, s)
|
||||
if err := s.ExtractFiles(a); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -154,6 +158,7 @@ func TestScript(t *testing.T) {
|
||||
// will work better seeing the full path relative to cmd/go
|
||||
// (where the "go test" command is usually run).
|
||||
scripttest.Run(t, engine, s, file, bytes.NewReader(a.Comment))
|
||||
checkCounters(t, telemetryDir)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -177,7 +182,7 @@ func tbFromContext(ctx context.Context) (testing.TB, bool) {
|
||||
|
||||
// initScriptState creates the initial directory structure in s for unpacking a
|
||||
// cmd/go script.
|
||||
func initScriptDirs(t testing.TB, s *script.State) {
|
||||
func initScriptDirs(t testing.TB, s *script.State) (telemetryDir string) {
|
||||
must := func(err error) {
|
||||
if err != nil {
|
||||
t.Helper()
|
||||
@ -188,6 +193,10 @@ func initScriptDirs(t testing.TB, s *script.State) {
|
||||
work := s.Getwd()
|
||||
must(s.Setenv("WORK", work))
|
||||
|
||||
telemetryDir = filepath.Join(work, "telemetry")
|
||||
must(os.MkdirAll(telemetryDir, 0777))
|
||||
must(s.Setenv("TESTGO_TELEMETRY_DIR", filepath.Join(work, "telemetry")))
|
||||
|
||||
must(os.MkdirAll(filepath.Join(work, "tmp"), 0777))
|
||||
must(s.Setenv(tempEnvName(), filepath.Join(work, "tmp")))
|
||||
|
||||
@ -196,6 +205,7 @@ func initScriptDirs(t testing.TB, s *script.State) {
|
||||
gopathSrc := filepath.Join(gopath, "src")
|
||||
must(os.MkdirAll(gopathSrc, 0777))
|
||||
must(s.Chdir(gopathSrc))
|
||||
return telemetryDir
|
||||
}
|
||||
|
||||
func scriptEnv(srv *vcstest.Server, srvCertFile string) ([]string, error) {
|
||||
@ -357,3 +367,53 @@ func updateSum(t testing.TB, e *script.Engine, s *script.State, archive *txtar.A
|
||||
}
|
||||
return rewrite
|
||||
}
|
||||
|
||||
func readCounters(t *testing.T, telemetryDir string) map[string]uint64 {
|
||||
localDir := filepath.Join(telemetryDir, "local")
|
||||
dirents, err := os.ReadDir(localDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil // The Go command didn't ever run so the local dir wasn't created
|
||||
}
|
||||
t.Fatalf("reading telemetry local dir: %v", err)
|
||||
}
|
||||
totals := map[string]uint64{}
|
||||
for _, dirent := range dirents {
|
||||
if dirent.IsDir() || !strings.HasSuffix(dirent.Name(), ".count") {
|
||||
// not a counter file
|
||||
continue
|
||||
}
|
||||
counters, _, err := countertest.ReadFile(filepath.Join(localDir, dirent.Name()))
|
||||
if err != nil {
|
||||
t.Fatalf("reading counter file: %v", err)
|
||||
}
|
||||
for k, v := range counters {
|
||||
totals[k] += v
|
||||
}
|
||||
}
|
||||
|
||||
return totals
|
||||
}
|
||||
|
||||
//go:embed testdata/counters.txt
|
||||
var countersTxt string
|
||||
|
||||
var (
|
||||
allowedCountersOnce sync.Once
|
||||
allowedCounters = map[string]bool{} // Set of allowed counters.
|
||||
)
|
||||
|
||||
func checkCounters(t *testing.T, telemetryDir string) {
|
||||
allowedCountersOnce.Do(func() {
|
||||
for _, counter := range strings.Fields(countersTxt) {
|
||||
allowedCounters[counter] = true
|
||||
}
|
||||
})
|
||||
counters := readCounters(t, telemetryDir)
|
||||
for name := range counters {
|
||||
if !allowedCounters[name] {
|
||||
t.Fatalf("incremented counter %q is not in testdata/counters.txt. "+
|
||||
"Please update counters_test.go to produce an entry for it.", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
src/cmd/go/telemetry.go
Normal file
13
src/cmd/go/telemetry.go
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//go:build !cmd_go_bootstrap
|
||||
|
||||
package main
|
||||
|
||||
import "golang.org/x/telemetry"
|
||||
|
||||
var TelemetryStart = func() {
|
||||
telemetry.Start(telemetry.Config{Upload: true})
|
||||
}
|
9
src/cmd/go/telemetry_bootstrap.go
Normal file
9
src/cmd/go/telemetry_bootstrap.go
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//go:build cmd_go_bootstrap
|
||||
|
||||
package main
|
||||
|
||||
var TelemetryStart = func() {}
|
661
src/cmd/go/testdata/counters.txt
vendored
Normal file
661
src/cmd/go/testdata/counters.txt
vendored
Normal file
@ -0,0 +1,661 @@
|
||||
cmd/go/flag:C
|
||||
cmd/go/subcommand:unknown
|
||||
cmd/go/flag:fixdocs
|
||||
cmd/go/flag:fixreadme
|
||||
cmd/go/flag:flaky
|
||||
cmd/go/flag:proxy
|
||||
cmd/go/flag:test.bench
|
||||
cmd/go/flag:test.benchmem
|
||||
cmd/go/flag:test.benchtime
|
||||
cmd/go/flag:test.blockprofile
|
||||
cmd/go/flag:test.blockprofilerate
|
||||
cmd/go/flag:test.count
|
||||
cmd/go/flag:test.coverprofile
|
||||
cmd/go/flag:test.cpu
|
||||
cmd/go/flag:test.cpuprofile
|
||||
cmd/go/flag:test.failfast
|
||||
cmd/go/flag:test.fullpath
|
||||
cmd/go/flag:test.fuzz
|
||||
cmd/go/flag:test.fuzzcachedir
|
||||
cmd/go/flag:test.fuzzminimizetime
|
||||
cmd/go/flag:test.fuzztime
|
||||
cmd/go/flag:test.fuzzworker
|
||||
cmd/go/flag:test.gocoverdir
|
||||
cmd/go/flag:test.list
|
||||
cmd/go/flag:test.memprofile
|
||||
cmd/go/flag:test.memprofilerate
|
||||
cmd/go/flag:test.mutexprofile
|
||||
cmd/go/flag:test.mutexprofilefraction
|
||||
cmd/go/flag:test.outputdir
|
||||
cmd/go/flag:test.paniconexit0
|
||||
cmd/go/flag:test.parallel
|
||||
cmd/go/flag:test.run
|
||||
cmd/go/flag:test.short
|
||||
cmd/go/flag:test.shuffle
|
||||
cmd/go/flag:test.skip
|
||||
cmd/go/flag:test.testlogfile
|
||||
cmd/go/flag:test.timeout
|
||||
cmd/go/flag:test.trace
|
||||
cmd/go/flag:test.v
|
||||
cmd/go/flag:testsum
|
||||
cmd/go/flag:testwork
|
||||
cmd/go/flag:update
|
||||
cmd/go/subcommand:bug
|
||||
cmd/go/flag:bug-C
|
||||
cmd/go/flag:bug-v
|
||||
cmd/go/subcommand:help-bug
|
||||
cmd/go/subcommand:build
|
||||
cmd/go/flag:build-C
|
||||
cmd/go/flag:build-a
|
||||
cmd/go/flag:build-asan
|
||||
cmd/go/flag:build-asmflags
|
||||
cmd/go/flag:build-buildmode
|
||||
cmd/go/flag:build-buildvcs
|
||||
cmd/go/flag:build-compiler
|
||||
cmd/go/flag:build-cover
|
||||
cmd/go/flag:build-covermode
|
||||
cmd/go/flag:build-coverpkg
|
||||
cmd/go/flag:build-debug-actiongraph
|
||||
cmd/go/flag:build-debug-runtime-trace
|
||||
cmd/go/flag:build-debug-trace
|
||||
cmd/go/flag:build-gccgoflags
|
||||
cmd/go/flag:build-gcflags
|
||||
cmd/go/flag:build-installsuffix
|
||||
cmd/go/flag:build-ldflags
|
||||
cmd/go/flag:build-linkshared
|
||||
cmd/go/flag:build-mod
|
||||
cmd/go/flag:build-modcacherw
|
||||
cmd/go/flag:build-modfile
|
||||
cmd/go/flag:build-msan
|
||||
cmd/go/flag:build-n
|
||||
cmd/go/flag:build-o
|
||||
cmd/go/flag:build-overlay
|
||||
cmd/go/flag:build-p
|
||||
cmd/go/flag:build-pgo
|
||||
cmd/go/flag:build-pkgdir
|
||||
cmd/go/flag:build-race
|
||||
cmd/go/flag:build-tags
|
||||
cmd/go/flag:build-toolexec
|
||||
cmd/go/flag:build-trimpath
|
||||
cmd/go/flag:build-v
|
||||
cmd/go/flag:build-work
|
||||
cmd/go/flag:build-x
|
||||
cmd/go/subcommand:help-build
|
||||
cmd/go/subcommand:clean
|
||||
cmd/go/flag:clean-C
|
||||
cmd/go/flag:clean-a
|
||||
cmd/go/flag:clean-asan
|
||||
cmd/go/flag:clean-asmflags
|
||||
cmd/go/flag:clean-buildmode
|
||||
cmd/go/flag:clean-buildvcs
|
||||
cmd/go/flag:clean-cache
|
||||
cmd/go/flag:clean-compiler
|
||||
cmd/go/flag:clean-debug-actiongraph
|
||||
cmd/go/flag:clean-debug-runtime-trace
|
||||
cmd/go/flag:clean-debug-trace
|
||||
cmd/go/flag:clean-fuzzcache
|
||||
cmd/go/flag:clean-gccgoflags
|
||||
cmd/go/flag:clean-gcflags
|
||||
cmd/go/flag:clean-i
|
||||
cmd/go/flag:clean-installsuffix
|
||||
cmd/go/flag:clean-ldflags
|
||||
cmd/go/flag:clean-linkshared
|
||||
cmd/go/flag:clean-mod
|
||||
cmd/go/flag:clean-modcache
|
||||
cmd/go/flag:clean-modcacherw
|
||||
cmd/go/flag:clean-modfile
|
||||
cmd/go/flag:clean-msan
|
||||
cmd/go/flag:clean-n
|
||||
cmd/go/flag:clean-overlay
|
||||
cmd/go/flag:clean-p
|
||||
cmd/go/flag:clean-pgo
|
||||
cmd/go/flag:clean-pkgdir
|
||||
cmd/go/flag:clean-r
|
||||
cmd/go/flag:clean-race
|
||||
cmd/go/flag:clean-tags
|
||||
cmd/go/flag:clean-testcache
|
||||
cmd/go/flag:clean-toolexec
|
||||
cmd/go/flag:clean-trimpath
|
||||
cmd/go/flag:clean-v
|
||||
cmd/go/flag:clean-work
|
||||
cmd/go/flag:clean-x
|
||||
cmd/go/subcommand:help-clean
|
||||
cmd/go/subcommand:doc
|
||||
cmd/go/subcommand:help-doc
|
||||
cmd/go/subcommand:env
|
||||
cmd/go/flag:env-C
|
||||
cmd/go/flag:env-json
|
||||
cmd/go/flag:env-n
|
||||
cmd/go/flag:env-u
|
||||
cmd/go/flag:env-w
|
||||
cmd/go/flag:env-x
|
||||
cmd/go/subcommand:help-env
|
||||
cmd/go/subcommand:fix
|
||||
cmd/go/flag:fix-C
|
||||
cmd/go/flag:fix-a
|
||||
cmd/go/flag:fix-asan
|
||||
cmd/go/flag:fix-asmflags
|
||||
cmd/go/flag:fix-buildmode
|
||||
cmd/go/flag:fix-buildvcs
|
||||
cmd/go/flag:fix-compiler
|
||||
cmd/go/flag:fix-debug-actiongraph
|
||||
cmd/go/flag:fix-debug-runtime-trace
|
||||
cmd/go/flag:fix-debug-trace
|
||||
cmd/go/flag:fix-fix
|
||||
cmd/go/flag:fix-gccgoflags
|
||||
cmd/go/flag:fix-gcflags
|
||||
cmd/go/flag:fix-installsuffix
|
||||
cmd/go/flag:fix-ldflags
|
||||
cmd/go/flag:fix-linkshared
|
||||
cmd/go/flag:fix-mod
|
||||
cmd/go/flag:fix-modcacherw
|
||||
cmd/go/flag:fix-modfile
|
||||
cmd/go/flag:fix-msan
|
||||
cmd/go/flag:fix-n
|
||||
cmd/go/flag:fix-overlay
|
||||
cmd/go/flag:fix-p
|
||||
cmd/go/flag:fix-pgo
|
||||
cmd/go/flag:fix-pkgdir
|
||||
cmd/go/flag:fix-race
|
||||
cmd/go/flag:fix-tags
|
||||
cmd/go/flag:fix-toolexec
|
||||
cmd/go/flag:fix-trimpath
|
||||
cmd/go/flag:fix-v
|
||||
cmd/go/flag:fix-work
|
||||
cmd/go/flag:fix-x
|
||||
cmd/go/subcommand:help-fix
|
||||
cmd/go/subcommand:fmt
|
||||
cmd/go/flag:fmt-C
|
||||
cmd/go/flag:fmt-mod
|
||||
cmd/go/flag:fmt-modcacherw
|
||||
cmd/go/flag:fmt-modfile
|
||||
cmd/go/flag:fmt-n
|
||||
cmd/go/flag:fmt-overlay
|
||||
cmd/go/flag:fmt-x
|
||||
cmd/go/subcommand:help-fmt
|
||||
cmd/go/subcommand:generate
|
||||
cmd/go/flag:generate-C
|
||||
cmd/go/flag:generate-a
|
||||
cmd/go/flag:generate-asan
|
||||
cmd/go/flag:generate-asmflags
|
||||
cmd/go/flag:generate-buildmode
|
||||
cmd/go/flag:generate-buildvcs
|
||||
cmd/go/flag:generate-compiler
|
||||
cmd/go/flag:generate-debug-actiongraph
|
||||
cmd/go/flag:generate-debug-runtime-trace
|
||||
cmd/go/flag:generate-debug-trace
|
||||
cmd/go/flag:generate-gccgoflags
|
||||
cmd/go/flag:generate-gcflags
|
||||
cmd/go/flag:generate-installsuffix
|
||||
cmd/go/flag:generate-ldflags
|
||||
cmd/go/flag:generate-linkshared
|
||||
cmd/go/flag:generate-mod
|
||||
cmd/go/flag:generate-modcacherw
|
||||
cmd/go/flag:generate-modfile
|
||||
cmd/go/flag:generate-msan
|
||||
cmd/go/flag:generate-n
|
||||
cmd/go/flag:generate-overlay
|
||||
cmd/go/flag:generate-p
|
||||
cmd/go/flag:generate-pgo
|
||||
cmd/go/flag:generate-pkgdir
|
||||
cmd/go/flag:generate-race
|
||||
cmd/go/flag:generate-run
|
||||
cmd/go/flag:generate-skip
|
||||
cmd/go/flag:generate-tags
|
||||
cmd/go/flag:generate-toolexec
|
||||
cmd/go/flag:generate-trimpath
|
||||
cmd/go/flag:generate-v
|
||||
cmd/go/flag:generate-work
|
||||
cmd/go/flag:generate-x
|
||||
cmd/go/subcommand:help-generate
|
||||
cmd/go/subcommand:get
|
||||
cmd/go/flag:get-C
|
||||
cmd/go/flag:get-a
|
||||
cmd/go/flag:get-asan
|
||||
cmd/go/flag:get-asmflags
|
||||
cmd/go/flag:get-buildmode
|
||||
cmd/go/flag:get-buildvcs
|
||||
cmd/go/flag:get-compiler
|
||||
cmd/go/flag:get-d
|
||||
cmd/go/flag:get-debug-actiongraph
|
||||
cmd/go/flag:get-debug-runtime-trace
|
||||
cmd/go/flag:get-debug-trace
|
||||
cmd/go/flag:get-f
|
||||
cmd/go/flag:get-fix
|
||||
cmd/go/flag:get-gccgoflags
|
||||
cmd/go/flag:get-gcflags
|
||||
cmd/go/flag:get-insecure
|
||||
cmd/go/flag:get-installsuffix
|
||||
cmd/go/flag:get-ldflags
|
||||
cmd/go/flag:get-linkshared
|
||||
cmd/go/flag:get-m
|
||||
cmd/go/flag:get-modcacherw
|
||||
cmd/go/flag:get-modfile
|
||||
cmd/go/flag:get-msan
|
||||
cmd/go/flag:get-n
|
||||
cmd/go/flag:get-overlay
|
||||
cmd/go/flag:get-p
|
||||
cmd/go/flag:get-pgo
|
||||
cmd/go/flag:get-pkgdir
|
||||
cmd/go/flag:get-race
|
||||
cmd/go/flag:get-t
|
||||
cmd/go/flag:get-tags
|
||||
cmd/go/flag:get-toolexec
|
||||
cmd/go/flag:get-trimpath
|
||||
cmd/go/flag:get-u
|
||||
cmd/go/flag:get-v
|
||||
cmd/go/flag:get-work
|
||||
cmd/go/flag:get-x
|
||||
cmd/go/subcommand:help-get
|
||||
cmd/go/subcommand:install
|
||||
cmd/go/flag:install-C
|
||||
cmd/go/flag:install-a
|
||||
cmd/go/flag:install-asan
|
||||
cmd/go/flag:install-asmflags
|
||||
cmd/go/flag:install-buildmode
|
||||
cmd/go/flag:install-buildvcs
|
||||
cmd/go/flag:install-compiler
|
||||
cmd/go/flag:install-cover
|
||||
cmd/go/flag:install-covermode
|
||||
cmd/go/flag:install-coverpkg
|
||||
cmd/go/flag:install-debug-actiongraph
|
||||
cmd/go/flag:install-debug-runtime-trace
|
||||
cmd/go/flag:install-debug-trace
|
||||
cmd/go/flag:install-gccgoflags
|
||||
cmd/go/flag:install-gcflags
|
||||
cmd/go/flag:install-installsuffix
|
||||
cmd/go/flag:install-ldflags
|
||||
cmd/go/flag:install-linkshared
|
||||
cmd/go/flag:install-mod
|
||||
cmd/go/flag:install-modcacherw
|
||||
cmd/go/flag:install-modfile
|
||||
cmd/go/flag:install-msan
|
||||
cmd/go/flag:install-n
|
||||
cmd/go/flag:install-overlay
|
||||
cmd/go/flag:install-p
|
||||
cmd/go/flag:install-pgo
|
||||
cmd/go/flag:install-pkgdir
|
||||
cmd/go/flag:install-race
|
||||
cmd/go/flag:install-tags
|
||||
cmd/go/flag:install-toolexec
|
||||
cmd/go/flag:install-trimpath
|
||||
cmd/go/flag:install-v
|
||||
cmd/go/flag:install-work
|
||||
cmd/go/flag:install-x
|
||||
cmd/go/subcommand:help-install
|
||||
cmd/go/subcommand:list
|
||||
cmd/go/flag:list-C
|
||||
cmd/go/flag:list-a
|
||||
cmd/go/flag:list-asan
|
||||
cmd/go/flag:list-asmflags
|
||||
cmd/go/flag:list-buildmode
|
||||
cmd/go/flag:list-buildvcs
|
||||
cmd/go/flag:list-compiled
|
||||
cmd/go/flag:list-compiler
|
||||
cmd/go/flag:list-cover
|
||||
cmd/go/flag:list-covermode
|
||||
cmd/go/flag:list-coverpkg
|
||||
cmd/go/flag:list-debug-actiongraph
|
||||
cmd/go/flag:list-debug-runtime-trace
|
||||
cmd/go/flag:list-debug-trace
|
||||
cmd/go/flag:list-deps
|
||||
cmd/go/flag:list-e
|
||||
cmd/go/flag:list-export
|
||||
cmd/go/flag:list-f
|
||||
cmd/go/flag:list-find
|
||||
cmd/go/flag:list-gccgoflags
|
||||
cmd/go/flag:list-gcflags
|
||||
cmd/go/flag:list-installsuffix
|
||||
cmd/go/flag:list-json
|
||||
cmd/go/flag:list-ldflags
|
||||
cmd/go/flag:list-linkshared
|
||||
cmd/go/flag:list-m
|
||||
cmd/go/flag:list-mod
|
||||
cmd/go/flag:list-modcacherw
|
||||
cmd/go/flag:list-modfile
|
||||
cmd/go/flag:list-msan
|
||||
cmd/go/flag:list-n
|
||||
cmd/go/flag:list-overlay
|
||||
cmd/go/flag:list-p
|
||||
cmd/go/flag:list-pgo
|
||||
cmd/go/flag:list-pkgdir
|
||||
cmd/go/flag:list-race
|
||||
cmd/go/flag:list-retracted
|
||||
cmd/go/flag:list-reuse
|
||||
cmd/go/flag:list-tags
|
||||
cmd/go/flag:list-test
|
||||
cmd/go/flag:list-toolexec
|
||||
cmd/go/flag:list-trimpath
|
||||
cmd/go/flag:list-u
|
||||
cmd/go/flag:list-v
|
||||
cmd/go/flag:list-versions
|
||||
cmd/go/flag:list-work
|
||||
cmd/go/flag:list-x
|
||||
cmd/go/subcommand:help-list
|
||||
cmd/go/subcommand:help-mod
|
||||
cmd/go/subcommand:mod-download
|
||||
cmd/go/flag:mod-download-C
|
||||
cmd/go/flag:mod-download-json
|
||||
cmd/go/flag:mod-download-modcacherw
|
||||
cmd/go/flag:mod-download-modfile
|
||||
cmd/go/flag:mod-download-overlay
|
||||
cmd/go/flag:mod-download-reuse
|
||||
cmd/go/flag:mod-download-x
|
||||
cmd/go/subcommand:mod-help-download
|
||||
cmd/go/subcommand:help-mod-download
|
||||
cmd/go/subcommand:mod-edit
|
||||
cmd/go/flag:mod-edit-C
|
||||
cmd/go/flag:mod-edit-dropexclude
|
||||
cmd/go/flag:mod-edit-dropreplace
|
||||
cmd/go/flag:mod-edit-droprequire
|
||||
cmd/go/flag:mod-edit-dropretract
|
||||
cmd/go/flag:mod-edit-exclude
|
||||
cmd/go/flag:mod-edit-fmt
|
||||
cmd/go/flag:mod-edit-go
|
||||
cmd/go/flag:mod-edit-json
|
||||
cmd/go/flag:mod-edit-modcacherw
|
||||
cmd/go/flag:mod-edit-modfile
|
||||
cmd/go/flag:mod-edit-module
|
||||
cmd/go/flag:mod-edit-n
|
||||
cmd/go/flag:mod-edit-overlay
|
||||
cmd/go/flag:mod-edit-print
|
||||
cmd/go/flag:mod-edit-replace
|
||||
cmd/go/flag:mod-edit-require
|
||||
cmd/go/flag:mod-edit-retract
|
||||
cmd/go/flag:mod-edit-toolchain
|
||||
cmd/go/flag:mod-edit-x
|
||||
cmd/go/subcommand:mod-help-edit
|
||||
cmd/go/subcommand:help-mod-edit
|
||||
cmd/go/subcommand:mod-graph
|
||||
cmd/go/flag:mod-graph-C
|
||||
cmd/go/flag:mod-graph-go
|
||||
cmd/go/flag:mod-graph-modcacherw
|
||||
cmd/go/flag:mod-graph-modfile
|
||||
cmd/go/flag:mod-graph-overlay
|
||||
cmd/go/flag:mod-graph-x
|
||||
cmd/go/subcommand:mod-help-graph
|
||||
cmd/go/subcommand:help-mod-graph
|
||||
cmd/go/subcommand:mod-init
|
||||
cmd/go/flag:mod-init-C
|
||||
cmd/go/flag:mod-init-modcacherw
|
||||
cmd/go/flag:mod-init-modfile
|
||||
cmd/go/flag:mod-init-overlay
|
||||
cmd/go/subcommand:mod-help-init
|
||||
cmd/go/subcommand:help-mod-init
|
||||
cmd/go/subcommand:mod-tidy
|
||||
cmd/go/flag:mod-tidy-C
|
||||
cmd/go/flag:mod-tidy-compat
|
||||
cmd/go/flag:mod-tidy-e
|
||||
cmd/go/flag:mod-tidy-go
|
||||
cmd/go/flag:mod-tidy-modcacherw
|
||||
cmd/go/flag:mod-tidy-modfile
|
||||
cmd/go/flag:mod-tidy-overlay
|
||||
cmd/go/flag:mod-tidy-v
|
||||
cmd/go/flag:mod-tidy-x
|
||||
cmd/go/subcommand:mod-help-tidy
|
||||
cmd/go/subcommand:help-mod-tidy
|
||||
cmd/go/subcommand:mod-vendor
|
||||
cmd/go/flag:mod-vendor-C
|
||||
cmd/go/flag:mod-vendor-e
|
||||
cmd/go/flag:mod-vendor-modcacherw
|
||||
cmd/go/flag:mod-vendor-modfile
|
||||
cmd/go/flag:mod-vendor-o
|
||||
cmd/go/flag:mod-vendor-overlay
|
||||
cmd/go/flag:mod-vendor-v
|
||||
cmd/go/subcommand:mod-help-vendor
|
||||
cmd/go/subcommand:help-mod-vendor
|
||||
cmd/go/subcommand:mod-verify
|
||||
cmd/go/flag:mod-verify-C
|
||||
cmd/go/flag:mod-verify-modcacherw
|
||||
cmd/go/flag:mod-verify-modfile
|
||||
cmd/go/flag:mod-verify-overlay
|
||||
cmd/go/subcommand:mod-help-verify
|
||||
cmd/go/subcommand:help-mod-verify
|
||||
cmd/go/subcommand:mod-why
|
||||
cmd/go/flag:mod-why-C
|
||||
cmd/go/flag:mod-why-m
|
||||
cmd/go/flag:mod-why-modcacherw
|
||||
cmd/go/flag:mod-why-modfile
|
||||
cmd/go/flag:mod-why-overlay
|
||||
cmd/go/flag:mod-why-vendor
|
||||
cmd/go/subcommand:mod-help-why
|
||||
cmd/go/subcommand:help-mod-why
|
||||
cmd/go/subcommand:help-work
|
||||
cmd/go/subcommand:work-edit
|
||||
cmd/go/flag:work-edit-C
|
||||
cmd/go/flag:work-edit-dropreplace
|
||||
cmd/go/flag:work-edit-dropuse
|
||||
cmd/go/flag:work-edit-fmt
|
||||
cmd/go/flag:work-edit-go
|
||||
cmd/go/flag:work-edit-json
|
||||
cmd/go/flag:work-edit-print
|
||||
cmd/go/flag:work-edit-replace
|
||||
cmd/go/flag:work-edit-toolchain
|
||||
cmd/go/flag:work-edit-use
|
||||
cmd/go/subcommand:work-help-edit
|
||||
cmd/go/subcommand:help-work-edit
|
||||
cmd/go/subcommand:work-init
|
||||
cmd/go/flag:work-init-C
|
||||
cmd/go/flag:work-init-modcacherw
|
||||
cmd/go/flag:work-init-modfile
|
||||
cmd/go/flag:work-init-overlay
|
||||
cmd/go/subcommand:work-help-init
|
||||
cmd/go/subcommand:help-work-init
|
||||
cmd/go/subcommand:work-sync
|
||||
cmd/go/flag:work-sync-C
|
||||
cmd/go/flag:work-sync-modcacherw
|
||||
cmd/go/flag:work-sync-modfile
|
||||
cmd/go/flag:work-sync-overlay
|
||||
cmd/go/subcommand:work-help-sync
|
||||
cmd/go/subcommand:help-work-sync
|
||||
cmd/go/subcommand:work-use
|
||||
cmd/go/flag:work-use-C
|
||||
cmd/go/flag:work-use-modcacherw
|
||||
cmd/go/flag:work-use-modfile
|
||||
cmd/go/flag:work-use-overlay
|
||||
cmd/go/flag:work-use-r
|
||||
cmd/go/subcommand:work-help-use
|
||||
cmd/go/subcommand:help-work-use
|
||||
cmd/go/subcommand:work-vendor
|
||||
cmd/go/flag:work-vendor-C
|
||||
cmd/go/flag:work-vendor-e
|
||||
cmd/go/flag:work-vendor-modcacherw
|
||||
cmd/go/flag:work-vendor-modfile
|
||||
cmd/go/flag:work-vendor-o
|
||||
cmd/go/flag:work-vendor-overlay
|
||||
cmd/go/flag:work-vendor-v
|
||||
cmd/go/subcommand:work-help-vendor
|
||||
cmd/go/subcommand:help-work-vendor
|
||||
cmd/go/subcommand:run
|
||||
cmd/go/flag:run-C
|
||||
cmd/go/flag:run-a
|
||||
cmd/go/flag:run-asan
|
||||
cmd/go/flag:run-asmflags
|
||||
cmd/go/flag:run-buildmode
|
||||
cmd/go/flag:run-buildvcs
|
||||
cmd/go/flag:run-compiler
|
||||
cmd/go/flag:run-cover
|
||||
cmd/go/flag:run-covermode
|
||||
cmd/go/flag:run-coverpkg
|
||||
cmd/go/flag:run-debug-actiongraph
|
||||
cmd/go/flag:run-debug-runtime-trace
|
||||
cmd/go/flag:run-debug-trace
|
||||
cmd/go/flag:run-exec
|
||||
cmd/go/flag:run-gccgoflags
|
||||
cmd/go/flag:run-gcflags
|
||||
cmd/go/flag:run-installsuffix
|
||||
cmd/go/flag:run-ldflags
|
||||
cmd/go/flag:run-linkshared
|
||||
cmd/go/flag:run-mod
|
||||
cmd/go/flag:run-modcacherw
|
||||
cmd/go/flag:run-modfile
|
||||
cmd/go/flag:run-msan
|
||||
cmd/go/flag:run-n
|
||||
cmd/go/flag:run-overlay
|
||||
cmd/go/flag:run-p
|
||||
cmd/go/flag:run-pgo
|
||||
cmd/go/flag:run-pkgdir
|
||||
cmd/go/flag:run-race
|
||||
cmd/go/flag:run-tags
|
||||
cmd/go/flag:run-toolexec
|
||||
cmd/go/flag:run-trimpath
|
||||
cmd/go/flag:run-v
|
||||
cmd/go/flag:run-work
|
||||
cmd/go/flag:run-x
|
||||
cmd/go/subcommand:help-run
|
||||
cmd/go/subcommand:test
|
||||
cmd/go/flag:test-C
|
||||
cmd/go/flag:test-a
|
||||
cmd/go/flag:test-asan
|
||||
cmd/go/flag:test-asmflags
|
||||
cmd/go/flag:test-bench
|
||||
cmd/go/flag:test-benchmem
|
||||
cmd/go/flag:test-benchtime
|
||||
cmd/go/flag:test-blockprofile
|
||||
cmd/go/flag:test-blockprofilerate
|
||||
cmd/go/flag:test-buildmode
|
||||
cmd/go/flag:test-buildvcs
|
||||
cmd/go/flag:test-c
|
||||
cmd/go/flag:test-compiler
|
||||
cmd/go/flag:test-count
|
||||
cmd/go/flag:test-cover
|
||||
cmd/go/flag:test-covermode
|
||||
cmd/go/flag:test-coverpkg
|
||||
cmd/go/flag:test-coverprofile
|
||||
cmd/go/flag:test-cpu
|
||||
cmd/go/flag:test-cpuprofile
|
||||
cmd/go/flag:test-debug-actiongraph
|
||||
cmd/go/flag:test-debug-runtime-trace
|
||||
cmd/go/flag:test-debug-trace
|
||||
cmd/go/flag:test-exec
|
||||
cmd/go/flag:test-failfast
|
||||
cmd/go/flag:test-fullpath
|
||||
cmd/go/flag:test-fuzz
|
||||
cmd/go/flag:test-fuzzminimizetime
|
||||
cmd/go/flag:test-fuzztime
|
||||
cmd/go/flag:test-gccgoflags
|
||||
cmd/go/flag:test-gcflags
|
||||
cmd/go/flag:test-installsuffix
|
||||
cmd/go/flag:test-json
|
||||
cmd/go/flag:test-ldflags
|
||||
cmd/go/flag:test-linkshared
|
||||
cmd/go/flag:test-list
|
||||
cmd/go/flag:test-memprofile
|
||||
cmd/go/flag:test-memprofilerate
|
||||
cmd/go/flag:test-mod
|
||||
cmd/go/flag:test-modcacherw
|
||||
cmd/go/flag:test-modfile
|
||||
cmd/go/flag:test-msan
|
||||
cmd/go/flag:test-mutexprofile
|
||||
cmd/go/flag:test-mutexprofilefraction
|
||||
cmd/go/flag:test-n
|
||||
cmd/go/flag:test-o
|
||||
cmd/go/flag:test-outputdir
|
||||
cmd/go/flag:test-overlay
|
||||
cmd/go/flag:test-p
|
||||
cmd/go/flag:test-parallel
|
||||
cmd/go/flag:test-pgo
|
||||
cmd/go/flag:test-pkgdir
|
||||
cmd/go/flag:test-race
|
||||
cmd/go/flag:test-run
|
||||
cmd/go/flag:test-short
|
||||
cmd/go/flag:test-shuffle
|
||||
cmd/go/flag:test-skip
|
||||
cmd/go/flag:test-tags
|
||||
cmd/go/flag:test-test.bench
|
||||
cmd/go/flag:test-test.benchmem
|
||||
cmd/go/flag:test-test.benchtime
|
||||
cmd/go/flag:test-test.blockprofile
|
||||
cmd/go/flag:test-test.blockprofilerate
|
||||
cmd/go/flag:test-test.count
|
||||
cmd/go/flag:test-test.coverprofile
|
||||
cmd/go/flag:test-test.cpu
|
||||
cmd/go/flag:test-test.cpuprofile
|
||||
cmd/go/flag:test-test.failfast
|
||||
cmd/go/flag:test-test.fullpath
|
||||
cmd/go/flag:test-test.fuzz
|
||||
cmd/go/flag:test-test.fuzzminimizetime
|
||||
cmd/go/flag:test-test.fuzztime
|
||||
cmd/go/flag:test-test.list
|
||||
cmd/go/flag:test-test.memprofile
|
||||
cmd/go/flag:test-test.memprofilerate
|
||||
cmd/go/flag:test-test.mutexprofile
|
||||
cmd/go/flag:test-test.mutexprofilefraction
|
||||
cmd/go/flag:test-test.outputdir
|
||||
cmd/go/flag:test-test.parallel
|
||||
cmd/go/flag:test-test.run
|
||||
cmd/go/flag:test-test.short
|
||||
cmd/go/flag:test-test.shuffle
|
||||
cmd/go/flag:test-test.skip
|
||||
cmd/go/flag:test-test.timeout
|
||||
cmd/go/flag:test-test.trace
|
||||
cmd/go/flag:test-test.v
|
||||
cmd/go/flag:test-timeout
|
||||
cmd/go/flag:test-toolexec
|
||||
cmd/go/flag:test-trace
|
||||
cmd/go/flag:test-trimpath
|
||||
cmd/go/flag:test-v
|
||||
cmd/go/flag:test-vet
|
||||
cmd/go/flag:test-work
|
||||
cmd/go/flag:test-x
|
||||
cmd/go/subcommand:help-test
|
||||
cmd/go/subcommand:tool
|
||||
cmd/go/flag:tool-C
|
||||
cmd/go/flag:tool-n
|
||||
cmd/go/subcommand:help-tool
|
||||
cmd/go/subcommand:version
|
||||
cmd/go/flag:version-C
|
||||
cmd/go/flag:version-m
|
||||
cmd/go/flag:version-v
|
||||
cmd/go/subcommand:help-version
|
||||
cmd/go/subcommand:vet
|
||||
cmd/go/flag:vet-C
|
||||
cmd/go/flag:vet-a
|
||||
cmd/go/flag:vet-asan
|
||||
cmd/go/flag:vet-asmflags
|
||||
cmd/go/flag:vet-buildmode
|
||||
cmd/go/flag:vet-buildvcs
|
||||
cmd/go/flag:vet-compiler
|
||||
cmd/go/flag:vet-debug-actiongraph
|
||||
cmd/go/flag:vet-debug-runtime-trace
|
||||
cmd/go/flag:vet-debug-trace
|
||||
cmd/go/flag:vet-gccgoflags
|
||||
cmd/go/flag:vet-gcflags
|
||||
cmd/go/flag:vet-installsuffix
|
||||
cmd/go/flag:vet-ldflags
|
||||
cmd/go/flag:vet-linkshared
|
||||
cmd/go/flag:vet-mod
|
||||
cmd/go/flag:vet-modcacherw
|
||||
cmd/go/flag:vet-modfile
|
||||
cmd/go/flag:vet-msan
|
||||
cmd/go/flag:vet-n
|
||||
cmd/go/flag:vet-overlay
|
||||
cmd/go/flag:vet-p
|
||||
cmd/go/flag:vet-pgo
|
||||
cmd/go/flag:vet-pkgdir
|
||||
cmd/go/flag:vet-race
|
||||
cmd/go/flag:vet-tags
|
||||
cmd/go/flag:vet-toolexec
|
||||
cmd/go/flag:vet-trimpath
|
||||
cmd/go/flag:vet-v
|
||||
cmd/go/flag:vet-vettool
|
||||
cmd/go/flag:vet-work
|
||||
cmd/go/flag:vet-x
|
||||
cmd/go/subcommand:help-vet
|
||||
cmd/go/subcommand:help-buildconstraint
|
||||
cmd/go/subcommand:help-buildmode
|
||||
cmd/go/subcommand:help-c
|
||||
cmd/go/subcommand:help-cache
|
||||
cmd/go/subcommand:help-environment
|
||||
cmd/go/subcommand:help-filetype
|
||||
cmd/go/subcommand:help-go.mod
|
||||
cmd/go/subcommand:help-gopath
|
||||
cmd/go/subcommand:help-goproxy
|
||||
cmd/go/subcommand:help-importpath
|
||||
cmd/go/subcommand:help-modules
|
||||
cmd/go/subcommand:help-module-auth
|
||||
cmd/go/subcommand:help-packages
|
||||
cmd/go/subcommand:help-private
|
||||
cmd/go/subcommand:help-testflag
|
||||
cmd/go/subcommand:help-testfunc
|
||||
cmd/go/subcommand:help-vcs
|
135
src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go
generated
vendored
Normal file
135
src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright 2016 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 errgroup provides synchronization, error propagation, and Context
|
||||
// cancelation for groups of goroutines working on subtasks of a common task.
|
||||
//
|
||||
// [errgroup.Group] is related to [sync.WaitGroup] but adds handling of tasks
|
||||
// returning errors.
|
||||
package errgroup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type token struct{}
|
||||
|
||||
// A Group is a collection of goroutines working on subtasks that are part of
|
||||
// the same overall task.
|
||||
//
|
||||
// A zero Group is valid, has no limit on the number of active goroutines,
|
||||
// and does not cancel on error.
|
||||
type Group struct {
|
||||
cancel func(error)
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
sem chan token
|
||||
|
||||
errOnce sync.Once
|
||||
err error
|
||||
}
|
||||
|
||||
func (g *Group) done() {
|
||||
if g.sem != nil {
|
||||
<-g.sem
|
||||
}
|
||||
g.wg.Done()
|
||||
}
|
||||
|
||||
// WithContext returns a new Group and an associated Context derived from ctx.
|
||||
//
|
||||
// The derived Context is canceled the first time a function passed to Go
|
||||
// returns a non-nil error or the first time Wait returns, whichever occurs
|
||||
// first.
|
||||
func WithContext(ctx context.Context) (*Group, context.Context) {
|
||||
ctx, cancel := withCancelCause(ctx)
|
||||
return &Group{cancel: cancel}, ctx
|
||||
}
|
||||
|
||||
// Wait blocks until all function calls from the Go method have returned, then
|
||||
// returns the first non-nil error (if any) from them.
|
||||
func (g *Group) Wait() error {
|
||||
g.wg.Wait()
|
||||
if g.cancel != nil {
|
||||
g.cancel(g.err)
|
||||
}
|
||||
return g.err
|
||||
}
|
||||
|
||||
// Go calls the given function in a new goroutine.
|
||||
// It blocks until the new goroutine can be added without the number of
|
||||
// active goroutines in the group exceeding the configured limit.
|
||||
//
|
||||
// The first call to return a non-nil error cancels the group's context, if the
|
||||
// group was created by calling WithContext. The error will be returned by Wait.
|
||||
func (g *Group) Go(f func() error) {
|
||||
if g.sem != nil {
|
||||
g.sem <- token{}
|
||||
}
|
||||
|
||||
g.wg.Add(1)
|
||||
go func() {
|
||||
defer g.done()
|
||||
|
||||
if err := f(); err != nil {
|
||||
g.errOnce.Do(func() {
|
||||
g.err = err
|
||||
if g.cancel != nil {
|
||||
g.cancel(g.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// TryGo calls the given function in a new goroutine only if the number of
|
||||
// active goroutines in the group is currently below the configured limit.
|
||||
//
|
||||
// The return value reports whether the goroutine was started.
|
||||
func (g *Group) TryGo(f func() error) bool {
|
||||
if g.sem != nil {
|
||||
select {
|
||||
case g.sem <- token{}:
|
||||
// Note: this allows barging iff channels in general allow barging.
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
g.wg.Add(1)
|
||||
go func() {
|
||||
defer g.done()
|
||||
|
||||
if err := f(); err != nil {
|
||||
g.errOnce.Do(func() {
|
||||
g.err = err
|
||||
if g.cancel != nil {
|
||||
g.cancel(g.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}()
|
||||
return true
|
||||
}
|
||||
|
||||
// SetLimit limits the number of active goroutines in this group to at most n.
|
||||
// A negative value indicates no limit.
|
||||
//
|
||||
// Any subsequent call to the Go method will block until it can add an active
|
||||
// goroutine without exceeding the configured limit.
|
||||
//
|
||||
// The limit must not be modified while any goroutines in the group are active.
|
||||
func (g *Group) SetLimit(n int) {
|
||||
if n < 0 {
|
||||
g.sem = nil
|
||||
return
|
||||
}
|
||||
if len(g.sem) != 0 {
|
||||
panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", len(g.sem)))
|
||||
}
|
||||
g.sem = make(chan token, n)
|
||||
}
|
13
src/cmd/vendor/golang.org/x/sync/errgroup/go120.go
generated
vendored
Normal file
13
src/cmd/vendor/golang.org/x/sync/errgroup/go120.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// 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.
|
||||
|
||||
//go:build go1.20
|
||||
|
||||
package errgroup
|
||||
|
||||
import "context"
|
||||
|
||||
func withCancelCause(parent context.Context) (context.Context, func(error)) {
|
||||
return context.WithCancelCause(parent)
|
||||
}
|
14
src/cmd/vendor/golang.org/x/sync/errgroup/pre_go120.go
generated
vendored
Normal file
14
src/cmd/vendor/golang.org/x/sync/errgroup/pre_go120.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
//go:build !go1.20
|
||||
|
||||
package errgroup
|
||||
|
||||
import "context"
|
||||
|
||||
func withCancelCause(parent context.Context) (context.Context, func(error)) {
|
||||
ctx, cancel := context.WithCancel(parent)
|
||||
return ctx, func(error) { cancel() }
|
||||
}
|
17
src/cmd/vendor/golang.org/x/telemetry/.dockerignore
generated
vendored
Normal file
17
src/cmd/vendor/golang.org/x/telemetry/.dockerignore
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
.git
|
||||
.localstorage
|
||||
node_modules
|
||||
devtools
|
||||
.eslint*
|
||||
.gitignore
|
||||
.prettier*
|
||||
.stylelint*
|
||||
CONTRIBUTING.md
|
||||
LICENSE
|
||||
npm
|
||||
npx
|
||||
package-lock.json
|
||||
package.json
|
||||
PATENTS
|
||||
README.md
|
||||
tsconfig.json
|
11
src/cmd/vendor/golang.org/x/telemetry/.eslintrc.json
generated
vendored
Normal file
11
src/cmd/vendor/golang.org/x/telemetry/.eslintrc.json
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"root": true,
|
||||
"ignorePatterns": ["*.min.js"]
|
||||
}
|
14
src/cmd/vendor/golang.org/x/telemetry/.gitattributes
generated
vendored
Normal file
14
src/cmd/vendor/golang.org/x/telemetry/.gitattributes
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# Treat all files in the repo as binary, with no git magic updating
|
||||
# line endings. This produces predictable results in different environments.
|
||||
#
|
||||
# Windows users contributing to Go will need to use a modern version
|
||||
# of git and editors capable of LF line endings.
|
||||
#
|
||||
# Windows .bat files are known to have multiple bugs when run with LF
|
||||
# endings. So if they are checked in with CRLF endings, there should
|
||||
# be a test like the one in test/winbatch.go in the go repository.
|
||||
# (See golang.org/issue/37791.)
|
||||
#
|
||||
# See golang.org/issue/9281.
|
||||
|
||||
* -text
|
2
src/cmd/vendor/golang.org/x/telemetry/.gitignore
generated
vendored
Normal file
2
src/cmd/vendor/golang.org/x/telemetry/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
.localstorage
|
1
src/cmd/vendor/golang.org/x/telemetry/.prettierrc.json
generated
vendored
Normal file
1
src/cmd/vendor/golang.org/x/telemetry/.prettierrc.json
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"proseWrap": "always"}
|
11
src/cmd/vendor/golang.org/x/telemetry/.stylelintrc.json
generated
vendored
Normal file
11
src/cmd/vendor/golang.org/x/telemetry/.stylelintrc.json
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": ["stylelint-config-standard"],
|
||||
"rules": {
|
||||
"declaration-property-value-allowed-list": {
|
||||
"/color/": ["/^var\\(--/", "transparent"]
|
||||
},
|
||||
"unit-disallowed-list": ["px"],
|
||||
"selector-class-pattern": "^[a-zA-Z\\-]+$"
|
||||
},
|
||||
"ignoreFiles": ["**/*.min.css"]
|
||||
}
|
30
src/cmd/vendor/golang.org/x/telemetry/CONTRIBUTING.md
generated
vendored
Normal file
30
src/cmd/vendor/golang.org/x/telemetry/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
# Contributing to Go
|
||||
|
||||
Go is an open source project.
|
||||
|
||||
It is the work of hundreds of contributors. We appreciate your help!
|
||||
|
||||
## Filing issues
|
||||
|
||||
When [filing an issue](https://golang.org/issue/new), make sure to answer these
|
||||
five questions:
|
||||
|
||||
1. What version of Go are you using (`go version`)?
|
||||
2. What operating system and processor architecture are you using?
|
||||
3. What did you do?
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
|
||||
General questions should go to the
|
||||
[golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead
|
||||
of the issue tracker. The gophers there will answer or ask you to file an issue
|
||||
if you've tripped over a bug.
|
||||
|
||||
## Contributing code
|
||||
|
||||
Please read the
|
||||
[Contribution Guidelines](https://golang.org/doc/contribute.html) before sending
|
||||
patches.
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed under the BSD-style
|
||||
license found in the LICENSE file.
|
60
src/cmd/vendor/golang.org/x/telemetry/README.md
generated
vendored
Normal file
60
src/cmd/vendor/golang.org/x/telemetry/README.md
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
# Go Telemetry
|
||||
|
||||
This repository holds the Go Telemetry server code and libraries, used for
|
||||
hosting [telemetry.go.dev](https://telemetry.go.dev) and instrumenting Go
|
||||
toolchain programs with opt-in telemetry.
|
||||
|
||||
**Warning**: this repository is intended for use only in tools maintained by
|
||||
the Go team, including tools in the Go distribution and auxiliary tools like
|
||||
[gopls](https://pkg.go.dev/golang.org/x/tools/gopls) or
|
||||
[govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck). There are
|
||||
no compatibility guarantees for any of the packages here: public APIs will
|
||||
change in breaking ways as the telemetry integration is refined.
|
||||
|
||||
## Notable Packages
|
||||
|
||||
- The [x/telemetry/counter](https://pkg.go.dev/golang.org/x/telemetry/counter)
|
||||
package provides a library for instrumenting programs with counters and stack
|
||||
reports.
|
||||
- The [x/telemetry/upload](https://pkg.go.dev/golang.org/x/telemetry/upload)
|
||||
package provides a hook for Go toolchain programs to upload telemetry data,
|
||||
if the user has opted in to telemetry uploading.
|
||||
- The [x/telemetry/cmd/gotelemetry](https://pkg.go.dev/pkg/golang.org/x/telemetry/cmd/gotelemetry)
|
||||
command is used for managing telemetry data and configuration.
|
||||
- The [x/telemetry/config](https://pkg.go.dev/pkg/golang.org/x/telemetry/config)
|
||||
package defines the subset of telemetry data that has been approved for
|
||||
uploading by the telemetry proposal process.
|
||||
- The [x/telemetry/godev](https://pkg.go.dev/pkg/golang.org/x/telemetry/godev) directory defines
|
||||
the services running at [telemetry.go.dev](https://telemetry.go.dev).
|
||||
|
||||
## Contributing
|
||||
|
||||
This repository uses Gerrit for code changes. To learn how to submit changes to
|
||||
this repository, see https://golang.org/doc/contribute.html.
|
||||
|
||||
The main issue tracker for the time repository is located at
|
||||
https://github.com/golang/go/issues. Prefix your issue with "x/telemetry:" in
|
||||
the subject line, so it is easy to find.
|
||||
|
||||
### Linting & Formatting
|
||||
|
||||
This repository uses [eslint](https://eslint.org/) to format TS files,
|
||||
[stylelint](https://stylelint.io/) to format CSS files, and
|
||||
[prettier](https://prettier.io/) to format TS, CSS, Markdown, and YAML files.
|
||||
|
||||
See the style guides:
|
||||
|
||||
- [TypeScript](https://google.github.io/styleguide/tsguide.html)
|
||||
- [CSS](https://go.dev/wiki/CSSStyleGuide)
|
||||
|
||||
It is encouraged that all TS and CSS code be run through formatters before
|
||||
submitting a change. However, it is not a strict requirement enforced by CI.
|
||||
|
||||
### Installing npm Dependencies:
|
||||
|
||||
1. Install [docker](https://docs.docker.com/get-docker/)
|
||||
2. Run `./npm install`
|
||||
|
||||
### Run ESLint, Stylelint, & Prettier
|
||||
|
||||
./npm run all
|
62
src/cmd/vendor/golang.org/x/telemetry/counter/countertest/countertest.go
generated
vendored
Normal file
62
src/cmd/vendor/golang.org/x/telemetry/counter/countertest/countertest.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
// 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.
|
||||
|
||||
//go:build go1.19
|
||||
|
||||
// countertest provides testing utilities for counters.
|
||||
// This package cannot be used except for testing.
|
||||
package countertest
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/telemetry/counter"
|
||||
ic "golang.org/x/telemetry/internal/counter"
|
||||
"golang.org/x/telemetry/internal/telemetry"
|
||||
)
|
||||
|
||||
var (
|
||||
openedMu sync.Mutex
|
||||
opened bool
|
||||
)
|
||||
|
||||
func isOpen() bool {
|
||||
openedMu.Lock()
|
||||
defer openedMu.Unlock()
|
||||
return opened
|
||||
}
|
||||
|
||||
// Open enables telemetry data writing to disk.
|
||||
// This is supposed to be called once during the program execution
|
||||
// (i.e. typically in TestMain), and must not be used with
|
||||
// golang.org/x/telemetry/counter.Open.
|
||||
func Open(telemetryDir string) {
|
||||
openedMu.Lock()
|
||||
defer openedMu.Unlock()
|
||||
if opened {
|
||||
panic("Open was called more than once")
|
||||
}
|
||||
telemetry.ModeFile = telemetry.ModeFilePath(filepath.Join(telemetryDir, "mode"))
|
||||
telemetry.LocalDir = filepath.Join(telemetryDir, "local")
|
||||
telemetry.UploadDir = filepath.Join(telemetryDir, "upload")
|
||||
|
||||
counter.Open()
|
||||
opened = true
|
||||
}
|
||||
|
||||
// ReadCounter reads the given counter.
|
||||
func ReadCounter(c *counter.Counter) (count uint64, _ error) {
|
||||
return ic.Read(c)
|
||||
}
|
||||
|
||||
// ReadStackCounter reads the given StackCounter.
|
||||
func ReadStackCounter(c *counter.StackCounter) (stackCounts map[string]uint64, _ error) {
|
||||
return ic.ReadStack(c)
|
||||
}
|
||||
|
||||
// ReadFile reads the counters and stack counters from the given file.
|
||||
func ReadFile(name string) (counters, stackCounters map[string]uint64, _ error) {
|
||||
return ic.ReadFile(name)
|
||||
}
|
21
src/cmd/vendor/golang.org/x/telemetry/counter/countertest/countertest_go118.go
generated
vendored
Normal file
21
src/cmd/vendor/golang.org/x/telemetry/counter/countertest/countertest_go118.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//go:build !go1.19
|
||||
|
||||
package countertest
|
||||
|
||||
import "golang.org/x/telemetry/counter"
|
||||
|
||||
func Open(telemetryDir string) {}
|
||||
|
||||
func ReadCounter(c *counter.Counter) (count uint64, _ error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func ReadStackCounter(c *counter.StackCounter) (stackCounts map[string]uint64, _ error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func ReadFile(name string) (map[string]uint64, map[string]uint64, error) { return nil, nil, nil }
|
16
src/cmd/vendor/golang.org/x/telemetry/counter/countertest/countertest_go121.go
generated
vendored
Normal file
16
src/cmd/vendor/golang.org/x/telemetry/counter/countertest/countertest_go121.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// 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.
|
||||
|
||||
//go:build go1.21
|
||||
|
||||
package countertest
|
||||
|
||||
import "testing"
|
||||
|
||||
func init() {
|
||||
// Extra safety check for go1.21+.
|
||||
if !testing.Testing() {
|
||||
panic("use of this package is disallowed in non-testing code")
|
||||
}
|
||||
}
|
1
src/cmd/vendor/golang.org/x/telemetry/doc.go
generated
vendored
Normal file
1
src/cmd/vendor/golang.org/x/telemetry/doc.go
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
package telemetry
|
140
src/cmd/vendor/golang.org/x/telemetry/internal/config/config.go
generated
vendored
Normal file
140
src/cmd/vendor/golang.org/x/telemetry/internal/config/config.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
// 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 config provides methods for loading and querying a
|
||||
// telemetry upload config file.
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/telemetry/internal/telemetry"
|
||||
)
|
||||
|
||||
// Config is a wrapper around telemetry.UploadConfig that provides some
|
||||
// convenience methods for checking the contents of a report.
|
||||
type Config struct {
|
||||
*telemetry.UploadConfig
|
||||
program map[string]bool
|
||||
goos map[string]bool
|
||||
goarch map[string]bool
|
||||
goversion map[string]bool
|
||||
pgversion map[pgkey]bool
|
||||
pgcounter map[pgkey]bool
|
||||
pgcounterprefix map[pgkey]bool
|
||||
pgstack map[pgkey]bool
|
||||
rate map[pgkey]float64
|
||||
}
|
||||
|
||||
type pgkey struct {
|
||||
program, key string
|
||||
}
|
||||
|
||||
func ReadConfig(file string) (*Config, error) {
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var cfg telemetry.UploadConfig
|
||||
if err := json.Unmarshal(data, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewConfig(&cfg), nil
|
||||
}
|
||||
|
||||
func NewConfig(cfg *telemetry.UploadConfig) *Config {
|
||||
ucfg := Config{UploadConfig: cfg}
|
||||
ucfg.goos = set(ucfg.GOOS)
|
||||
ucfg.goarch = set(ucfg.GOARCH)
|
||||
ucfg.goversion = set(ucfg.GoVersion)
|
||||
ucfg.program = make(map[string]bool, len(ucfg.Programs))
|
||||
ucfg.pgversion = make(map[pgkey]bool, len(ucfg.Programs))
|
||||
ucfg.pgcounter = make(map[pgkey]bool, len(ucfg.Programs))
|
||||
ucfg.pgcounterprefix = make(map[pgkey]bool, len(ucfg.Programs))
|
||||
ucfg.pgstack = make(map[pgkey]bool, len(ucfg.Programs))
|
||||
ucfg.rate = make(map[pgkey]float64)
|
||||
for _, p := range ucfg.Programs {
|
||||
ucfg.program[p.Name] = true
|
||||
for _, v := range p.Versions {
|
||||
ucfg.pgversion[pgkey{p.Name, v}] = true
|
||||
}
|
||||
for _, c := range p.Counters {
|
||||
for _, e := range Expand(c.Name) {
|
||||
ucfg.pgcounter[pgkey{p.Name, e}] = true
|
||||
ucfg.rate[pgkey{p.Name, e}] = c.Rate
|
||||
}
|
||||
prefix, _, found := strings.Cut(c.Name, ":")
|
||||
if found {
|
||||
ucfg.pgcounterprefix[pgkey{p.Name, prefix}] = true
|
||||
}
|
||||
}
|
||||
for _, s := range p.Stacks {
|
||||
ucfg.pgstack[pgkey{p.Name, s.Name}] = true
|
||||
ucfg.rate[pgkey{p.Name, s.Name}] = s.Rate
|
||||
}
|
||||
}
|
||||
return &ucfg
|
||||
}
|
||||
|
||||
func (r *Config) HasProgram(s string) bool {
|
||||
return r.program[s]
|
||||
}
|
||||
|
||||
func (r *Config) HasGOOS(s string) bool {
|
||||
return r.goos[s]
|
||||
}
|
||||
|
||||
func (r *Config) HasGOARCH(s string) bool {
|
||||
return r.goarch[s]
|
||||
}
|
||||
|
||||
func (r *Config) HasGoVersion(s string) bool {
|
||||
return r.goversion[s]
|
||||
}
|
||||
|
||||
func (r *Config) HasVersion(program, version string) bool {
|
||||
return r.pgversion[pgkey{program, version}]
|
||||
}
|
||||
|
||||
func (r *Config) HasCounter(program, counter string) bool {
|
||||
return r.pgcounter[pgkey{program, counter}]
|
||||
}
|
||||
|
||||
func (r *Config) HasCounterPrefix(program, prefix string) bool {
|
||||
return r.pgcounterprefix[pgkey{program, prefix}]
|
||||
}
|
||||
|
||||
func (r *Config) HasStack(program, stack string) bool {
|
||||
return r.pgstack[pgkey{program, stack}]
|
||||
}
|
||||
|
||||
func (r *Config) Rate(program, name string) float64 {
|
||||
return r.rate[pgkey{program, name}]
|
||||
}
|
||||
|
||||
func set(slice []string) map[string]bool {
|
||||
s := make(map[string]bool, len(slice))
|
||||
for _, v := range slice {
|
||||
s[v] = true
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Expand takes a counter defined with buckets and expands it into distinct
|
||||
// strings for each bucket
|
||||
func Expand(counter string) []string {
|
||||
prefix, rest, hasBuckets := strings.Cut(counter, "{")
|
||||
var counters []string
|
||||
if hasBuckets {
|
||||
buckets := strings.Split(strings.TrimSuffix(rest, "}"), ",")
|
||||
for _, b := range buckets {
|
||||
counters = append(counters, prefix+b)
|
||||
}
|
||||
} else {
|
||||
counters = append(counters, prefix)
|
||||
}
|
||||
return counters
|
||||
}
|
78
src/cmd/vendor/golang.org/x/telemetry/internal/configstore/download.go
generated
vendored
Normal file
78
src/cmd/vendor/golang.org/x/telemetry/internal/configstore/download.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
// 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 configstore abstracts interaction with the telemetry config server.
|
||||
// Telemetry config (golang.org/x/telemetry/config) is distributed as a go
|
||||
// module containing go.mod and config.json. Programs that upload collected
|
||||
// counters download the latest config using `go mod download`. This provides
|
||||
// verification of downloaded configuration and cacheability.
|
||||
package configstore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/telemetry/internal/telemetry"
|
||||
)
|
||||
|
||||
const (
|
||||
configModulePath = "golang.org/x/telemetry/config"
|
||||
configFileName = "config.json"
|
||||
)
|
||||
|
||||
// DownloadOption is an option for Download.
|
||||
type DownloadOption struct {
|
||||
// Env holds the environment variables used when downloading the configuration.
|
||||
// If nil, the process's environment variables are used.
|
||||
Env []string
|
||||
}
|
||||
|
||||
// Download fetches the requested telemetry UploadConfig using "go mod download".
|
||||
//
|
||||
// The second result is the canonical version of the requested configuration.
|
||||
func Download(version string, opts *DownloadOption) (telemetry.UploadConfig, string, error) {
|
||||
if version == "" {
|
||||
version = "latest"
|
||||
}
|
||||
if opts == nil {
|
||||
opts = &DownloadOption{}
|
||||
}
|
||||
modVer := configModulePath + "@" + version
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := exec.Command("go", "mod", "download", "-json", modVer)
|
||||
cmd.Env = opts.Env
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
var info struct {
|
||||
Error string
|
||||
}
|
||||
if err := json.Unmarshal(stdout.Bytes(), &info); err == nil && info.Error != "" {
|
||||
return telemetry.UploadConfig{}, "", fmt.Errorf("failed to download config module: %v", info.Error)
|
||||
}
|
||||
return telemetry.UploadConfig{}, "", fmt.Errorf("failed to download config module: %w\n%s", err, &stderr)
|
||||
}
|
||||
|
||||
var info struct {
|
||||
Dir string
|
||||
Version string
|
||||
Error string
|
||||
}
|
||||
if err := json.Unmarshal(stdout.Bytes(), &info); err != nil || info.Dir == "" {
|
||||
return telemetry.UploadConfig{}, "", fmt.Errorf("failed to download config module (invalid JSON): %w", err)
|
||||
}
|
||||
data, err := os.ReadFile(filepath.Join(info.Dir, configFileName))
|
||||
if err != nil {
|
||||
return telemetry.UploadConfig{}, "", fmt.Errorf("invalid config module: %w", err)
|
||||
}
|
||||
var cfg telemetry.UploadConfig
|
||||
if err := json.Unmarshal(data, &cfg); err != nil {
|
||||
return telemetry.UploadConfig{}, "", fmt.Errorf("invalid config: %w", err)
|
||||
}
|
||||
return cfg, info.Version, nil
|
||||
}
|
14
src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/crash_go123.go
generated
vendored
Normal file
14
src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/crash_go123.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//go:build go1.23
|
||||
// +build go1.23
|
||||
|
||||
package crashmonitor
|
||||
|
||||
import "runtime/debug"
|
||||
|
||||
func init() {
|
||||
setCrashOutput = debug.SetCrashOutput
|
||||
}
|
256
src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go
generated
vendored
Normal file
256
src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go
generated
vendored
Normal file
@ -0,0 +1,256 @@
|
||||
// Copyright 2024 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 crashmonitor
|
||||
|
||||
// This file defines a monitor that reports arbitrary Go runtime
|
||||
// crashes to telemetry.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/telemetry/internal/counter"
|
||||
)
|
||||
|
||||
// Supported reports whether the runtime supports [runtime.SetCrashOutput].
|
||||
//
|
||||
// TODO(adonovan): eliminate once go1.23+ is assured.
|
||||
func Supported() bool { return setCrashOutput != nil }
|
||||
|
||||
var setCrashOutput func(*os.File) error // = runtime.SetCrashOutput on go1.23+
|
||||
|
||||
// Parent sets up the parent side of the crashmonitor. It requires
|
||||
// exclusive use of a writable pipe connected to the child process's stdin.
|
||||
func Parent(pipe *os.File) {
|
||||
writeSentinel(pipe)
|
||||
// Ensure that we get pc=0x%x values in the traceback.
|
||||
debug.SetTraceback("system")
|
||||
setCrashOutput(pipe)
|
||||
}
|
||||
|
||||
// Child runs the part of the crashmonitor that runs in the child process.
|
||||
// It expects its stdin to be connected via a pipe to the parent which has
|
||||
// run Parent.
|
||||
func Child() {
|
||||
// Wait for parent process's dying gasp.
|
||||
// If the parent dies for any reason this read will return.
|
||||
data, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read from input pipe: %v", err)
|
||||
}
|
||||
|
||||
// If the only line is the sentinel, it wasn't a crash.
|
||||
if bytes.Count(data, []byte("\n")) < 2 {
|
||||
childExitHook()
|
||||
os.Exit(0) // parent exited without crash report
|
||||
}
|
||||
|
||||
log.Printf("parent reported crash:\n%s", data)
|
||||
|
||||
// Parse the stack out of the crash report
|
||||
// and record a telemetry count for it.
|
||||
name, err := telemetryCounterName(data)
|
||||
if err != nil {
|
||||
// Keep count of how often this happens
|
||||
// so that we can investigate if necessary.
|
||||
incrementCounter("crash/malformed")
|
||||
|
||||
// Something went wrong.
|
||||
// Save the crash securely in the file system.
|
||||
f, err := os.CreateTemp(os.TempDir(), "*.crash")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := f.Write(data); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("failed to report crash to telemetry: %v", err)
|
||||
log.Fatalf("crash report saved at %s", f.Name())
|
||||
}
|
||||
|
||||
incrementCounter(name)
|
||||
|
||||
childExitHook()
|
||||
log.Fatalf("telemetry crash recorded")
|
||||
}
|
||||
|
||||
// (stubbed by test)
|
||||
var (
|
||||
incrementCounter = func(name string) { counter.New(name).Inc() }
|
||||
childExitHook = func() {}
|
||||
)
|
||||
|
||||
// The sentinel function returns its address. The difference between
|
||||
// this value as observed by calls in two different processes of the
|
||||
// same executable tells us the relative offset of their text segments.
|
||||
//
|
||||
// It would be nice if SetCrashOutput took care of this as it's fiddly
|
||||
// and likely to confuse every user at first.
|
||||
func sentinel() uint64 {
|
||||
return uint64(reflect.ValueOf(sentinel).Pointer())
|
||||
}
|
||||
|
||||
func writeSentinel(out io.Writer) {
|
||||
fmt.Fprintf(out, "sentinel %x\n", sentinel())
|
||||
}
|
||||
|
||||
// telemetryCounterName parses a crash report produced by the Go
|
||||
// runtime, extracts the stack of the first runnable goroutine,
|
||||
// converts each line into telemetry form ("symbol:relative-line"),
|
||||
// and returns this as the name of a counter.
|
||||
func telemetryCounterName(crash []byte) (string, error) {
|
||||
pcs, err := parseStackPCs(string(crash))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Limit the number of frames we request.
|
||||
pcs = pcs[:min(len(pcs), 16)]
|
||||
|
||||
if len(pcs) == 0 {
|
||||
// This can occur if all goroutines are idle, as when
|
||||
// caught in a deadlock, or killed by an async signal
|
||||
// while blocked.
|
||||
//
|
||||
// TODO(adonovan): consider how to report such
|
||||
// situations. Reporting a goroutine in [sleep] or
|
||||
// [select] state could be quite confusing without
|
||||
// further information about the nature of the crash,
|
||||
// as the problem is not local to the code location.
|
||||
//
|
||||
// For now, we keep count of this situation so that we
|
||||
// can access whether it needs a more involved solution.
|
||||
return "crash/no-running-goroutine", nil
|
||||
}
|
||||
|
||||
// This string appears at the start of all
|
||||
// crashmonitor-generated counter names.
|
||||
//
|
||||
// It is tempting to expose this as a parameter of Start, but
|
||||
// it is not without risk. What value should most programs
|
||||
// provide? There's no point giving the name of the executable
|
||||
// as this is already recorded by telemetry. What if the
|
||||
// application runs in multiple modes? Then it might be useful
|
||||
// to record the mode. The problem is that an application with
|
||||
// multiple modes probably doesn't know its mode by line 1 of
|
||||
// main.main: it might require flag or argument parsing, or
|
||||
// even validation of an environment variable, and we really
|
||||
// want to steer users aware from any logic before Start. The
|
||||
// flags and arguments will be wrong in the child process, and
|
||||
// every extra conditional branch creates a risk that the
|
||||
// recursively executed child program will behave not like the
|
||||
// monitor but like the application. If the child process
|
||||
// exits before calling Start, then the parent application
|
||||
// will not have a monitor, and its crash reports will be
|
||||
// discarded (written in to a pipe that is never read).
|
||||
//
|
||||
// So for now, we use this constant string.
|
||||
const prefix = "crash/crash"
|
||||
return counter.EncodeStack(pcs, prefix), nil
|
||||
}
|
||||
|
||||
// parseStackPCs parses the parent process's program counters for the
|
||||
// first running goroutine out of a GOTRACEBACK=system traceback,
|
||||
// adjusting them so that they are valid for the child process's text
|
||||
// segment.
|
||||
//
|
||||
// This function returns only program counter values, ensuring that
|
||||
// there is no possibility of strings from the crash report (which may
|
||||
// contain PII) leaking into the telemetry system.
|
||||
func parseStackPCs(crash string) ([]uintptr, error) {
|
||||
// getPC parses the PC out of a line of the form:
|
||||
// \tFILE:LINE +0xRELPC sp=... fp=... pc=...
|
||||
getPC := func(line string) (uint64, error) {
|
||||
_, pcstr, ok := strings.Cut(line, " pc=") // e.g. pc=0x%x
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("no pc= for stack frame: %s", line)
|
||||
}
|
||||
return strconv.ParseUint(pcstr, 0, 64) // 0 => allow 0x prefix
|
||||
}
|
||||
|
||||
var (
|
||||
pcs []uintptr
|
||||
parentSentinel uint64
|
||||
childSentinel = sentinel()
|
||||
on = false // are we in the first running goroutine?
|
||||
lines = strings.Split(crash, "\n")
|
||||
)
|
||||
for i := 0; i < len(lines); i++ {
|
||||
line := lines[i]
|
||||
|
||||
// Read sentinel value.
|
||||
if parentSentinel == 0 && strings.HasPrefix(line, "sentinel ") {
|
||||
_, err := fmt.Sscanf(line, "sentinel %x", &parentSentinel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read sentinel line")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Search for "goroutine GID [STATUS]"
|
||||
if !on {
|
||||
if strings.HasPrefix(line, "goroutine ") &&
|
||||
strings.Contains(line, " [running]:") {
|
||||
on = true
|
||||
|
||||
if parentSentinel == 0 {
|
||||
return nil, fmt.Errorf("no sentinel value in crash report")
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// A blank line marks end of a goroutine stack.
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
|
||||
// Skip the final "created by SYMBOL in goroutine GID" part.
|
||||
if strings.HasPrefix(line, "created by ") {
|
||||
break
|
||||
}
|
||||
|
||||
// Expect a pair of lines:
|
||||
// SYMBOL(ARGS)
|
||||
// \tFILE:LINE +0xRELPC sp=0x%x fp=0x%x pc=0x%x
|
||||
// Note: SYMBOL may contain parens "pkg.(*T).method"
|
||||
// The RELPC is sometimes missing.
|
||||
|
||||
// Skip the symbol(args) line.
|
||||
i++
|
||||
if i == len(lines) {
|
||||
break
|
||||
}
|
||||
line = lines[i]
|
||||
|
||||
// Parse the PC, and correct for the parent and child's
|
||||
// different mappings of the text section.
|
||||
pc, err := getPC(line)
|
||||
if err != nil {
|
||||
// Inlined frame, perhaps; skip it.
|
||||
continue
|
||||
}
|
||||
pcs = append(pcs, uintptr(pc-parentSentinel+childSentinel))
|
||||
}
|
||||
return pcs, nil
|
||||
}
|
||||
|
||||
func min(x, y int) int {
|
||||
if x < y {
|
||||
return x
|
||||
} else {
|
||||
return y
|
||||
}
|
||||
}
|
45
src/cmd/vendor/golang.org/x/telemetry/internal/upload/Doc.txt
generated
vendored
Normal file
45
src/cmd/vendor/golang.org/x/telemetry/internal/upload/Doc.txt
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
The upload process converts count files into reports, and
|
||||
uploads reports. There will be only one report, named YYYY-MM-DD.json,
|
||||
for a given day.
|
||||
|
||||
First phase. Look at the localdir (os.UserConfigdir()/go/telemetry/local)
|
||||
and find all .count and .json files. Find the count files that are no
|
||||
longer active by looking at their metadata.
|
||||
|
||||
Second phase. Group the inactive count files by their expiry date, and
|
||||
for each date generate the local report and the upload report. (The upload
|
||||
report only contains the counters in the upload configuration.) The upload
|
||||
report is saved in the local directory with a name like YYYY-MM-DD.json, if
|
||||
there is no file already existing with that name.
|
||||
If the local report is different, it is saved in the local directory
|
||||
with a name like local.YYYY-MM-DD.json. The new upload report is
|
||||
added to the list of .json files from the first phase. At this point
|
||||
the count files are no longer needed and can be deleted.
|
||||
|
||||
Third phase. Look at the .json files in the list from the first phase.
|
||||
If the name starts with local, skip it. If there is a file with the
|
||||
identical name in the upload directory, remove the one in the local directory.
|
||||
Otherwise try to upload the one in the local directory,
|
||||
If the upload succeeds, move the file to the uploaded directory.
|
||||
|
||||
|
||||
There are various error conditions.
|
||||
1. Several processes could look at localdir and see work to do.
|
||||
1A. They could see different sets of expired count files for some day.
|
||||
This could happen if another process is removing count files. In this
|
||||
case there is already a YYYY-MM-DD.json file either in localdir
|
||||
or updatedir, so the process seeing fewer count files will not generate
|
||||
a report.
|
||||
1B. They could see the same count files, and no report in either directory.
|
||||
They will both generate (in memory) reports and check to see if there
|
||||
is a YYYY-MM-DD.json file in either directory. They could both then
|
||||
write two files with the same name, but different X values, but
|
||||
otherwise the same contents. The X values are very close to the front
|
||||
of the file. Assuming reasonable file system semantics one version of
|
||||
the file will be written. To minimize this, just before writing reports
|
||||
the code checks again to see if they exist.
|
||||
1C. Once there is an existing well-formed file YYYY-MM-DD.json in localdir
|
||||
eventually the upload will succeed, and the file will be moved to updatedir.
|
||||
It is possible that other processes will not see the file in updatedir and
|
||||
upload it again and also move it to uploaddir. This is harmless as all
|
||||
the uploaded files are identical.
|
91
src/cmd/vendor/golang.org/x/telemetry/internal/upload/date.go
generated
vendored
Normal file
91
src/cmd/vendor/golang.org/x/telemetry/internal/upload/date.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
// 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 upload
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/telemetry/internal/counter"
|
||||
)
|
||||
|
||||
// time and date handling
|
||||
|
||||
var distantPast = 21 * 24 * time.Hour
|
||||
|
||||
// reports that are too old (21 days) are not uploaded
|
||||
func tooOld(date string, uploadStartTime time.Time) bool {
|
||||
t, err := time.Parse("2006-01-02", date)
|
||||
if err != nil {
|
||||
logger.Printf("tooOld: %v", err)
|
||||
return false
|
||||
}
|
||||
age := uploadStartTime.Sub(t)
|
||||
return age > distantPast
|
||||
}
|
||||
|
||||
// a time in the far future for the expiry time with errors
|
||||
var farFuture = time.UnixMilli(1 << 62)
|
||||
|
||||
// counterDateSpan parses the counter file named fname and returns the (begin, end) span
|
||||
// recorded in its metadata.
|
||||
// On any error, it returns (0, farFuture), so that invalid files don't look
|
||||
// like they can be used.
|
||||
//
|
||||
// TODO(rfindley): just return an error to make this explicit.
|
||||
func (u *Uploader) counterDateSpan(fname string) (begin, end time.Time) {
|
||||
parsed, err := u.parse(fname)
|
||||
if err != nil {
|
||||
logger.Printf("expiry Parse: %v for %s", err, fname)
|
||||
return time.Time{}, farFuture
|
||||
}
|
||||
begin, err = time.Parse(time.RFC3339, parsed.Meta["TimeBegin"])
|
||||
if err != nil {
|
||||
logger.Printf("time.Parse(%s[TimeBegin]) failed: %v", fname, err)
|
||||
return time.Time{}, farFuture
|
||||
}
|
||||
end, err = time.Parse(time.RFC3339, parsed.Meta["TimeEnd"])
|
||||
if err != nil {
|
||||
logger.Printf("time.Parse(%s[TimeEnd]) failed: %v", fname, err)
|
||||
return time.Time{}, farFuture
|
||||
}
|
||||
return begin, end
|
||||
}
|
||||
|
||||
// stillOpen returns true if the counter file might still be active
|
||||
func (u *Uploader) stillOpen(fname string) bool {
|
||||
_, expiry := u.counterDateSpan(fname)
|
||||
return expiry.After(u.StartTime)
|
||||
}
|
||||
|
||||
// avoid parsing count files multiple times
|
||||
type parsedCache struct {
|
||||
mu sync.Mutex
|
||||
m map[string]*counter.File
|
||||
}
|
||||
|
||||
func (u *Uploader) parse(fname string) (*counter.File, error) {
|
||||
u.cache.mu.Lock()
|
||||
defer u.cache.mu.Unlock()
|
||||
if u.cache.m == nil {
|
||||
u.cache.m = make(map[string]*counter.File)
|
||||
}
|
||||
if f, ok := u.cache.m[fname]; ok {
|
||||
return f, nil
|
||||
}
|
||||
buf, err := os.ReadFile(fname)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse ReadFile: %v for %s", err, fname)
|
||||
}
|
||||
f, err := counter.Parse(fname, buf)
|
||||
if err != nil {
|
||||
|
||||
return nil, fmt.Errorf("parse Parse: %v for %s", err, fname)
|
||||
}
|
||||
u.cache.m[fname] = f
|
||||
return f, nil
|
||||
}
|
96
src/cmd/vendor/golang.org/x/telemetry/internal/upload/findwork.go
generated
vendored
Normal file
96
src/cmd/vendor/golang.org/x/telemetry/internal/upload/findwork.go
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// 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 upload
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// files to handle
|
||||
type work struct {
|
||||
// absolute file names
|
||||
countfiles []string // count files to process
|
||||
readyfiles []string // old reports to upload
|
||||
// relative names
|
||||
uploaded map[string]bool // reports that have been uploaded
|
||||
}
|
||||
|
||||
// find all the files that look like counter files or reports
|
||||
// that need to be uploaded. (There may be unexpected leftover files
|
||||
// and uploading is supposed to be idempotent.)
|
||||
func (u *Uploader) findWork() work {
|
||||
localdir, uploaddir := u.LocalDir, u.UploadDir
|
||||
var ans work
|
||||
fis, err := os.ReadDir(localdir)
|
||||
if err != nil {
|
||||
logger.Printf("could not read %s, progress impossible (%v)", localdir, err)
|
||||
return ans
|
||||
}
|
||||
|
||||
mode, asof := u.ModeFilePath.Mode()
|
||||
logger.Printf("mode %s, asof %s", mode, asof)
|
||||
|
||||
// count files end in .v1.count
|
||||
// reports end in .json. If they are not to be uploaded they
|
||||
// start with local.
|
||||
for _, fi := range fis {
|
||||
if strings.HasSuffix(fi.Name(), ".v1.count") {
|
||||
fname := filepath.Join(localdir, fi.Name())
|
||||
if u.stillOpen(fname) {
|
||||
logger.Printf("still active: %s", fname)
|
||||
continue
|
||||
}
|
||||
ans.countfiles = append(ans.countfiles, fname)
|
||||
} else if strings.HasPrefix(fi.Name(), "local.") {
|
||||
// skip
|
||||
} else if strings.HasSuffix(fi.Name(), ".json") && mode == "on" {
|
||||
// Collect reports that are ready for upload.
|
||||
reportDate := uploadReportDate(fi.Name())
|
||||
if !asof.IsZero() && !reportDate.IsZero() {
|
||||
// If both the mode asof date and the report date are present, do the
|
||||
// right thing...
|
||||
//
|
||||
// (see https://github.com/golang/go/issues/63142#issuecomment-1734025130)
|
||||
if asof.Before(reportDate) {
|
||||
// Note: since this report was created after telemetry was enabled,
|
||||
// we can only assume that the process that created it checked that
|
||||
// the counter data contained therein was all from after the asof
|
||||
// date.
|
||||
//
|
||||
// TODO(rfindley): store the begin date in reports, so that we can
|
||||
// verify this assumption.
|
||||
logger.Printf("uploadable %s", fi.Name())
|
||||
ans.readyfiles = append(ans.readyfiles, filepath.Join(localdir, fi.Name()))
|
||||
}
|
||||
} else {
|
||||
// ...otherwise fall back on the old behavior of uploading all
|
||||
// unuploaded files.
|
||||
//
|
||||
// TODO(rfindley): invert this logic following more testing. We
|
||||
// should only upload if we know both the asof date and the report
|
||||
// date, and they are acceptable.
|
||||
logger.Printf("uploadable anyway %s", fi.Name())
|
||||
ans.readyfiles = append(ans.readyfiles, filepath.Join(localdir, fi.Name()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fis, err = os.ReadDir(uploaddir)
|
||||
if err != nil {
|
||||
os.MkdirAll(uploaddir, 0777)
|
||||
return ans
|
||||
}
|
||||
// There should be only one of these per day; maybe sometime
|
||||
// we'll want to clean the directory.
|
||||
ans.uploaded = make(map[string]bool)
|
||||
for _, fi := range fis {
|
||||
if strings.HasSuffix(fi.Name(), ".json") {
|
||||
ans.uploaded[fi.Name()] = true
|
||||
}
|
||||
}
|
||||
return ans
|
||||
}
|
311
src/cmd/vendor/golang.org/x/telemetry/internal/upload/reports.go
generated
vendored
Normal file
311
src/cmd/vendor/golang.org/x/telemetry/internal/upload/reports.go
generated
vendored
Normal file
@ -0,0 +1,311 @@
|
||||
// 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 upload
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/telemetry/internal/config"
|
||||
"golang.org/x/telemetry/internal/configstore"
|
||||
"golang.org/x/telemetry/internal/counter"
|
||||
"golang.org/x/telemetry/internal/telemetry"
|
||||
)
|
||||
|
||||
// reports generates reports from inactive count files
|
||||
func (u *Uploader) reports(todo *work) ([]string, error) {
|
||||
if mode, _ := u.ModeFilePath.Mode(); mode == "off" {
|
||||
return nil, nil // no reports
|
||||
}
|
||||
thisInstant := u.StartTime
|
||||
today := thisInstant.Format("2006-01-02")
|
||||
lastWeek := latestReport(todo.uploaded)
|
||||
if lastWeek >= today { //should never happen
|
||||
lastWeek = ""
|
||||
}
|
||||
logger.Printf("lastWeek %q, today %s", lastWeek, today)
|
||||
countFiles := make(map[string][]string) // expiry date string->filenames
|
||||
earliest := make(map[string]time.Time) // earliest begin time for any counter
|
||||
for _, f := range todo.countfiles {
|
||||
begin, end := u.counterDateSpan(f)
|
||||
|
||||
if end.Before(thisInstant) {
|
||||
expiry := end.Format(dateFormat)
|
||||
countFiles[expiry] = append(countFiles[expiry], f)
|
||||
if earliest[expiry].IsZero() || earliest[expiry].After(begin) {
|
||||
earliest[expiry] = begin
|
||||
}
|
||||
}
|
||||
}
|
||||
for expiry, files := range countFiles {
|
||||
if notNeeded(expiry, *todo) {
|
||||
logger.Printf("files for %s not needed, deleting %v", expiry, files)
|
||||
// The report already exists.
|
||||
// There's another check in createReport.
|
||||
deleteFiles(files)
|
||||
continue
|
||||
}
|
||||
fname, err := u.createReport(earliest[expiry], expiry, files, lastWeek)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fname != "" {
|
||||
todo.readyfiles = append(todo.readyfiles, fname)
|
||||
}
|
||||
}
|
||||
return todo.readyfiles, nil
|
||||
}
|
||||
|
||||
// latestReport returns the YYYY-MM-DD of the last report uploaded
|
||||
// or the empty string if there are no reports.
|
||||
func latestReport(uploaded map[string]bool) string {
|
||||
var latest string
|
||||
for name := range uploaded {
|
||||
if strings.HasSuffix(name, ".json") {
|
||||
if name > latest {
|
||||
latest = name
|
||||
}
|
||||
}
|
||||
}
|
||||
if latest == "" {
|
||||
return ""
|
||||
}
|
||||
// strip off the .json
|
||||
return latest[:len(latest)-len(".json")]
|
||||
}
|
||||
|
||||
// notNeeded returns true if the report for date has already been created
|
||||
func notNeeded(date string, todo work) bool {
|
||||
if todo.uploaded != nil && todo.uploaded[date+".json"] {
|
||||
return true
|
||||
}
|
||||
// maybe the report is already in todo.readyfiles
|
||||
for _, f := range todo.readyfiles {
|
||||
if strings.Contains(f, date) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func deleteFiles(files []string) {
|
||||
for _, f := range files {
|
||||
if err := os.Remove(f); err != nil {
|
||||
// this could be a race condition.
|
||||
// conversely, on Windows, err may be nil and
|
||||
// the file not deleted if anyone has it open.
|
||||
logger.Printf("%v failed to remove %s", err, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// createReport for all the count files for the same date.
|
||||
// returns the absolute path name of the file containing the report
|
||||
func (u *Uploader) createReport(start time.Time, expiryDate string, files []string, lastWeek string) (string, error) {
|
||||
if u.Config == nil {
|
||||
a, v, err := configstore.Download("latest", nil)
|
||||
if err != nil {
|
||||
logger.Print(err) // or something (e.g., panic(err))
|
||||
}
|
||||
u.Config = &a
|
||||
u.ConfigVersion = v
|
||||
}
|
||||
uploadOK := true
|
||||
mode, asof := u.ModeFilePath.Mode()
|
||||
if u.Config == nil || mode != "on" {
|
||||
logger.Printf("no upload config or mode %q is not 'on'", mode)
|
||||
uploadOK = false // no config, nothing to upload
|
||||
}
|
||||
if tooOld(expiryDate, u.StartTime) {
|
||||
logger.Printf("expiryDate %s is too old", expiryDate)
|
||||
uploadOK = false
|
||||
}
|
||||
// If the mode is recorded with an asof date, don't upload if the report
|
||||
// includes any data on or before the asof date.
|
||||
if !asof.IsZero() && !asof.Before(start) {
|
||||
logger.Printf("asof %s is not before start %s", asof, start)
|
||||
uploadOK = false
|
||||
}
|
||||
// should we check that all the x.Meta are consistent for GOOS, GOARCH, etc?
|
||||
report := &telemetry.Report{
|
||||
Config: u.ConfigVersion,
|
||||
X: computeRandom(), // json encodes all the bits
|
||||
Week: expiryDate,
|
||||
LastWeek: lastWeek,
|
||||
}
|
||||
if report.X > u.Config.SampleRate && u.Config.SampleRate > 0 {
|
||||
logger.Printf("X:%f > SampleRate:%f, not uploadable", report.X, u.Config.SampleRate)
|
||||
uploadOK = false
|
||||
}
|
||||
var succeeded bool
|
||||
for _, f := range files {
|
||||
x, err := u.parse(string(f))
|
||||
if err != nil {
|
||||
logger.Printf("unparseable (%v) %s", err, f)
|
||||
continue
|
||||
}
|
||||
prog := findProgReport(x.Meta, report)
|
||||
for k, v := range x.Count {
|
||||
if counter.IsStackCounter(k) {
|
||||
// stack
|
||||
prog.Stacks[k] += int64(v)
|
||||
} else {
|
||||
// counter
|
||||
prog.Counters[k] += int64(v)
|
||||
}
|
||||
succeeded = true
|
||||
}
|
||||
}
|
||||
if !succeeded {
|
||||
return "", fmt.Errorf("all %d count files were unparseable", len(files))
|
||||
}
|
||||
// 1. generate the local report
|
||||
localContents, err := json.MarshalIndent(report, "", " ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal report (%v)", err)
|
||||
}
|
||||
// check that the report can be read back
|
||||
// TODO(pjw): remove for production?
|
||||
var x telemetry.Report
|
||||
if err := json.Unmarshal(localContents, &x); err != nil {
|
||||
return "", fmt.Errorf("failed to unmarshal local report (%v)", err)
|
||||
}
|
||||
|
||||
var uploadContents []byte
|
||||
if uploadOK {
|
||||
// 2. create the uploadable version
|
||||
cfg := config.NewConfig(u.Config)
|
||||
upload := &telemetry.Report{
|
||||
Week: report.Week,
|
||||
LastWeek: report.LastWeek,
|
||||
X: report.X,
|
||||
Config: report.Config,
|
||||
}
|
||||
for _, p := range report.Programs {
|
||||
// does the uploadConfig want this program?
|
||||
// if so, copy over the Stacks and Counters
|
||||
// that the uploadConfig mentions.
|
||||
if !cfg.HasGoVersion(p.GoVersion) || !cfg.HasProgram(p.Program) || !cfg.HasVersion(p.Program, p.Version) {
|
||||
continue
|
||||
}
|
||||
x := &telemetry.ProgramReport{
|
||||
Program: p.Program,
|
||||
Version: p.Version,
|
||||
GOOS: p.GOOS,
|
||||
GOARCH: p.GOARCH,
|
||||
GoVersion: p.GoVersion,
|
||||
Counters: make(map[string]int64),
|
||||
Stacks: make(map[string]int64),
|
||||
}
|
||||
upload.Programs = append(upload.Programs, x)
|
||||
for k, v := range p.Counters {
|
||||
if cfg.HasCounter(p.Program, k) && report.X <= cfg.Rate(p.Program, k) {
|
||||
x.Counters[k] = v
|
||||
}
|
||||
}
|
||||
// and the same for Stacks
|
||||
// this can be made more efficient, when it matters
|
||||
for k, v := range p.Stacks {
|
||||
before, _, _ := strings.Cut(k, "\n")
|
||||
if cfg.HasStack(p.Program, before) && report.X <= cfg.Rate(p.Program, before) {
|
||||
x.Stacks[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uploadContents, err = json.MarshalIndent(upload, "", " ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal upload report (%v)", err)
|
||||
}
|
||||
}
|
||||
localFileName := filepath.Join(u.LocalDir, "local."+expiryDate+".json")
|
||||
uploadFileName := filepath.Join(u.LocalDir, expiryDate+".json")
|
||||
|
||||
/* Prepare to write files */
|
||||
// if either file exists, someone has been here ahead of us
|
||||
// (there is still a race, but this check shortens the open window)
|
||||
if _, err := os.Stat(localFileName); err == nil {
|
||||
deleteFiles(files)
|
||||
return "", fmt.Errorf("local report %s already exists", localFileName)
|
||||
}
|
||||
if _, err := os.Stat(uploadFileName); err == nil {
|
||||
deleteFiles(files)
|
||||
return "", fmt.Errorf("report %s already exists", uploadFileName)
|
||||
}
|
||||
// write the uploadable file
|
||||
var errUpload, errLocal error
|
||||
if uploadOK {
|
||||
errUpload = os.WriteFile(uploadFileName, uploadContents, 0644)
|
||||
}
|
||||
// write the local file
|
||||
errLocal = os.WriteFile(localFileName, localContents, 0644)
|
||||
/* Wrote the files */
|
||||
|
||||
// even though these errors won't occur, what should happen
|
||||
// if errUpload == nil and it is ok to upload, and errLocal != nil?
|
||||
if errLocal != nil {
|
||||
return "", fmt.Errorf("failed to write local file %s (%v)", localFileName, errLocal)
|
||||
}
|
||||
if errUpload != nil {
|
||||
return "", fmt.Errorf("failed to write upload file %s (%v)", uploadFileName, errUpload)
|
||||
}
|
||||
logger.Printf("created %q, deleting %v", uploadFileName, files)
|
||||
deleteFiles(files)
|
||||
if uploadOK {
|
||||
return uploadFileName, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// return an existing ProgremReport, or create anew
|
||||
func findProgReport(meta map[string]string, report *telemetry.Report) *telemetry.ProgramReport {
|
||||
for _, prog := range report.Programs {
|
||||
if prog.Program == meta["Program"] && prog.Version == meta["Version"] &&
|
||||
prog.GoVersion == meta["GoVersion"] && prog.GOOS == meta["GOOS"] &&
|
||||
prog.GOARCH == meta["GOARCH"] {
|
||||
return prog
|
||||
}
|
||||
}
|
||||
prog := telemetry.ProgramReport{
|
||||
Program: meta["Program"],
|
||||
Version: meta["Version"],
|
||||
GoVersion: meta["GoVersion"],
|
||||
GOOS: meta["GOOS"],
|
||||
GOARCH: meta["GOARCH"],
|
||||
Counters: make(map[string]int64),
|
||||
Stacks: make(map[string]int64),
|
||||
}
|
||||
report.Programs = append(report.Programs, &prog)
|
||||
return &prog
|
||||
}
|
||||
|
||||
// turn 8 random bytes into a float64 in [0,1]
|
||||
func computeRandom() float64 {
|
||||
for {
|
||||
b := make([]byte, 8)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
logger.Fatalf("rand.Read: %v", err)
|
||||
}
|
||||
// and turn it into a float64
|
||||
x := math.Float64frombits(binary.LittleEndian.Uint64(b))
|
||||
if math.IsNaN(x) || math.IsInf(x, 0) {
|
||||
continue
|
||||
}
|
||||
x = math.Abs(x)
|
||||
if x < 0x1p-1000 { // avoid underflow patterns
|
||||
continue
|
||||
}
|
||||
frac, _ := math.Frexp(x) // 52 bits of randomness
|
||||
return frac*2 - 1
|
||||
}
|
||||
}
|
135
src/cmd/vendor/golang.org/x/telemetry/internal/upload/run.go
generated
vendored
Normal file
135
src/cmd/vendor/golang.org/x/telemetry/internal/upload/run.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
// 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 upload
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/telemetry/internal/telemetry"
|
||||
)
|
||||
|
||||
var logger *log.Logger
|
||||
|
||||
func init() {
|
||||
logger = log.New(io.Discard, "", 0)
|
||||
}
|
||||
|
||||
// keep track of what SetLogOutput has seen
|
||||
var seenlogwriters []io.Writer
|
||||
|
||||
// SetLogOutput sets the default logger's output destination.
|
||||
func SetLogOutput(logging io.Writer) {
|
||||
if logging == nil {
|
||||
return
|
||||
}
|
||||
logger.SetOutput(logging) // the common case
|
||||
seenlogwriters = append(seenlogwriters, logging)
|
||||
if len(seenlogwriters) > 1 {
|
||||
// The client asked for logging, and there is also a debug dir
|
||||
logger.SetOutput(io.MultiWriter(seenlogwriters...))
|
||||
}
|
||||
}
|
||||
|
||||
// LogIfDebug arranges to write a log file in the directory
|
||||
// dirname, if it exists. If dirname is the empty string,
|
||||
// the function tries the directory it.Localdir/debug.
|
||||
func LogIfDebug(dirname string) error {
|
||||
dname := filepath.Join(telemetry.LocalDir, "debug")
|
||||
if dirname != "" {
|
||||
dname = dirname
|
||||
}
|
||||
fd, err := os.Stat(dname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fd == nil || !fd.IsDir() {
|
||||
// debug doesn't exist or isn't a directory
|
||||
return nil
|
||||
}
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return fmt.Errorf("no build info")
|
||||
}
|
||||
year, month, day := time.Now().UTC().Date()
|
||||
goVers := info.GoVersion
|
||||
// E.g., goVers:"go1.22-20240109-RC01 cl/597041403 +dcbe772469 X:loopvar"
|
||||
words := strings.Fields(goVers)
|
||||
goVers = words[0]
|
||||
progPkgPath := info.Path
|
||||
if progPkgPath == "" {
|
||||
progPkgPath = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe")
|
||||
}
|
||||
prog := path.Base(progPkgPath)
|
||||
progVers := info.Main.Version
|
||||
fname := filepath.Join(dname, fmt.Sprintf("%s-%s-%s-%4d%02d%02d-%d.log",
|
||||
prog, progVers, goVers, year, month, day, os.Getpid()))
|
||||
fname = strings.ReplaceAll(fname, " ", "")
|
||||
if _, err := os.Stat(fname); err == nil {
|
||||
// This process previously called upload.Run
|
||||
return nil
|
||||
}
|
||||
logfd, err := os.Create(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
SetLogOutput(logfd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Uploader carries parameters needed for upload.
|
||||
type Uploader struct {
|
||||
// Config is used to select counters to upload.
|
||||
Config *telemetry.UploadConfig
|
||||
// ConfigVersion is the version of the config.
|
||||
ConfigVersion string
|
||||
|
||||
// LocalDir is where the local counter files are.
|
||||
LocalDir string
|
||||
// UploadDir is where uploader leaves the copy of uploaded data.
|
||||
UploadDir string
|
||||
// ModeFilePath is the file.
|
||||
ModeFilePath telemetry.ModeFilePath
|
||||
|
||||
UploadServerURL string
|
||||
StartTime time.Time
|
||||
|
||||
cache parsedCache
|
||||
}
|
||||
|
||||
// NewUploader creates a default uploader.
|
||||
func NewUploader(config *telemetry.UploadConfig) *Uploader {
|
||||
return &Uploader{
|
||||
Config: config,
|
||||
ConfigVersion: "custom",
|
||||
LocalDir: telemetry.LocalDir,
|
||||
UploadDir: telemetry.UploadDir,
|
||||
ModeFilePath: telemetry.ModeFile,
|
||||
UploadServerURL: "https://telemetry.go.dev/upload",
|
||||
StartTime: time.Now().UTC(),
|
||||
}
|
||||
}
|
||||
|
||||
// Run generates and uploads reports
|
||||
func (u *Uploader) Run() {
|
||||
if telemetry.DisabledOnPlatform {
|
||||
return
|
||||
}
|
||||
todo := u.findWork()
|
||||
ready, err := u.reports(&todo)
|
||||
if err != nil {
|
||||
logger.Printf("reports: %v", err)
|
||||
}
|
||||
for _, f := range ready {
|
||||
u.uploadReport(f)
|
||||
}
|
||||
}
|
85
src/cmd/vendor/golang.org/x/telemetry/internal/upload/upload.go
generated
vendored
Normal file
85
src/cmd/vendor/golang.org/x/telemetry/internal/upload/upload.go
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
// 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 upload
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
dateRE = regexp.MustCompile(`(\d\d\d\d-\d\d-\d\d)[.]json$`)
|
||||
dateFormat = "2006-01-02"
|
||||
// TODO(rfindley): use dateFormat throughout.
|
||||
)
|
||||
|
||||
// uploadReportDate returns the date component of the upload file name, or "" if the
|
||||
// date was unmatched.
|
||||
func uploadReportDate(fname string) time.Time {
|
||||
match := dateRE.FindStringSubmatch(fname)
|
||||
if match == nil || len(match) < 2 {
|
||||
logger.Printf("malformed report name: missing date: %q", filepath.Base(fname))
|
||||
return time.Time{}
|
||||
}
|
||||
d, err := time.Parse(dateFormat, match[1])
|
||||
if err != nil {
|
||||
logger.Printf("malformed report name: bad date: %q", filepath.Base(fname))
|
||||
return time.Time{}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (u *Uploader) uploadReport(fname string) {
|
||||
thisInstant := u.StartTime
|
||||
// TODO(rfindley): use uploadReportDate here, once we've done a gopls release.
|
||||
|
||||
// first make sure it is not in the future
|
||||
today := thisInstant.Format("2006-01-02")
|
||||
match := dateRE.FindStringSubmatch(fname)
|
||||
if match == nil || len(match) < 2 {
|
||||
logger.Printf("report name seemed to have no date %q", filepath.Base(fname))
|
||||
} else if match[1] > today {
|
||||
logger.Printf("report %q is later than today %s", filepath.Base(fname), today)
|
||||
return // report is in the future, which shouldn't happen
|
||||
}
|
||||
buf, err := os.ReadFile(fname)
|
||||
if err != nil {
|
||||
logger.Printf("%v reading %s", err, fname)
|
||||
return
|
||||
}
|
||||
if u.uploadReportContents(fname, buf) {
|
||||
// anything left to do?
|
||||
}
|
||||
}
|
||||
|
||||
// try to upload the report, 'true' if successful
|
||||
func (u *Uploader) uploadReportContents(fname string, buf []byte) bool {
|
||||
b := bytes.NewReader(buf)
|
||||
fdate := strings.TrimSuffix(filepath.Base(fname), ".json")
|
||||
fdate = fdate[len(fdate)-len("2006-01-02"):]
|
||||
server := u.UploadServerURL + "/" + fdate
|
||||
|
||||
resp, err := http.Post(server, "application/json", b)
|
||||
if err != nil {
|
||||
logger.Printf("error on Post: %v %q for %q", err, server, fname)
|
||||
return false
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
logger.Printf("resp error on upload %q: %v for %q %q [%+v]", server, resp.Status, fname, fdate, resp)
|
||||
return false
|
||||
}
|
||||
// put a copy in the uploaded directory
|
||||
newname := filepath.Join(u.UploadDir, fdate+".json")
|
||||
if err := os.WriteFile(newname, buf, 0644); err == nil {
|
||||
os.Remove(fname) // if it exists
|
||||
}
|
||||
logger.Printf("uploaded %s to %q", fdate+".json", server)
|
||||
return true
|
||||
}
|
40
src/cmd/vendor/golang.org/x/telemetry/mode.go
generated
vendored
Normal file
40
src/cmd/vendor/golang.org/x/telemetry/mode.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// 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 (
|
||||
"golang.org/x/telemetry/internal/telemetry"
|
||||
)
|
||||
|
||||
// Mode returns the current telemetry mode.
|
||||
//
|
||||
// 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 "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 "local".
|
||||
//
|
||||
// [gotelemetry]: https://pkg.go.dev/golang.org/x/telemetry/cmd/gotelemetry
|
||||
func Mode() string {
|
||||
mode, _ := telemetry.Mode()
|
||||
return mode
|
||||
}
|
||||
|
||||
// SetMode sets the global telemetry mode to the given value.
|
||||
//
|
||||
// See the documentation of [Mode] for a description of the supported mode
|
||||
// values.
|
||||
//
|
||||
// An error is returned if the provided mode value is invalid, or if an error
|
||||
// occurs while persisting the mode value to the file system.
|
||||
func SetMode(mode string) error {
|
||||
return telemetry.SetMode(mode)
|
||||
}
|
13
src/cmd/vendor/golang.org/x/telemetry/npm
generated
vendored
Normal file
13
src/cmd/vendor/golang.org/x/telemetry/npm
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2022 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.
|
||||
|
||||
docker run \
|
||||
--rm \
|
||||
--volume $(pwd):/workspace \
|
||||
--workdir /workspace \
|
||||
--env NODE_OPTIONS="--dns-result-order=ipv4first" \
|
||||
--entrypoint npm \
|
||||
node:18.16.0-slim \
|
||||
$@
|
13
src/cmd/vendor/golang.org/x/telemetry/npx
generated
vendored
Normal file
13
src/cmd/vendor/golang.org/x/telemetry/npx
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2022 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.
|
||||
|
||||
docker run \
|
||||
--rm \
|
||||
--volume $(pwd):/workspace \
|
||||
--workdir /workspace \
|
||||
--env NODE_OPTIONS="--dns-result-order=ipv4first" \
|
||||
--entrypoint npx \
|
||||
node:18.16.0-slim \
|
||||
$@
|
4363
src/cmd/vendor/golang.org/x/telemetry/package-lock.json
generated
vendored
Normal file
4363
src/cmd/vendor/golang.org/x/telemetry/package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
src/cmd/vendor/golang.org/x/telemetry/package.json
generated
vendored
Normal file
23
src/cmd/vendor/golang.org/x/telemetry/package.json
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"scripts": {
|
||||
"eslint": "eslint . --fix",
|
||||
"stylelint": "stylelint '**/*.css' --fix",
|
||||
"prettier": "prettier --write **/*.{css,ts,md,yaml} !**/*.min.css",
|
||||
"all": "run-s --continue-on-error eslint stylelint prettier"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "5.59.6",
|
||||
"@typescript-eslint/parser": "5.59.6",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-config-prettier": "8.8.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"prettier": "2.8.8",
|
||||
"stylelint": "15.6.2",
|
||||
"stylelint-config-standard": "33.0.0",
|
||||
"typescript": "5.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@observablehq/plot": "0.6.9",
|
||||
"d3": "7.8.5"
|
||||
}
|
||||
}
|
213
src/cmd/vendor/golang.org/x/telemetry/start.go
generated
vendored
Normal file
213
src/cmd/vendor/golang.org/x/telemetry/start.go
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
// Copyright 2024 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 (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/telemetry/counter"
|
||||
"golang.org/x/telemetry/internal/crashmonitor"
|
||||
"golang.org/x/telemetry/internal/telemetry"
|
||||
"golang.org/x/telemetry/upload"
|
||||
)
|
||||
|
||||
// Config controls the behavior of [Start].
|
||||
type Config struct {
|
||||
// ReportCrashes, if set, will enable crash reporting.
|
||||
// ReportCrashes uses the [debug.SetCrashOutput] mechanism, which is a
|
||||
// process-wide resource.
|
||||
// Do not make other calls to that function within your application.
|
||||
// ReportCrashes is a non-functional unless the program is built with go1.23+.
|
||||
ReportCrashes bool
|
||||
|
||||
// Upload causes this program to periodically upload approved counters
|
||||
// from the local telemetry database to telemetry.go.dev.
|
||||
//
|
||||
// This option has no effect unless the user has given consent
|
||||
// to enable data collection, for example by running
|
||||
// cmd/gotelemetry or affirming the gopls dialog.
|
||||
//
|
||||
// (This feature is expected to be used only by gopls.
|
||||
// Longer term, the go command may become the sole program
|
||||
// responsible for uploading.)
|
||||
Upload bool
|
||||
}
|
||||
|
||||
// Start initializes telemetry using the specified configuration.
|
||||
//
|
||||
// Start opens the local telemetry database so that counter increment
|
||||
// operations are durably recorded in the local file system.
|
||||
//
|
||||
// If [Config.Upload] is set, and the user has opted in to telemetry
|
||||
// uploading, this process may attempt to upload approved counters
|
||||
// to telemetry.go.dev.
|
||||
//
|
||||
// If [Config.ReportCrashes] is set, any fatal crash will be
|
||||
// recorded by incrementing a counter named for the stack of the
|
||||
// first running goroutine in the traceback.
|
||||
//
|
||||
// If either of these flags is set, Start re-executes the current
|
||||
// executable as a child process, in a special mode in which it
|
||||
// acts as a telemetry sidecar for the parent process (the application).
|
||||
// In that mode, the call to Start will never return, so Start must
|
||||
// be called immediately within main, even before such things as
|
||||
// inspecting the command line. The application should avoid expensive
|
||||
// steps or external side effects in init functions, as they will
|
||||
// be executed twice (parent and child).
|
||||
func Start(config Config) {
|
||||
counter.Open()
|
||||
|
||||
// Crash monitoring and uploading both require a sidecar process.
|
||||
if (config.ReportCrashes && crashmonitor.Supported()) || config.Upload {
|
||||
if os.Getenv(telemetryChildVar) != "" {
|
||||
child(config)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
parent(config)
|
||||
}
|
||||
}
|
||||
|
||||
var daemonize = func(cmd *exec.Cmd) {}
|
||||
|
||||
const telemetryChildVar = "X_TELEMETRY_CHILD"
|
||||
|
||||
func parent(config Config) {
|
||||
// This process is the application (parent).
|
||||
// Fork+exec the telemetry child.
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cmd := exec.Command(exe, "** telemetry **") // this unused arg is just for ps(1)
|
||||
daemonize(cmd)
|
||||
cmd.Env = append(os.Environ(), telemetryChildVar+"=1")
|
||||
|
||||
// The child process must write to a log file, not
|
||||
// the stderr file it inherited from the parent, as
|
||||
// the child may outlive the parent but should not prolong
|
||||
// the life of any pipes created (by the grandparent)
|
||||
// to gather the output of the parent.
|
||||
//
|
||||
// By default, we discard the child process's stderr,
|
||||
// but in line with the uploader, log to a file in local/debug
|
||||
// only if that directory was created by the user.
|
||||
localDebug := filepath.Join(telemetry.LocalDir, "debug")
|
||||
fd, err := os.Stat(localDebug)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
log.Fatalf("failed to stat debug directory: %v", err)
|
||||
}
|
||||
} else if fd.IsDir() {
|
||||
// local/debug exists and is a directory. Set stderr to a log file path
|
||||
// in local/debug.
|
||||
childLogPath := filepath.Join(localDebug, "sidecar.log")
|
||||
childLog, err := os.OpenFile(childLogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
|
||||
if err != nil {
|
||||
log.Fatalf("opening sidecar log file for child: %v", err)
|
||||
}
|
||||
defer childLog.Close()
|
||||
cmd.Stderr = childLog
|
||||
}
|
||||
|
||||
if config.ReportCrashes {
|
||||
pipe, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
log.Fatalf("StdinPipe: %v", err)
|
||||
}
|
||||
|
||||
crashmonitor.Parent(pipe.(*os.File)) // (this conversion is safe)
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Fatalf("can't start telemetry child process: %v", err)
|
||||
}
|
||||
go cmd.Wait() // Release resources if cmd happens not to outlive this process.
|
||||
}
|
||||
|
||||
func child(config Config) {
|
||||
log.SetPrefix(fmt.Sprintf("telemetry-sidecar (pid %v): ", os.Getpid()))
|
||||
|
||||
// Start crashmonitoring and uploading depending on what's requested
|
||||
// and wait for the longer running child to complete before exiting:
|
||||
// if we collected a crash before the upload finished, wait for the
|
||||
// upload to finish before exiting
|
||||
var g errgroup.Group
|
||||
|
||||
if config.Upload {
|
||||
g.Go(func() error {
|
||||
uploaderChild()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if config.ReportCrashes {
|
||||
g.Go(func() error {
|
||||
crashmonitor.Child()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
g.Wait()
|
||||
}
|
||||
|
||||
func uploaderChild() {
|
||||
tokenfilepath := filepath.Join(telemetry.LocalDir, "upload.token")
|
||||
ok, err := acquireUploadToken(tokenfilepath)
|
||||
if err != nil {
|
||||
log.Printf("error acquiring upload token: %v", err)
|
||||
return
|
||||
} else if !ok {
|
||||
// It hasn't been a day since the last upload.Run attempt or there's
|
||||
// a concurrently running uploader.
|
||||
return
|
||||
}
|
||||
upload.Run(&upload.Control{Logger: os.Stderr})
|
||||
}
|
||||
|
||||
// acquireUploadToken acquires a token permitting the caller to upload.
|
||||
// To limit the frequency of uploads, only one token is issue per
|
||||
// machine per time period.
|
||||
// The boolean indicates whether the token was acquired.
|
||||
func acquireUploadToken(tokenfile string) (bool, error) {
|
||||
const period = 24 * time.Hour
|
||||
|
||||
// A process acquires a token by successfully creating a
|
||||
// well-known file. If the file already exists and has an
|
||||
// mtime age less then than the period, the process does
|
||||
// not acquire the token. If the file is older than the
|
||||
// period, the process is allowed to remove the file and
|
||||
// try to re-create it.
|
||||
fi, err := os.Stat(tokenfile)
|
||||
if err == nil {
|
||||
if time.Since(fi.ModTime()) < period {
|
||||
return false, nil
|
||||
}
|
||||
// There's a possible race here where two processes check the
|
||||
// token file and see that it's older than the period, then the
|
||||
// first one removes it and creates another, and then a second one
|
||||
// removes the newly created file and creates yet another
|
||||
// file. Then both processes would act as though they had the token.
|
||||
// This is very rare, but it's also okay because we're only grabbing
|
||||
// the token to do rate limiting, not for correctness.
|
||||
_ = os.Remove(tokenfile)
|
||||
} else if !os.IsNotExist(err) {
|
||||
return false, fmt.Errorf("statting token file: %v", err)
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(tokenfile, os.O_CREATE|os.O_EXCL, 0666)
|
||||
if err != nil {
|
||||
if os.IsExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("creating token file: %v", err)
|
||||
}
|
||||
_ = f.Close()
|
||||
return true, nil
|
||||
}
|
22
src/cmd/vendor/golang.org/x/telemetry/start_posix.go
generated
vendored
Normal file
22
src/cmd/vendor/golang.org/x/telemetry/start_posix.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func init() {
|
||||
daemonize = daemonizePosix
|
||||
}
|
||||
|
||||
func daemonizePosix(cmd *exec.Cmd) {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
Setsid: true,
|
||||
}
|
||||
}
|
29
src/cmd/vendor/golang.org/x/telemetry/start_windows.go
generated
vendored
Normal file
29
src/cmd/vendor/golang.org/x/telemetry/start_windows.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2024 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.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func init() {
|
||||
daemonize = daemonizeWindows
|
||||
}
|
||||
|
||||
func daemonizeWindows(cmd *exec.Cmd) {
|
||||
// Set DETACHED_PROCESS creation flag so that closing
|
||||
// the console window the parent process was run in
|
||||
// does not kill the child.
|
||||
// See documentation of creation flags in the Microsoft documentation:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
CreationFlags: windows.DETACHED_PROCESS,
|
||||
}
|
||||
}
|
26
src/cmd/vendor/golang.org/x/telemetry/tsconfig.json
generated
vendored
Normal file
26
src/cmd/vendor/golang.org/x/telemetry/tsconfig.json
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "node",
|
||||
|
||||
"strict": true,
|
||||
"allowUnusedLabels": false,
|
||||
"allowUnreachableCode": false,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
|
||||
"checkJs": true,
|
||||
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
}
|
21
src/cmd/vendor/golang.org/x/telemetry/types_alias.go
generated
vendored
Normal file
21
src/cmd/vendor/golang.org/x/telemetry/types_alias.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2024 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 "golang.org/x/telemetry/internal/telemetry"
|
||||
|
||||
// Common types and directories used by multiple packages.
|
||||
|
||||
// An UploadConfig controls what data is uploaded.
|
||||
type UploadConfig = telemetry.UploadConfig
|
||||
|
||||
type ProgramConfig = telemetry.ProgramConfig
|
||||
|
||||
type CounterConfig = telemetry.CounterConfig
|
||||
|
||||
// A Report is what's uploaded (or saved locally)
|
||||
type Report = telemetry.Report
|
||||
|
||||
type ProgramReport = telemetry.ProgramReport
|
38
src/cmd/vendor/golang.org/x/telemetry/upload/upload.go
generated
vendored
Normal file
38
src/cmd/vendor/golang.org/x/telemetry/upload/upload.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// 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 upload
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"golang.org/x/telemetry/internal/upload"
|
||||
)
|
||||
|
||||
// Run generates and uploads reports, as allowed by the mode file.
|
||||
// A nil Control is legal.
|
||||
func Run(c *Control) {
|
||||
if c != nil && c.Logger != nil {
|
||||
upload.SetLogOutput(c.Logger)
|
||||
}
|
||||
// ignore error: failed logging should not block uploads
|
||||
upload.LogIfDebug("")
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Printf("upload recover: %v", err)
|
||||
}
|
||||
}()
|
||||
upload.NewUploader(nil).Run()
|
||||
}
|
||||
|
||||
// A Control allows the user to override various default
|
||||
// reporting and uploading choices.
|
||||
// Future versions may also allow the user to set the upload URL.
|
||||
type Control struct {
|
||||
// Logger provides a io.Writer for error messages during uploading
|
||||
// nil is legal and no log messages get generated
|
||||
Logger io.Writer
|
||||
}
|
8
src/cmd/vendor/modules.txt
vendored
8
src/cmd/vendor/modules.txt
vendored
@ -38,6 +38,7 @@ golang.org/x/mod/sumdb/tlog
|
||||
golang.org/x/mod/zip
|
||||
# golang.org/x/sync v0.6.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/sync/errgroup
|
||||
golang.org/x/sync/semaphore
|
||||
# golang.org/x/sys v0.17.0
|
||||
## explicit; go 1.18
|
||||
@ -46,10 +47,17 @@ golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
# golang.org/x/telemetry v0.0.0-20240229223025-3d5706d2d0fb
|
||||
## explicit; go 1.20
|
||||
golang.org/x/telemetry
|
||||
golang.org/x/telemetry/counter
|
||||
golang.org/x/telemetry/counter/countertest
|
||||
golang.org/x/telemetry/internal/config
|
||||
golang.org/x/telemetry/internal/configstore
|
||||
golang.org/x/telemetry/internal/counter
|
||||
golang.org/x/telemetry/internal/crashmonitor
|
||||
golang.org/x/telemetry/internal/mmap
|
||||
golang.org/x/telemetry/internal/telemetry
|
||||
golang.org/x/telemetry/internal/upload
|
||||
golang.org/x/telemetry/upload
|
||||
# golang.org/x/term v0.17.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/term
|
||||
|
Loading…
x
Reference in New Issue
Block a user