src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

counter.go (5278B)


      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 }