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"
|
"cmd/internal/sys"
|
||||||
|
|
||||||
cmdgo "cmd/go"
|
cmdgo "cmd/go"
|
||||||
|
|
||||||
|
"golang.org/x/telemetry/counter/countertest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -153,6 +155,15 @@ func TestMain(m *testing.M) {
|
|||||||
web.EnableTestHooks(interceptors)
|
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()
|
cmdgo.Main()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// 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=^TestDocsUpToDate$ -fixdocs
|
||||||
|
//go:generate go test cmd/go -v -run=^TestCounterNamesUpToDate$ -update
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ var _ = go11tag
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(0)
|
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()
|
handleChdirFlag()
|
||||||
toolchain.Select()
|
toolchain.Select()
|
||||||
|
|
||||||
@ -153,7 +154,6 @@ func main() {
|
|||||||
|
|
||||||
cmd, used := lookupCmd(args)
|
cmd, used := lookupCmd(args)
|
||||||
cfg.CmdName = strings.Join(args[:used], " ")
|
cfg.CmdName = strings.Join(args[:used], " ")
|
||||||
counter.Inc("cmd/go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-"))
|
|
||||||
if len(cmd.Commands) > 0 {
|
if len(cmd.Commands) > 0 {
|
||||||
if used >= len(args) {
|
if used >= len(args) {
|
||||||
help.PrintUsage(os.Stderr, cmd)
|
help.PrintUsage(os.Stderr, cmd)
|
||||||
@ -162,6 +162,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
if args[used] == "help" {
|
if args[used] == "help" {
|
||||||
// Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'.
|
// 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:]...))
|
help.Help(os.Stdout, append(slices.Clip(args[:used]), args[used+1:]...))
|
||||||
base.Exit()
|
base.Exit()
|
||||||
}
|
}
|
||||||
@ -173,10 +174,12 @@ func main() {
|
|||||||
if cmdName == "" {
|
if cmdName == "" {
|
||||||
cmdName = args[0]
|
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)
|
fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cmdName, helpArg)
|
||||||
base.SetExitStatus(2)
|
base.SetExitStatus(2)
|
||||||
base.Exit()
|
base.Exit()
|
||||||
}
|
}
|
||||||
|
counter.Inc("cmd/go/subcommand:" + strings.ReplaceAll(cfg.CmdName, " ", "-"))
|
||||||
invoke(cmd, args[used-1:])
|
invoke(cmd, args[used-1:])
|
||||||
base.Exit()
|
base.Exit()
|
||||||
}
|
}
|
||||||
@ -241,7 +244,7 @@ func invoke(cmd *base.Command, args []string) {
|
|||||||
} else {
|
} else {
|
||||||
base.SetFromGOFLAGS(&cmd.Flag)
|
base.SetFromGOFLAGS(&cmd.Flag)
|
||||||
cmd.Flag.Parse(args[1:])
|
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()
|
args = cmd.Flag.Args()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +329,7 @@ func handleChdirFlag() {
|
|||||||
_, dir, _ = strings.Cut(a, "=")
|
_, dir, _ = strings.Cut(a, "=")
|
||||||
os.Args = slices.Delete(os.Args, used, used+1)
|
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 {
|
if err := os.Chdir(dir); err != nil {
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
_ "embed"
|
||||||
"flag"
|
"flag"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"internal/txtar"
|
"internal/txtar"
|
||||||
@ -21,6 +22,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -29,6 +31,8 @@ import (
|
|||||||
"cmd/go/internal/script"
|
"cmd/go/internal/script"
|
||||||
"cmd/go/internal/script/scripttest"
|
"cmd/go/internal/script/scripttest"
|
||||||
"cmd/go/internal/vcweb/vcstest"
|
"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.`)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
initScriptDirs(t, s)
|
telemetryDir := initScriptDirs(t, s)
|
||||||
if err := s.ExtractFiles(a); err != nil {
|
if err := s.ExtractFiles(a); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -154,6 +158,7 @@ func TestScript(t *testing.T) {
|
|||||||
// will work better seeing the full path relative to cmd/go
|
// will work better seeing the full path relative to cmd/go
|
||||||
// (where the "go test" command is usually run).
|
// (where the "go test" command is usually run).
|
||||||
scripttest.Run(t, engine, s, file, bytes.NewReader(a.Comment))
|
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
|
// initScriptState creates the initial directory structure in s for unpacking a
|
||||||
// cmd/go script.
|
// 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) {
|
must := func(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@ -188,6 +193,10 @@ func initScriptDirs(t testing.TB, s *script.State) {
|
|||||||
work := s.Getwd()
|
work := s.Getwd()
|
||||||
must(s.Setenv("WORK", work))
|
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(os.MkdirAll(filepath.Join(work, "tmp"), 0777))
|
||||||
must(s.Setenv(tempEnvName(), filepath.Join(work, "tmp")))
|
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")
|
gopathSrc := filepath.Join(gopath, "src")
|
||||||
must(os.MkdirAll(gopathSrc, 0777))
|
must(os.MkdirAll(gopathSrc, 0777))
|
||||||
must(s.Chdir(gopathSrc))
|
must(s.Chdir(gopathSrc))
|
||||||
|
return telemetryDir
|
||||||
}
|
}
|
||||||
|
|
||||||
func scriptEnv(srv *vcstest.Server, srvCertFile string) ([]string, error) {
|
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
|
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/mod/zip
|
||||||
# golang.org/x/sync v0.6.0
|
# golang.org/x/sync v0.6.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
|
golang.org/x/sync/errgroup
|
||||||
golang.org/x/sync/semaphore
|
golang.org/x/sync/semaphore
|
||||||
# golang.org/x/sys v0.17.0
|
# golang.org/x/sys v0.17.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
@ -46,10 +47,17 @@ golang.org/x/sys/unix
|
|||||||
golang.org/x/sys/windows
|
golang.org/x/sys/windows
|
||||||
# golang.org/x/telemetry v0.0.0-20240229223025-3d5706d2d0fb
|
# golang.org/x/telemetry v0.0.0-20240229223025-3d5706d2d0fb
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
|
golang.org/x/telemetry
|
||||||
golang.org/x/telemetry/counter
|
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/counter
|
||||||
|
golang.org/x/telemetry/internal/crashmonitor
|
||||||
golang.org/x/telemetry/internal/mmap
|
golang.org/x/telemetry/internal/mmap
|
||||||
golang.org/x/telemetry/internal/telemetry
|
golang.org/x/telemetry/internal/telemetry
|
||||||
|
golang.org/x/telemetry/internal/upload
|
||||||
|
golang.org/x/telemetry/upload
|
||||||
# golang.org/x/term v0.17.0
|
# golang.org/x/term v0.17.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
golang.org/x/term
|
golang.org/x/term
|
||||||
|
Loading…
x
Reference in New Issue
Block a user