Source file src/cmd/vendor/golang.org/x/telemetry/counter/counter.go
1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package counter 6 7 // The implementation of this package and tests are located in 8 // internal/counter, which can be shared with the upload package. 9 // TODO(hyangah): use of type aliases prevents nice documentation 10 // rendering in go doc or pkgsite. Fix this either by avoiding 11 // type aliasing or restructuring the internal/counter package. 12 import ( 13 "flag" 14 "path" 15 "runtime/debug" 16 17 "golang.org/x/telemetry/internal/counter" 18 "golang.org/x/telemetry/internal/telemetry" 19 ) 20 21 // Inc increments the counter with the given name. 22 func Inc(name string) { 23 New(name).Inc() 24 } 25 26 // Add adds n to the counter with the given name. 27 func Add(name string, n int64) { 28 New(name).Add(n) 29 } 30 31 // New returns a counter with the given name. 32 // New can be called in global initializers and will be compiled down to 33 // linker-initialized data. That is, calling New to initialize a global 34 // has no cost at program startup. 35 // 36 // See "Counter Naming" in the package doc for a description of counter naming 37 // conventions. 38 func New(name string) *Counter { 39 // Note: not calling DefaultFile.New in order to keep this 40 // function something the compiler can inline and convert 41 // into static data initializations, with no init-time footprint. 42 // TODO(hyangah): is it trivial enough for the compiler to inline? 43 return counter.New(name) 44 } 45 46 // A Counter is a single named event counter. 47 // A Counter is safe for use by multiple goroutines simultaneously. 48 // 49 // Counters should typically be created using New 50 // and stored as global variables, like: 51 // 52 // package mypackage 53 // var errorCount = counter.New("mypackage/errors") 54 // 55 // (The initialization of errorCount in this example is handled 56 // entirely by the compiler and linker; this line executes no code 57 // at program startup.) 58 // 59 // Then code can call Add to increment the counter 60 // each time the corresponding event is observed. 61 // 62 // Although it is possible to use New to create 63 // a Counter each time a particular event needs to be recorded, 64 // that usage fails to amortize the construction cost over 65 // multiple calls to Add, so it is more expensive and not recommended. 66 type Counter = counter.Counter 67 68 // A StackCounter is the in-memory knowledge about a stack counter. 69 // StackCounters are more expensive to use than regular Counters, 70 // requiring, at a minimum, a call to runtime.Callers. 71 type StackCounter = counter.StackCounter 72 73 // NewStack returns a new stack counter with the given name and depth. 74 // 75 // See "Counter Naming" in the package doc for a description of counter naming 76 // conventions. 77 func NewStack(name string, depth int) *StackCounter { 78 return counter.NewStack(name, depth) 79 } 80 81 // Open prepares telemetry counters for recording to the file system. 82 // 83 // If the telemetry mode is "off", Open is a no-op. Otherwise, it opens the 84 // counter file on disk and starts to mmap telemetry counters to the file. 85 // Open also persists any counters already created in the current process. 86 // 87 // Open should only be called from short-lived processes such as command line 88 // tools. If your process is long-running, use [OpenAndRotate]. 89 func Open() { 90 counter.Open(false) 91 } 92 93 // OpenAndRotate is like [Open], but also schedules a rotation of the counter 94 // file when it expires. 95 // 96 // See golang/go#68497 for background on why [OpenAndRotate] is a separate API. 97 // 98 // TODO(rfindley): refactor Open and OpenAndRotate for Go 1.24. 99 func OpenAndRotate() { 100 counter.Open(true) 101 } 102 103 // OpenDir prepares telemetry counters for recording to the file system, using 104 // the specified telemetry directory, if it is not the empty string. 105 // 106 // If the telemetry mode is "off", Open is a no-op. Otherwise, it opens the 107 // counter file on disk and starts to mmap telemetry counters to the file. 108 // Open also persists any counters already created in the current process. 109 func OpenDir(telemetryDir string) { 110 if telemetryDir != "" { 111 telemetry.Default = telemetry.NewDir(telemetryDir) 112 } 113 counter.Open(false) 114 } 115 116 // CountFlags creates a counter for every flag that is set 117 // and increments the counter. The name of the counter is 118 // the concatenation of prefix and the flag name. 119 // 120 // For instance, CountFlags("gopls/flag:", *flag.CommandLine) 121 func CountFlags(prefix string, fs flag.FlagSet) { 122 fs.Visit(func(f *flag.Flag) { 123 New(prefix + f.Name).Inc() 124 }) 125 } 126 127 // CountCommandLineFlags creates a counter for every flag 128 // that is set in the default flag.CommandLine FlagSet using 129 // the counter name binaryName+"/flag:"+flagName where 130 // binaryName is the base name of the Path embedded in the 131 // binary's build info. If the binary does not have embedded build 132 // info, the "flag:"+flagName counter will be incremented. 133 // 134 // CountCommandLineFlags must be called after flags are parsed 135 // with flag.Parse. 136 // 137 // For instance, if the -S flag is passed to cmd/compile and 138 // CountCommandLineFlags is called after flags are parsed, 139 // the "compile/flag:S" counter will be incremented. 140 func CountCommandLineFlags() { 141 prefix := "flag:" 142 if buildInfo, ok := debug.ReadBuildInfo(); ok && buildInfo.Path != "" { 143 prefix = path.Base(buildInfo.Path) + "/" + prefix 144 } 145 CountFlags(prefix, *flag.CommandLine) 146 } 147