Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
79b16b0
perf: Optimize Stringify allocations (~2x faster)
merchantmoh-debug Jan 24, 2026
9e260bd
Apply suggestions from code review
gmlewis Jan 24, 2026
2ac81f8
fix(pr): revert formatting scope creep; re-apply HeaderRateReset export
merchantmoh-debug Jan 29, 2026
6aa407a
Merge branch 'master' into feat/opentelemetry-support
merchantmoh-debug Jan 29, 2026
cd280c9
fix(pr): remove duplicate folder and align go.mod versions
merchantmoh-debug Jan 29, 2026
02bb4d0
Update example/otel/main.go
merchantmoh-debug Jan 29, 2026
acfd884
Update example/otel/main.go
merchantmoh-debug Jan 29, 2026
0ea6962
Update example/otel/main.go
merchantmoh-debug Jan 29, 2026
c7772b7
Update otel/transport.go
merchantmoh-debug Jan 29, 2026
de7349b
Update otel/transport.go
merchantmoh-debug Jan 29, 2026
c1c24c2
Update otel/transport.go
merchantmoh-debug Jan 29, 2026
0f3f5ff
Merge branch 'master' into feat/opentelemetry-support
merchantmoh-debug Jan 31, 2026
a285e48
fix(otel): export rate limit constants (HeaderRateReset/Resource) to …
merchantmoh-debug Jan 31, 2026
cd4386a
fix(tests): update github_test.go to use exported RateLimit constants
merchantmoh-debug Jan 31, 2026
d59d91b
fix(otel): resolve deprecation and lint errors in example/otel
merchantmoh-debug Jan 31, 2026
490ac42
fix(otel): add replace directive and fix import grouping
merchantmoh-debug Jan 31, 2026
fe175fb
fix(otel): resolve lints (header, revive, fmtpercentv, gci)
merchantmoh-debug Jan 31, 2026
dd76890
trigger: force ci re-run to verify lint fixes
merchantmoh-debug Jan 31, 2026
73b6461
Apply suggestion from @gmlewis
gmlewis Jan 31, 2026
ecc307c
Apply suggestion from @gmlewis
gmlewis Jan 31, 2026
624e9ab
Apply suggestion from @gmlewis
gmlewis Jan 31, 2026
1bb856e
test(otel): add comprehensive unit tests for transport
merchantmoh-debug Feb 1, 2026
6f09c21
style(otel): strict lint fixes (paralleltest, fmtpercentv, revive)
merchantmoh-debug Feb 1, 2026
5920d98
Merge branch 'master' into feat/opentelemetry-support
merchantmoh-debug Feb 1, 2026
d5eb870
chore(otel): fix example documentation and downgrade deps to v1.27.0
merchantmoh-debug Feb 1, 2026
e79243d
fix(otel): synchronize dependencies in example/otel
google-labs-jules[bot] Feb 2, 2026
a7f6cfe
Merge pull request #13 from merchantmoh-debug/feat-otel-tidy-fixes-17…
merchantmoh-debug Feb 2, 2026
dad77b2
Apply code review feedback for OpenTelemetry support
google-labs-jules[bot] Feb 2, 2026
291e439
Merge branch 'feat/opentelemetry-support' into apply-otel-review-feed…
merchantmoh-debug Feb 2, 2026
0fdc8b2
Merge pull request #15 from merchantmoh-debug/apply-otel-review-feedb…
merchantmoh-debug Feb 2, 2026
ccb7a3e
Merge branch 'master' into feat/opentelemetry-support
merchantmoh-debug Feb 2, 2026
5e656ae
Update otel/go.mod
merchantmoh-debug Feb 2, 2026
8da9a45
Merge branch 'master' into feat/opentelemetry-support
merchantmoh-debug Feb 2, 2026
c06de1c
Apply code review feedback for OpenTelemetry support
google-labs-jules[bot] Feb 2, 2026
0b0cc06
Apply code review feedback for OpenTelemetry support
google-labs-jules[bot] Feb 2, 2026
a005fd3
Apply code review feedback for OpenTelemetry support
google-labs-jules[bot] Feb 2, 2026
da8ec1e
Apply code review feedback for OpenTelemetry support
google-labs-jules[bot] Feb 2, 2026
7a6262c
Merge pull request #16 from merchantmoh-debug/apply-otel-review-feedb…
merchantmoh-debug Feb 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions example/otel/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module github.com/google/go-github/v82/example/otel

go 1.24.0

require (
github.com/google/go-github/v82 v82.0.0
github.com/google/go-github/v82/otel v0.0.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0
go.opentelemetry.io/otel/sdk v1.27.0
)

require (
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/go-querystring v1.2.0 // indirect
go.opentelemetry.io/otel v1.27.0 // indirect
go.opentelemetry.io/otel/metric v1.27.0 // indirect
go.opentelemetry.io/otel/trace v1.27.0 // indirect
golang.org/x/sys v0.39.0 // indirect
)

replace github.com/google/go-github/v82 => ../../

replace github.com/google/go-github/v82/otel => ../../otel
30 changes: 30 additions & 0 deletions example/otel/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=
github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA=
go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik=
go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak=
go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI=
go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A=
go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw=
go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
63 changes: 63 additions & 0 deletions example/otel/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2026 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This example demonstrates how to use the otel transport to instrument
// the go-github client with OpenTelemetry tracing.
package main

import (
"context"
"fmt"
"log"
"net/http"

"github.com/google/go-github/v82/github"
"github.com/google/go-github/v82/otel"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/sdk/trace"
)

func main() {
// Initialize stdout exporter to see traces in console
exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint())
if err != nil {
log.Fatalf("failed to initialize stdouttrace exporter: %v", err)
}

tp := trace.NewTracerProvider(
trace.WithBatcher(exporter),
)
defer func() {
if err := tp.Shutdown(context.Background()); err != nil {
log.Fatal(err)
}
}()

// Configure HTTP client with OTel transport
httpClient := &http.Client{
Transport: otel.NewTransport(
http.DefaultTransport,
otel.WithTracerProvider(tp),
),
}

client := github.NewClient(httpClient)

// Make a request (Get Rate Limits is public and cheap)
limits, resp, err := client.RateLimit.Get(context.Background())
if err != nil {
log.Printf("Error fetching rate limits: %v", err)
} else {
fmt.Printf("Core Rate Limit: %v/%v (Resets at %v)\n",
limits.GetCore().Remaining,
limits.GetCore().Limit,
limits.GetCore().Reset)
}

// Check if we captured attributes in response
if resp != nil {
fmt.Printf("Response Status: %v\n", resp.Status)
}
}
32 changes: 17 additions & 15 deletions github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,16 @@ const (
defaultUserAgent = "go-github" + "/" + Version
uploadBaseURL = "https://uploads.github.com/"

headerAPIVersion = "X-Github-Api-Version"
headerRateLimit = "X-Ratelimit-Limit"
headerRateRemaining = "X-Ratelimit-Remaining"
headerRateUsed = "X-Ratelimit-Used"
headerRateReset = "X-Ratelimit-Reset"
headerRateResource = "X-Ratelimit-Resource"
headerOTP = "X-Github-Otp"
headerRetryAfter = "Retry-After"
HeaderRateLimit = "X-Ratelimit-Limit"
HeaderRateRemaining = "X-Ratelimit-Remaining"
HeaderRateUsed = "X-Ratelimit-Used"
HeaderRateReset = "X-Ratelimit-Reset"
HeaderRateResource = "X-Ratelimit-Resource"
Comment on lines +42 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exported constants should be moved above

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above, but below the Version.

HeaderRequestID = "X-Github-Request-Id"

headerAPIVersion = "X-Github-Api-Version"
headerOTP = "X-Github-Otp"
headerRetryAfter = "Retry-After"

headerTokenExpiration = "Github-Authentication-Token-Expiration"

Expand Down Expand Up @@ -785,21 +787,21 @@ func (r *Response) populatePageValues() {
// parseRate parses the rate related headers.
func parseRate(r *http.Response) Rate {
var rate Rate
if limit := r.Header.Get(headerRateLimit); limit != "" {
if limit := r.Header.Get(HeaderRateLimit); limit != "" {
rate.Limit, _ = strconv.Atoi(limit)
}
if remaining := r.Header.Get(headerRateRemaining); remaining != "" {
if remaining := r.Header.Get(HeaderRateRemaining); remaining != "" {
rate.Remaining, _ = strconv.Atoi(remaining)
}
if used := r.Header.Get(headerRateUsed); used != "" {
if used := r.Header.Get(HeaderRateUsed); used != "" {
rate.Used, _ = strconv.Atoi(used)
}
if reset := r.Header.Get(headerRateReset); reset != "" {
if reset := r.Header.Get(HeaderRateReset); reset != "" {
if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 {
rate.Reset = Timestamp{time.Unix(v, 0)}
}
}
if resource := r.Header.Get(headerRateResource); resource != "" {
if resource := r.Header.Get(HeaderRateResource); resource != "" {
rate.Resource = resource
}
return rate
Expand All @@ -820,7 +822,7 @@ func parseSecondaryRate(r *http.Response) *time.Duration {
// According to GitHub support, endpoints might return x-ratelimit-reset instead,
// as an integer which represents the number of seconds since epoch UTC,
// representing the time to resume making requests.
if v := r.Header.Get(headerRateReset); v != "" {
if v := r.Header.Get(HeaderRateReset); v != "" {
secondsSinceEpoch, _ := strconv.ParseInt(v, 10, 64) // Error handling is noop.
retryAfter := time.Until(time.Unix(secondsSinceEpoch, 0))
return &retryAfter
Expand Down Expand Up @@ -1454,7 +1456,7 @@ func CheckResponse(r *http.Response) error {
// Primary rate limit exceeded: GitHub returns 403 or 429 with X-RateLimit-Remaining: 0
// See: https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api
case (r.StatusCode == http.StatusForbidden || r.StatusCode == http.StatusTooManyRequests) &&
r.Header.Get(headerRateRemaining) == "0":
r.Header.Get(HeaderRateRemaining) == "0":
return &RateLimitError{
Rate: parseRate(r),
Response: errorResponse.Response,
Expand Down
Loading
Loading