フューチャー技術ブログ

Go 1.23リリース連載 Go Telemetry

はじめに

こんにちは。CSIGの棚井です。

Go 1.23 Release Notes の内容を紹介する「フューチャー技術ブログ Go 1.23 リリース連載」の記事です。

Go toolchain に追加された Go Telemetry を取り上げます。

TL;DR

  • Go 開発チームに「Go ツールチェーン(go, gopls, govulncheck)の利用状況、動作状況」をフィードバックするために追加されました
  • Go Telemetry のデフォルトは local mode のため、意図的にステータスを変更しない限りリモートアップロードは行われません
    • opt-in により有効化した場合、自動アップロード後に telemetry.go.dev で集計結果が公開されます
    • ユーザ環境固有の情報は、Telemetry には含まれません
  • 現時点(2024/07/25)ではアップロード数が少ない状況ですが、数が増えれば「世界的な Go の利用傾向、動作状況」が可視化できるようになります

telemetry in the Go toolchain #58409

Go の Telemetry の追加につながった Discussions(telemetry in the Go toolchain #58409)の内容を見ていきます。

2023年2月8日に Discussion が開かれた後、95 comments · 394 replies(506 comments との記載も)の会話を経て、telemetry は opt-in にするなどの仕様が固まり、Go1.23 でのリリースへとつながりました。

Discussions の冒頭には、投稿者により以下のような Telemetry の背景と、Go への導入提案が記載されています。

  • ソフトウェア開発者たちが、自分らの作成したツールが「どのように利用されているのか?」や「期待通りに動作しているのか?」を自分たち自身にフィードバックする方法として、現代では「Telemetry(テレメトリ)」という方法がある。ソフトウェア内で収集した Telemetry をサーバに転送することで、開発者の疑問に答える方法である
  • ツールを使うユーザの詳細な情報は集めずに、かつ、ツールの開発チーム側では効率的・効果的に作業を進められるような設計を目指して「Transparent Telemetry」というブログを投稿した
  • Transparent Telemetry を Go のツールチェーンに加えることで、開発チームとユーザ両方の助けになる想定である。ただし、この計装の追加提案は Go のコマンドラインツール(go, gopls, govulncheck)を念頭に置いており、Go のコンパイラは含めていない

Go の開発言語自体をメンテナンスしている「Go 開発チーム」に向けた Telemetry の連携として、今回の Go Telemetry が追加されました。

Transparent Telemetry の日本語での説明記事としては、a2not さんの「Transparent Telemetryの概要」がとても参考になりました。

Why Telemetry? の Bug reports are not enough. に記載された話として、「Go1.14 から、macOS 環境で cgo を利用する net パッケージをコンパイルするには、 Xcode のインストールが求められるという バグ が3年近く放置されていた」というのは非常に衝撃的な内容でした。macOS を使っていることによる「そういうものなのかな」という誤解に、全世界の Go ユーザが気づけなかったようです。

今回の Go Telemetry の追加には、上記のような「ユーザ報告として上がってこないことにより、Go 開発チームが気づけていないバグ」をデータ駆動で検知しようとする試みが含まれているのではと、私は考えています。

環境構築

Go Telemetry を操作する環境を準備していきます。

go1.23rc2 の実行環境を準備します。
golang.org/dl で該当のバージョンを選択してインストールしてください。

$ go install golang.org/dl/go1.23rc2@latest
go: downloading golang.org/dl v0.0.0-20240716205829-396652c1bbd0

$ go1.23rc2 download
Downloaded 0.0% ( 665 / 73568076 bytes) ...
Downloaded 8.7% ( 6367984 / 73568076 bytes) ...
Downloaded 22.2% (16333340 / 73568076 bytes) ...
Downloaded 36.5% (26862652 / 73568076 bytes) ...
Downloaded 49.8% (36650736 / 73568076 bytes) ...
Downloaded 63.4% (46676460 / 73568076 bytes) ...
Downloaded 76.3% (56108060 / 73568076 bytes) ...
Downloaded 89.9% (66143092 / 73568076 bytes) ...
Downloaded 100.0% (73568076 / 73568076 bytes)
Unpacking /home/me/sdk/go1.23rc2/go1.23rc2.linux-amd64.tar.gz ...
Success. You may now run 'go1.23rc2'

$ go1.23rc2 version
go version go1.23rc2 linux/amd64

go telemetry としてコマンドが追加(参照実装箇所)されているので、go1.23rc2 でも Telemetry コマンドの呼び出しが可能です。

$ go1.23rc2 telemetry help
usage: go telemetry [off|local|on]
Run 'go help telemetry' for details.


$ go1.23rc2 help telemetry
usage: go telemetry [off|local|on]

Telemetry is used to manage Go telemetry data and settings.

Telemetry can be in one of three modes: off, local, or on.

When telemetry is in local mode, counter data is written to the local file
system, but will not be uploaded to remote servers.

When telemetry is off, local counter data is neither collected nor uploaded.

When telemetry is on, telemetry data is written to the local file system
and periodically sent to https://telemetry.go.dev/. Uploaded data is used to
help improve the Go toolchain and related tools, and it will be published as
part of a public dataset.

For more details, see https://telemetry.go.dev/privacy.
This data is collected in accordance with the Google Privacy Policy
(https://policies.google.com/privacy).

To view the current telemetry mode, run "go telemetry".
To disable telemetry uploading, but keep local data collection, run
"go telemetry local".
To enable both collection and uploading, run “go telemetry on”.
To disable both collection and uploading, run "go telemetry off".

See https://go.dev/doc/telemetry for more information on telemetry.

help で Telemetry の使い方を詳しく確認出来ました。コマンドの利用者が増えるにつれて、この情報量多めの説明文も徐々にそぎ落とされるのではと予想しています。

また、gotelemetry としてのコマンドも用意されており、go install で取得可能です。

$ go install golang.org/x/telemetry/cmd/gotelemetry@latest
go: downloading golang.org/x/telemetry v0.0.0-20240723021908-ccdfb411a0c4


$ gotelemetry
Gotelemetry is a tool for managing Go telemetry data and settings.

Usage:

gotelemetry <command> [arguments]

The commands are:

on enable telemetry collection and uploading
local enable telemetry collection but disable uploading
off disable telemetry collection and uploading
view run a web viewer for local telemetry data
env print the current telemetry environment
clean remove all local telemetry data

Use "gotelemetry help <command>" for details about any command.

The following additional commands are available for diagnostic
purposes, and may change or be removed in the future:

csv print all known counters
dump view counter file data
upload run upload with logging enabled

gopls

go telemetry の各種コマンドは後程確認するとして、ここでは Go の Language Server である gopls の Telemetry への対応状況を見ていきます。

Discussions(telemetry in the Go toolchain #58409)の中で gopls に触れられていた、というのもあり、gopls にはすでに Telemetry 機能が追加されています。

もし VSCode で Go の開発を行っている方であれば、Telemetry が有効な状態(※ ローカルへのファイル出力のみ有効。サーバへのアップロードは行わない)となっています。

gopls, vscode-go で Telemetry が追加されたバージョンと、対応するリリースノートを表に整理しました。

ログの出力場所を確認すると、local, upload のディレクトリが生成されていることが確認できます。

$ uname -s
Linux

$ pwd
/home/me/.config/go/telemetry

$ ls -l
total 8
drwxr-xr-x 2 me me 4096 Jul 24 04:01 local
drwxr-xr-x 2 me me 4096 Nov 16 2023 upload

リリースノートをじっくりと確認する方であれば、VSCode, vscode-go の Telemetry の追記時点で、gopls の Telemetry が始まったことに気づけたのかもしれません。

Go Telemetry を動かしてみる

Documentation > Go Telemetry の記載内容を参考に、Go Telemetry の各機能を見ていきます。

Telemetry mode の設定

Go Telemetry には、3つの mode が存在します。デフォルトは local です。

mode ごとに、ローカルに Telemetry が出力されるか、また、リモートサーバに Telemetry がアップロードされるかの挙動が異なります。

mode ローカルに Telemetry が出力される リモートサーバに Telelemetry がアップロードされる
local
(default)
on
off

mode ステータスの確認と変更は、go telemetrygotelemetry の両方で可能です。

$ go1.23rc2 telemetry
local

$ go1.23rc2 telemetry off

$ go1.23rc2 telemetry
off

$ go1.23rc2 telemetry on
Telemetry uploading is now enabled and data will be periodically sent to
https://telemetry.go.dev/. Uploaded data is used to help improve the Go
toolchain and related tools, and it will be published as part of a public
dataset.

For more details, see https://telemetry.go.dev/privacy.
This data is collected in accordance with the Google Privacy Policy
(https://policies.google.com/privacy).

To disable telemetry uploading, but keep local data collection, run
“go telemetry local”.
To disable both collection and uploading, run “go telemetry off“.

$ go1.23rc2 telemetry local

$ go1.23rc2 telemetry
local
$ gotelemetry env
mode: local 2024-07-23 00:00:00 +0000 UTC

modefile: /home/me/.config/go/telemetry/mode
localdir: /home/me/.config/go/telemetry/local
uploaddir: /home/me/.config/go/telemetry/upload

$ gotelemetry off

$ gotelemetry env
mode: off 2024-07-23 00:00:00 +0000 UTC

modefile: /home/me/.config/go/telemetry/mode
localdir: /home/me/.config/go/telemetry/local
uploaddir: /home/me/.config/go/telemetry/upload

また mode の設定値は、次に取り上げる os.UserConfigDir()/go/telemetry 配下の mode というファイルに、更新日とセットで記録されています。

$ uname -s
Linux

$ cat $HOME/.config/go/telemetry/mode
local 2024-07-23

Telemetry の出力先

Telemetry は、ローカル環境の os.UserConfigDir()/go/telemetry に出力されています。

os 出力場所
Linux $XDG_CONFIG_HOME
$HOME/.config
macOS $HOME/Library/Application Support
Windows %AppData%

以降、本ブログでは、os.UserConfigDir()/go/telemetry のパスを <gotelemetry> と記載します。

Telemerty がローカルに出力され、リモートのサーバにアップロードされるまでの流れは以下のようになります(画像引用元

dataflow.png

Telemetry の内容

Telemetry には Basic counters と Stack counters の2種類があります。

gopls の Telemetry を用いて、それぞれが <gotelemetry> 配下に出力しているログの内容を見ていきます。

Basic counters

ローカルの <gotelemetry>/local/local.2024-07-19.json を開けてみたところ、以下のような中身となっていました。
※私の環境では \u003c が出力されていたため、< に手動で書き換えています。

{
"Week": "2024-07-19",
"LastWeek": "",
"X": 0.11111111111111111,
"Programs": [
{
"Program": "golang.org/x/tools/gopls",
"Version": "v0.16.1",
"GoVersion": "go1.22.3",
"GOOS": "linux",
"GOARCH": "amd64",
"Counters": {
"gopls/client:vscode": 9,
"gopls/definition/error-latency:<10ms": 13,
"gopls/definition/error-latency:<50ms": 1,
"gopls/definition/latency:<100ms": 1,
"gopls/definition/latency:<10ms": 73,
"gopls/definition/latency:<1s": 1,
"gopls/definition/latency:<200ms": 1,
"gopls/definition/latency:<500ms": 3,
"gopls/definition/latency:<50ms": 4,
"gopls/gotoolchain:auto": 9,
"gopls/goversion:1.22": 9,
"gopls/hover/error-latency:<10ms": 12,
"gopls/hover/error-latency:<50ms": 1,
"gopls/hover/latency:<100ms": 2,
"gopls/hover/latency:<10ms": 270,
"gopls/hover/latency:<200ms": 1,
"gopls/hover/latency:<50ms": 3,
"gopls/implementation/latency:<100ms": 2,
"gopls/implementation/latency:<24h": 1,
"gopls/implementation/latency:<500ms": 1,
"gopls/implementation/latency:<5s": 2,
"gopls/references/latency:<10ms": 1
},
"Stacks": {}
},
{
"Program": "github.com/golang/vscode-go/vscgo",
"Version": "v0.41.4",
"GoVersion": "go1.22.3",
"GOOS": "linux",
"GOARCH": "amd64",
"Counters": {
"activation_latency:<1s": 3,
"activation_latency:<500ms": 2,
"activation_latency:<5s": 2,
"inc_counters_duration:<10ms": 6,
"inc_counters_duration:<1s": 1,
"inc_counters_num_input:<2": 7
},
"Stacks": {}
}
],
"Config": "v0.26.0"
}
$ cat local.2024-07-19.json | jq .Programs[].Program
"golang.org/x/tools/gopls"
"github.com/golang/vscode-go/vscgo"

json ファイル内の項目から分かるように、goplsvscode-go/vscgo のバージョン情報や動作環境、レイテンシーのカウントを記録しています。

例えば "gopls/client:vscode": 9 の場合は、VSCode によって gopls のセッションが初期化された回数を表しています。Neovim や Eglot など他のエディタでも gopls を利用している場合には、それぞれ別途 gopls/client:neovimgopls/client:eglot の形式で記録されます。

gopls/client:vscode の表記で表されている場合、gopls/client をチャート名(chart name)、vscode をバケット名(bucket name)と呼びます。

また、Basic counters では <10mx, <50mx の表記により、レイテンシのヒストグラムも記録しています。

"gopls/definition/error-latency:<10ms": 13,
"gopls/definition/error-latency:<50ms": 1,
"gopls/definition/latency:<100ms": 1,
"gopls/definition/latency:<10ms": 73,
"gopls/definition/latency:<1s": 1,
"gopls/definition/latency:<200ms": 1,
"gopls/definition/latency:<500ms": 3,
"gopls/definition/latency:<50ms": 4,

Stack counters

stack counter では、プログラムがクラッシュした回数のカウントと、クラッシュ時のコールスタックを記録しています。

以下、実際に gopls/bug のスタックトレースが記録された Telemetry です。

{
"Week": "2024-07-18",
"LastWeek": "",
"X": 0.11111111111111111,
"Programs": [
{
"Program": "golang.org/x/tools/gopls",
"Version": "v0.16.1",
"GoVersion": "go1.22.3",
"GOOS": "linux",
"GOARCH": "amd64",
"Counters": {
"gopls/client:vscode": 14,
...
},
"Stacks": {
"gopls/bug\ngolang.org/x/tools/gopls/internal/util/bug.report:+35\ngolang.org/x/tools/gopls/internal/util/bug.Reportf:+1\ngolang.org/x/tools/gopls/internal/cache.typeErrorsToDiagnostics.func1:+28\ngolang.org/x/tools/gopls/internal/cache.typeErrorsToDiagnostics:+122\ngolang.org/x/tools/gopls/internal/cache.(*typeCheckBatch).checkPackage:+127\ngolang.org/x/tools/gopls/internal/cache.(*typeCheckBatch).handleSyntaxPackage:+70\ngolang.org/x/tools/gopls/internal/cache.(*Snapshot).forEachPackageInternal.func2:+1\ngolang.org/x/sync/errgroup.(*Group).Go.func1:+3\nruntime.goexit:+0": 1
}
},
],
"Config": "v0.26.0"
}

stack counter により、滅多に起こらないエラーや再現の難しいエラーだとしても、適切なスタックトレースが Telemetry に記録されます。

Web のパフォーマンス最適化には「推測するな、計測せよ」という格言があり、まさにそれを Telemetry により実現しています。

Counter files

これまでに見てきた Telemetry のファイルは、json フォーマットで記録される前に、以下のフォーマットで <gotelemetry>/local に出力されています。

# スキーマ
[program name]@[program version]-[go version]-[GOOS]-[GOARCH]-[date].v1.count

今回の動作検証環境では、以下のファイルが出力されていました。

# サンプルデータ
'gopls@v0.16.1-go1.22.3-linux-amd64-2024-07-22.v1.count'
  • データスキーマとサンプルデータの対応
schema example reported by
program name gopls debug.BuildInfo
program version v0.16.1 debug.BuildInfo
go version go1.22.3 debug.BuildInfo
GOOS linux runtime.GOOS
GOARCH amd64 runtime.GOARCH
date 2024-07-22 YYYY-MM-DD

Reporting and uploading

おおよそ1週間に1回程度の頻度で、Telemetry でカウントしたデータが <gotelemetry>/local 配下に <date>.json として出力されます。

出力されたデータは gotelemetry view による可視化が可能です。

$ gotelemetry view
server listening at http://127.0.0.1:4040

gopls/client

コメント_2024-07-24_073922.png

gopls/references/latency

コメント_2024-07-24_073729.png

gopls/implementation/latency

コメント_2024-07-24_073824.png

ローカルに蓄積された全 Telemetry の集計と可視化になるため、本ブログ執筆時点の telemetry.go.dev よりは情報量の多いグラフが得られると思います。

また、<date>.json の出力時に Telemetry の modeon に設定されていた場合、リモートサーバへのファイルアップロードと、<gotelemetry>/upload へのコピー作成が行われます。

Charts

Telemetry としてリモートに収集されたデータは、telemetry.go.dev に一般公開されています。
グラフ化された Chats と、その元となったデータは Reports として日付単位で公開されており、ブラウザで閲覧可能な状況となっています。

本ブログ執筆時点で Charts / 2024-07-20 を見てみると、68件のレポートを集計した結果との記載があります。

These charts were generated with data from 68 reports.

Discussions(telemetry in the Go toolchain #58409)には、分析に必要なレポート件数は約 16,000 件と記載されているため、今後のレポート件数の増加が重要になりそうです。

only about 16,000 reports are needed for 1% accuracy at a 99% confidence level.

現時点の少ないデータ数からでも、データ傾向は少しだけ見れます。

golang.org/x/tools/gopls, GoVersion

  • Gopher の皆さんは、最新の go version を利用されている方が多い
コメント_2024-07-24_051412.png

gopls/client:{vscode,vscodium,vscode-insiders,code-server,eglot,govim,neovim,coc.nvim,sublimetext,other}

  • gopls は VSCode での利用が多い
コメント_2024-07-24_050447.png

今後、レポートの母数が増えれば、世の中の Gopher 全体の傾向が、Telemetry により可視化できる未来が来るかもしれません。

ただし、現時点の Go Telemetry は opt-in により有効化する機能のため、データの偏り(データ母体が、あえて opt-in にするユーザの集まりになっている可能性がある点)には注意する必要があります。

おわりに

本ブログでは、Go1.23で追加された Go Telemetry を見てきました。

リポジトリの Issue 等を利用したユーザ報告駆動での調査とは別に、ツールに Telemetry を仕込んで「実挙動データを収集する」というトレンドについて、本ブログを執筆する中で改めて復習する機会となりました。以前に Terraform の実装コード読み を行った際に Open Telemetry の実装(terraform/telemetry.go)を見つけて、それ以降は「オブザーバビリティ・エンジニアリング」への関心を持ち続けていました。

最近の業務にて「ログ監視、インシデント対応」を担当する機会が増え、時期を合わせて Go のリリースノートに Telemetry が追加されたとの記載がありましたので、今回執筆させていただきました。

ここまで付き合いいただき、ありがとうございました。