|
| 1 | +--- |
| 2 | +title: "Go Telemetry" |
| 3 | +layout: article |
| 4 | +breadcrumb: true |
| 5 | +date: 2024-02-07:00:00Z |
| 6 | +--- |
| 7 | + |
| 8 | +Table of Contents: |
| 9 | + |
| 10 | + [Background](#background)\ |
| 11 | + [Overview](#overview)\ |
| 12 | + [Configuration](#config)\ |
| 13 | + [Counters](#counters)\ |
| 14 | + [Reporting and Uploading](#reports)\ |
| 15 | + [Charts](#charts) \ |
| 16 | + [IDE Prompting](#ide) \ |
| 17 | + [Frequently Asked Questions](#faq) |
| 18 | + |
| 19 | +## Background {#background} |
| 20 | + |
| 21 | +Go telemetry is a way for Go toolchain programs to collect data about their |
| 22 | +performance and usage. Here "Go toolchain" means developer tools maintained |
| 23 | +by the Go team, including the `go` command and supplemental tools such as the |
| 24 | +Go language server `gopls` or Go security tool `govulncheck`. Go telemetry is |
| 25 | +only intended for use in programs maintained by the Go team. |
| 26 | + |
| 27 | +By default, telemetry data is kept only on the local computer, but users may |
| 28 | +opt in to uploading an approved subset of telemetry data to [telemetry.go.dev]. |
| 29 | +Uploaded data helps the Go team improve the Go language and its tools, |
| 30 | +by helping us understand usage and breakages. |
| 31 | + |
| 32 | +The word "telemetry" has acquired negative connotations in the world of open |
| 33 | +source software, in many cases deservedly so. Yet measuring the user experience |
| 34 | +is an important element of modern software engineering, and data sources such |
| 35 | +as GitHub issues or annual surveys are coarse and lagging indicators, |
| 36 | +insufficient for the types of questions the Go team needs to be able to answer. |
| 37 | +Go telemetry is designed to help programs in the toolchain collect useful data |
| 38 | +about their reliability, performance, and usage, while maintaining the |
| 39 | +transparency and privacy that users expect from the Go project. To learn more |
| 40 | +about the design process and motivation for telemetry, please see the |
| 41 | +[telemetry blog posts](https://research.swtch.com/telemetry). |
| 42 | +To learn more about telemetry and privacy, please see the |
| 43 | +[telemetry privacy policy](https://telemetry.go.dev/privacy). |
| 44 | + |
| 45 | +This page explains how Go telemetry works, in some detail. For quick answers to |
| 46 | +frequently asked questions, see the [FAQ](#faq). |
| 47 | + |
| 48 | +## Overview {#overview} |
| 49 | + |
| 50 | +Go telemetry uses three core data types: |
| 51 | + |
| 52 | +- [_Counters_](#counters) are lightweight counts of named events, instrumented |
| 53 | + in the toolchain program. If collection is enabled (the [mode](#config) |
| 54 | + is **local** or **on**), counters are written to a memory-mapped file in the |
| 55 | + local file system. |
| 56 | +- [_Reports_](#reports) are aggregated summaries of counters for a given week. |
| 57 | + If uploading is enabled (the [mode](#config) is **on**), reports for |
| 58 | + [approved counters](#proposals) are uploaded to [telemetry.go.dev], where |
| 59 | + they are publicly accessible. |
| 60 | +- [_Charts_](#charts) summarize uploaded reports for all users. |
| 61 | + Charts can be viewed at [telemetry.go.dev]. |
| 62 | + |
| 63 | +All local Go telemetry data and configuration is stored in the directory |
| 64 | +<code>[os.UserConfigDir()](/pkg/os#UserConfigDir)/go/telemetry</code> |
| 65 | +directory. Below, we'll refer to this directory as `<gotelemetry>`. |
| 66 | + |
| 67 | +The diagram below illustrates this data flow. |
| 68 | + |
| 69 | +<div class="image"> |
| 70 | + <center> |
| 71 | + <img max-width="800px" src="/doc/telemetry/dataflow.png" /> |
| 72 | + </center> |
| 73 | +</div> |
| 74 | + |
| 75 | +In the rest of this document, we'll explore the components of this diagram. But |
| 76 | +first, let's learn more about the configuration that controls it. |
| 77 | + |
| 78 | +## Configuration {#config} |
| 79 | + |
| 80 | +The behavior of Go telemetry is controlled by a single value: the telemetry |
| 81 | +_mode_. The possible values for `mode` are `local` (the default), `on`, or |
| 82 | +`off`: |
| 83 | + |
| 84 | +- When `mode` is `local`, telemetry data is collected and stored on the local |
| 85 | + computer, but never uploaded to remote servers. |
| 86 | +- When `mode` is `on`, data is collected, and may be uploaded depending on |
| 87 | + [sampling](#uploads). |
| 88 | +- When `mode` is `off`, data is neither collected nor uploaded. |
| 89 | + |
| 90 | +The [`gotelemetry`](/pkg/golang.org/x/telemetry/cmd/gotelemetry) command |
| 91 | +configures the telemetry mode and manages local telemetry data. Use this |
| 92 | +command to install it: |
| 93 | + |
| 94 | +``` |
| 95 | +go install golang.org/x/telemetry/cmd/gotelemetry@latest |
| 96 | +``` |
| 97 | + |
| 98 | +The following commands interact with the telemetry mode: |
| 99 | + |
| 100 | +- `gotelemetry local`: set the mode to `local`. |
| 101 | +- `gotelemetry on`: set the mode to `on`. |
| 102 | +- `gotelemetry off`: set the mode to `off`. |
| 103 | +- `gotelemetry env`: see the current mode. |
| 104 | + |
| 105 | +For the complete usage information of the `gotelemetry` command line tool, |
| 106 | +see its [package documentation](/pkg/golang.org/x/telemetry/cmd/gotelemetry). |
| 107 | + |
| 108 | +Telemetry may also be enabled by accepting an [IDE prompt](#ide). |
| 109 | + |
| 110 | +## Counters {#counters} |
| 111 | + |
| 112 | +As mentioned above, Go telemetry is instrumented via _counters_. Counters come |
| 113 | +in two variants: basic counters and stack counters. |
| 114 | + |
| 115 | +### Basic counters |
| 116 | + |
| 117 | +A _basic counter_ is an incrementable value with a name that describes the |
| 118 | +event that it counts. For example, the `gopls/client:vscode` counter records |
| 119 | +the number of times a `gopls` session is initiated by VS Code. Alongside this |
| 120 | +counter we may have `gopls/client:neovim`, `gopls/client:eglot`, and so on, to |
| 121 | +record sessions with different editors or language clients. If you used |
| 122 | +multiple editors throughout the week, you might record the following counter |
| 123 | +data: |
| 124 | + |
| 125 | + gopls/client:vscode 8 |
| 126 | + gopls/client:neovim 5 |
| 127 | + gopls/client:eglot 2 |
| 128 | + |
| 129 | +When counters are related in this way, we sometimes refer to the part before |
| 130 | +the `:` the _chart name_ (`gopls/client` in this case), and the part after `:` |
| 131 | +as the _bucket name_ (`vscode`). We'll see why this matters when we discuss |
| 132 | +[charts](#charts). |
| 133 | + |
| 134 | +Basic counters can also represent a _histogram_. For example, the {{raw |
| 135 | +`<code>gopls/completion/latency:<50ms</code>`}} counter records the number |
| 136 | +of times an autocompletion takes less than 50ms. |
| 137 | + |
| 138 | +{{raw ` |
| 139 | +<pre> |
| 140 | +gopls/completion/latency:<10ms |
| 141 | +gopls/completion/latency:<50ms |
| 142 | +gopls/completion/latency:<100ms |
| 143 | +... |
| 144 | +</pre> |
| 145 | +`}} |
| 146 | + |
| 147 | +This pattern for recording histogram data is a convention: there's nothing |
| 148 | +special about the {{raw `<code><50ms</code>`}} bucket name. These types of |
| 149 | +counters are commonly used to measure performance. |
| 150 | + |
| 151 | +### Stack counters |
| 152 | + |
| 153 | +A _stack counter_ is a counter that also records the current call stack of the |
| 154 | +Go toolchain program when the count is incremented. For example, the |
| 155 | +`crash/crash` stack counter records the call stack when a toolchain program |
| 156 | +crashes: |
| 157 | + |
| 158 | + crash/crash |
| 159 | + golang.org/x/tools/gopls/internal/golang.hoverBuiltin:+22 |
| 160 | + golang.org/x/tools/gopls/internal/golang.Hover:+94 |
| 161 | + golang.org/x/tools/gopls/internal/server.Hover:+42 |
| 162 | + ... |
| 163 | + |
| 164 | +Stack counters typically measure events where program invariants are violated. |
| 165 | +The most common example of this is a crash, but another example is the |
| 166 | +`gopls/bug` stack counter, which counts unusual situations identified in |
| 167 | +advance by the programmer, such as a recovered panic or an error that "can't |
| 168 | +happen". Stack counters include only the names and line numbers of functions |
| 169 | +within Go toolchain programs. They don't include any information about user |
| 170 | +inputs, such as the names or contents of a user's source code. |
| 171 | + |
| 172 | +Stack counters can help track down rare or tricky bugs that don't get reported |
| 173 | +by other means. Since introducing the `gopls/bug` counter, we've found |
| 174 | +[dozens of instances](https://github.com/golang/go/issues?q=label%3Agopls%2Ftelemetry-wins) |
| 175 | +of "unreachable" code that was reached in practice, and tracking down these |
| 176 | +exceptions has led to the discovery (and fix) of many user-visible bugs that |
| 177 | +were either not obvious to the user or too difficult to report. Especially with |
| 178 | +prerelease testing, stack counters can help us improve the product more |
| 179 | +efficiently than we could without automation. |
| 180 | + |
| 181 | +### Counter files |
| 182 | + |
| 183 | +All counter data is written to the `<gotelemetry>/local` directory, in |
| 184 | +files named according to the following schema: |
| 185 | + |
| 186 | +``` |
| 187 | +[program name]@[program version]-[go version]-[GOOS]-[GOARCH]-[date].v1.count |
| 188 | +``` |
| 189 | + |
| 190 | +- The **program name** is the basename of the program's package path, as reported |
| 191 | + by [debug.BuildInfo]. |
| 192 | +- The **program version** and **go version** are also reported by [debug.BuildInfo]. |
| 193 | +- The **GOOS** and **GOARCH** values are reported by |
| 194 | + [`runtime.GOOS`](/pkg/runtime#GOOS) and |
| 195 | + [`runtime.GOARCH`](/pkg/runtime#GOARCH). |
| 196 | +- The **date** is the date the counter file was created, in `YYYY-MM-DD` format. |
| 197 | + |
| 198 | +These files are memory mapped into each running instance of the instrumented |
| 199 | +programs. The use of a memory-mapped file means that even if the program |
| 200 | +immediately crashes, or several copies of instrumented tools are running |
| 201 | +simultaneously, the counters are recorded safely. |
| 202 | + |
| 203 | +## Reporting and uploading {#reports} |
| 204 | + |
| 205 | +Approximately once a week, counter data gets aggregated into reports named |
| 206 | +`<date>.json` in the `<gotelemetry>/local` directory. These reports sum all of |
| 207 | +counts for the previous week, grouped by the same program identifiers used for |
| 208 | +the counter file (program name, program version, go version, GOOS, and GOARCH). |
| 209 | + |
| 210 | +Local reports can be viewed as charts with the |
| 211 | +[`gotelemetry view`](/pkg/golang.org/x/telemetry/cmd/gotelemetry) command. |
| 212 | +Here's an example summary of the `gopls/completion/latency` counter: |
| 213 | + |
| 214 | +<div class="image"> |
| 215 | + <center> |
| 216 | + <img max-width="800px" src="/doc/telemetry/gopls-latency.png" /> |
| 217 | + </center> |
| 218 | +</div> |
| 219 | + |
| 220 | +### Uploading {#uploads} |
| 221 | + |
| 222 | +If telemetry uploading is enabled, the weekly reporting process will also |
| 223 | +generate reports containing the subset of counters present in the |
| 224 | +[upload config](https://telemetry.go.dev/config). These counters must be |
| 225 | +approved by the public review process described in the next section. After it |
| 226 | +has been successfully uploaded, a copy of the uploaded reports are stored in |
| 227 | +the `<gotelemetry>/upload` directory. |
| 228 | + |
| 229 | +Once enough users opt in to uploading telemetry data, the upload process will |
| 230 | +randomly skip uploading for a fraction of reports, to reduce collection amounts |
| 231 | +and increase privacy while maintaining statistical significance. |
| 232 | + |
| 233 | +### The telemetry proposal process {#proposals} |
| 234 | + |
| 235 | +Counters may be added to the upload configuration only through the _telemetry |
| 236 | +proposal process_, which proceeds as follows: |
| 237 | + |
| 238 | +1. The proposer files a [proposal] to upload new data. This is expressed in the |
| 239 | + form of a specific [chart](#charts) that will be displayed on |
| 240 | + [telemetry.go.dev]. |
| 241 | +2. Once discussion on the issue resolves, the proposal is approved or declined |
| 242 | + by a member of the Go team. |
| 243 | +3. The proposer sends a CL modifying the internal |
| 244 | + [chart config](https://go.googlesource.com/telemetry/+/refs/heads/master/internal/configgen/config.txt) |
| 245 | + to include the new chart. |
| 246 | +4. An automatic process regenerates the upload config to allow uploading of the |
| 247 | + counters required for the new chart. This process will also regularly add |
| 248 | + new versions of the relevant programs to the upload config as they are |
| 249 | + released. |
| 250 | + |
| 251 | +In order to be approved, new charts cannot carry sensitive user information, |
| 252 | +and additionally must be both useful and feasible. In order to be _useful_, |
| 253 | +charts must serve a specific purpose, with actionable outcomes, that can't be |
| 254 | +served by other means. For example, in order to collect a counter that measures |
| 255 | +the latency of a given operation, it must be shown that this latency can't |
| 256 | +reasonably be measured via benchmarking, and that knowing the latency |
| 257 | +distribution will help meaningfully improve future versions of the program in |
| 258 | +question. In order to be _feasible_, it must be possible to reliably collect |
| 259 | +the requisite data, and the resulting measurements must be statistically |
| 260 | +significant. To demonstrate feasibility, the proposer may be asked to instrument |
| 261 | +the target program with counters and collect them locally first. |
| 262 | + |
| 263 | +The full set of such proposals is available at the |
| 264 | +[proposal project](https://github.com/orgs/golang/projects/29) on GitHub. |
| 265 | + |
| 266 | +## Charts {#charts} |
| 267 | + |
| 268 | +In addition to accepting uploads, the [telemetry.go.dev] website makes uploaded |
| 269 | +data publicly available. Each day, uploaded reports are processed into two |
| 270 | +outputs, which are available on the [telemetry.go.dev] homepage. |
| 271 | + |
| 272 | +- _merged_ reports merged counters from all uploads received on the given day. |
| 273 | +- _charts_ plot uploaded data as specified in the [chart config], which was |
| 274 | + produced as part of the proposal process. Recall from the discussion of |
| 275 | + [counters](#counters) that counter names such as `foo:bar` are decomposed |
| 276 | + into the chart name `foo` and bucket name `bar`. Each chart aggregates |
| 277 | + counters with the same chart name into the corresponding buckets. |
| 278 | + |
| 279 | +Charts are specified in the [chart config] format. For example, here's the |
| 280 | +chart config for the `gopls/client` chart. |
| 281 | + |
| 282 | + title: Editor Distribution |
| 283 | + counter: gopls/client:{vscode,vscodium,vscode-insiders,code-server,eglot,govim,neovim,coc.nvim,sublimetext,other} |
| 284 | + description: measure editor distribution for gopls users. |
| 285 | + type: partition |
| 286 | + issue: https://go.dev/issue/61038 |
| 287 | + issue: https://go.dev/issue/62214 # add vscode-insiders |
| 288 | + program: golang.org/x/tools/gopls |
| 289 | + version: v0.13.0 # temporarily back-version to demonstrate config generation. |
| 290 | + |
| 291 | +This configuration describes the chart to be produced, enumerates the set of |
| 292 | +counters to be aggregated, and specifies the program versions to which the |
| 293 | +chart applies. Additionally, the [proposal process](#proposals) requires that |
| 294 | +an accepted proposal be associated with the chart. Here's the chart resulting |
| 295 | +from that config: |
| 296 | + |
| 297 | +<div class="image"> |
| 298 | + <center> |
| 299 | + <img src="/doc/telemetry/gopls-clients.png" /> |
| 300 | + </center> |
| 301 | +</div> |
| 302 | + |
| 303 | +## IDE Prompting {#ide} |
| 304 | + |
| 305 | +For telemetry to answer the types of questions we want to ask of it, the set of |
| 306 | +users opting in to uploading need not be large--approximately 16,000 |
| 307 | +participants would allow for statistically significant measurements at the |
| 308 | +desired level of granularity. However, there is still a cost to assembling this |
| 309 | +healthy sample: we need to ask a large number of Go developers if they want to |
| 310 | +opt in. |
| 311 | + |
| 312 | +Furthermore, even if a large number of users choose to opt in _now_ (perhaps |
| 313 | +after reading a Go blog post), those users may be skewed toward experienced Go |
| 314 | +developers, and over time that initial sample will grow even more skewed. |
| 315 | +Also, as people replace their computers, they must actively choose to opt in |
| 316 | +again. In the telemetry blog post series, this is referred to as the |
| 317 | +["campaign cost"](https://research.swtch.com/telemetry-opt-in#campaign) of |
| 318 | +the opt-in model. |
| 319 | + |
| 320 | +To help keep the sample of participating users fresh, the Go language server |
| 321 | +[`gopls`] supports a prompt that asks users to opt in to Go telemetry. |
| 322 | +Here's what that looks like from VS Code: |
| 323 | + |
| 324 | +<div class="image"> |
| 325 | + <center> |
| 326 | + <img width="600px" src="/doc/telemetry/prompt.png" /> |
| 327 | + </center> |
| 328 | +</div> |
| 329 | + |
| 330 | +If users choose "Yes", their telemetry [mode](#config) will be set to `on`, |
| 331 | +just as if they had run |
| 332 | +[`gotelemetry on`](/pkg/golang.org/x/telemetry/cmd/gotelemetry). In this way, |
| 333 | +opting in is as easy as possible, and we can continually reach a large and |
| 334 | +stratified sample of Go developers. |
| 335 | + |
| 336 | +## Frequently Asked Question {#faq} |
| 337 | + |
| 338 | +**Q: How do I enable or disable Go telemetry?** |
| 339 | + |
| 340 | +A: Use the `gotelemetry` command, which can be installed with `go install |
| 341 | +golang.org/x/telemetry/cmd/gotelemetry@latest`. Run `gotelemetry off` to |
| 342 | +disable everything, even local collection. Run `gotelemetry on` to enable |
| 343 | +everything, including uploading approved counters to [telemetry.go.dev]. See |
| 344 | +the [Configuration](#config) section for more info. |
| 345 | + |
| 346 | +**Q: Where does local data get stored?** |
| 347 | + |
| 348 | +A: In the <code>[os.UserConfigDir()](/pkg/os#UserConfigDir)/go/telemetry</code> directory. |
| 349 | + |
| 350 | +**Q: How often does data get uploaded, if I opt in?** |
| 351 | + |
| 352 | +A: Approximately once a week. |
| 353 | + |
| 354 | +**Q: What data gets uploaded, if I opt in?** |
| 355 | + |
| 356 | +A: Only counters that are listed in the |
| 357 | +[upload config](https://telemetry.go.dev/config) may be uploaded. |
| 358 | +This is generated from the [chart config], which may be more readable. |
| 359 | + |
| 360 | +**Q: How do counters get added to the upload config?** |
| 361 | + |
| 362 | +A: Through the [public proposal process](#proposals). |
| 363 | + |
| 364 | +**Q: Where can I see telemetry data that has been uploaded?** |
| 365 | + |
| 366 | +A: Uploaded data is available as charts or merged summaries at [telemetry.go.dev]. |
| 367 | + |
| 368 | +**Q: Where is the source code for Go telemetry?** |
| 369 | + |
| 370 | +A: At [golang.org/x/telemetry](/pkg/golang.org/x/telemetry). |
| 371 | + |
| 372 | +[`gopls`]: /pkg/golang.org/x/tools/gopls |
| 373 | +[debug.BuildInfo]: /pkg/runtime/debug#BuildInfo |
| 374 | +[proposal]: /issue/new?assignees=&labels=Telemetry-Proposal&projects=golang%2F29&template=12-telemetry.yml&title=x%2Ftelemetry%2Fconfig%3A+proposal+title |
| 375 | +[telemetry.go.dev]: https://telemetry.go.dev |
| 376 | +[chart config]: /pkg/golang.org/x/telemetry/internal/graphconfig |
0 commit comments