Skip to content

Commit f855a53

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/telemetry/cmd/stacks: use authentication token
GitHub imposes a stringent rate limit for unauthenticated requests, that our current rate of telemetry often exceeds. This change causes the stacks command to read a GitHub authentication token from $HOME/.stacks.token and use it if found, relaxing the rate limit. Instructions for creating a token are recorded in comments. Fixes golang/go#68733 Change-Id: Ia4b73faa1340dfbed4b9b350d2c57f09abf8ca38 Reviewed-on: https://go-review.googlesource.com/c/tools/+/603155 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Alan Donovan <adonovan@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
1 parent 3ffd605 commit f855a53

File tree

1 file changed

+44
-4
lines changed

1 file changed

+44
-4
lines changed

gopls/internal/telemetry/cmd/stacks/stacks.go

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"log"
1818
"net/http"
1919
"net/url"
20+
"os"
21+
"path/filepath"
2022
"sort"
2123
"strings"
2224
"time"
@@ -31,13 +33,42 @@ import (
3133
// flags
3234
var (
3335
daysFlag = flag.Int("days", 7, "number of previous days of telemetry data to read")
36+
37+
token string // optional GitHub authentication token, to relax the rate limit
3438
)
3539

3640
func main() {
3741
log.SetFlags(0)
3842
log.SetPrefix("stacks: ")
3943
flag.Parse()
4044

45+
// Read GitHub authentication token from $HOME/.stacks.token.
46+
//
47+
// You can create one using the flow at: GitHub > You > Settings >
48+
// Developer Settings > Personal Access Tokens > Fine-grained tokens >
49+
// Generate New Token. Generate the token on behalf of yourself
50+
// (not "golang" or "google"), with no special permissions.
51+
// The token is typically of the form "github_pat_XXX", with 82 hex digits.
52+
// Save it in the file, with mode 0400.
53+
//
54+
// For security, secret tokens should be read from files, not
55+
// command-line flags or environment variables.
56+
{
57+
home, err := os.UserHomeDir()
58+
if err != nil {
59+
log.Fatal(err)
60+
}
61+
tokenFile := filepath.Join(home, ".stacks.token")
62+
content, err := os.ReadFile(tokenFile)
63+
if err != nil {
64+
if !os.IsNotExist(err) {
65+
log.Fatalf("cannot read GitHub authentication token: %v", err)
66+
}
67+
log.Printf("no file %s containing GitHub authentication token; continuing without authentication, which is subject to stricter rate limits (https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api).", tokenFile)
68+
}
69+
token = string(bytes.TrimSpace(content))
70+
}
71+
4172
// Maps stack text to Version/GoVersion/GOOS/GOARCH string to counter.
4273
stacks := make(map[string]map[string]int64)
4374
var distinctStacks int
@@ -129,10 +160,10 @@ func main() {
129160
batch := stackIDs[:min(6, len(stackIDs))]
130161
stackIDs = stackIDs[len(batch):]
131162

132-
query := "label:gopls/telemetry-wins in:body " + strings.Join(batch, " OR ")
163+
query := "is:issue label:gopls/telemetry-wins in:body " + strings.Join(batch, " OR ")
133164
res, err := searchIssues(query)
134165
if err != nil {
135-
log.Fatalf("GitHub issues query failed: %v", err)
166+
log.Fatalf("GitHub issues query %q failed: %v", query, err)
136167
}
137168
for _, issue := range res.Items {
138169
for _, id := range batch {
@@ -283,13 +314,22 @@ func newIssue(stack, id, jsonURL string, counts map[string]int64) string {
283314
// searchIssues queries the GitHub issue tracker.
284315
func searchIssues(query string) (*IssuesSearchResult, error) {
285316
q := url.QueryEscape(query)
286-
resp, err := http.Get(IssuesURL + "?q=" + q)
317+
318+
req, err := http.NewRequest("GET", IssuesURL+"?q="+q, nil)
319+
if err != nil {
320+
return nil, err
321+
}
322+
if token != "" {
323+
req.Header.Add("Authorization", "Bearer "+token)
324+
}
325+
resp, err := http.DefaultClient.Do(req)
287326
if err != nil {
288327
return nil, err
289328
}
290329
if resp.StatusCode != http.StatusOK {
330+
body, _ := io.ReadAll(resp.Body)
291331
resp.Body.Close()
292-
return nil, fmt.Errorf("search query failed: %s", resp.Status)
332+
return nil, fmt.Errorf("search query failed: %s (body: %s)", resp.Status, body)
293333
}
294334
var result IssuesSearchResult
295335
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {

0 commit comments

Comments
 (0)