@@ -32,6 +32,30 @@ const (
3232 OriginalTraceHeader string = "original-traceparent"
3333)
3434
35+ // contextKey is an unexported type for context keys in this package, preventing
36+ // collisions with keys defined in other packages.
37+ type contextKey string
38+
39+ const (
40+ githubAppIDKey contextKey = "github_app_id"
41+ githubInstallationIDKey contextKey = "github_installation_id"
42+ )
43+
44+ // WithGitHubAppID returns a copy of ctx with the GitHub App ID attached.
45+ // The transport reads this value to label rate limit metrics with the app
46+ // that made the request, enabling per-app visibility into quota consumption.
47+ func WithGitHubAppID (ctx context.Context , appID int64 ) context.Context {
48+ return context .WithValue (ctx , githubAppIDKey , strconv .FormatInt (appID , 10 ))
49+ }
50+
51+ // WithGitHubInstallationID returns a copy of ctx with the GitHub installation
52+ // ID attached. The transport reads this value to label rate limit metrics with
53+ // the installation that made the request. GitHub enforces rate limits per
54+ // installation, so this label identifies which (app, org) pair is consuming quota.
55+ func WithGitHubInstallationID (ctx context.Context , installationID int64 ) context.Context {
56+ return context .WithValue (ctx , githubInstallationIDKey , strconv .FormatInt (installationID , 10 ))
57+ }
58+
3559var (
3660 mReqCount = promauto .NewCounterVec (
3761 prometheus.CounterOpts {
@@ -283,50 +307,50 @@ var (
283307 Name : "github_rate_limit_remaining" ,
284308 Help : "The number of requests remaining in the current rate limit window" ,
285309 },
286- []string {"resource" , "organization" },
310+ []string {"resource" , "organization" , "app_id" , "installation_id" },
287311 )
288312 mGitHubRateLimit = promauto .NewGaugeVec (
289313 prometheus.GaugeOpts {
290314 Name : "github_rate_limit" ,
291315 Help : "The number of requests allowed during the rate limit window" ,
292316 },
293- []string {"resource" , "organization" },
317+ []string {"resource" , "organization" , "app_id" , "installation_id" },
294318 )
295319 mGitHubRateLimitReset = promauto .NewGaugeVec (
296320 prometheus.GaugeOpts {
297321 Name : "github_rate_limit_reset" ,
298322 Help : "The timestamp at which the current rate limit window resets" ,
299323 },
300- []string {"resource" , "organization" },
324+ []string {"resource" , "organization" , "app_id" , "installation_id" },
301325 )
302326 mGitHubRateLimitUsed = promauto .NewGaugeVec (
303327 prometheus.GaugeOpts {
304328 Name : "github_rate_limit_used" ,
305329 Help : "The fraction of the rate limit window used" ,
306330 },
307- []string {"resource" , "organization" },
331+ []string {"resource" , "organization" , "app_id" , "installation_id" },
308332 )
309333 mGitHubRateLimitTimeToReset = promauto .NewGaugeVec (
310334 prometheus.GaugeOpts {
311335 Name : "github_rate_limit_time_to_reset" ,
312336 Help : "The number of minutes until the current rate limit window resets" ,
313337 },
314- []string {"resource" , "organization" },
338+ []string {"resource" , "organization" , "app_id" , "installation_id" },
315339 )
316340 mGitHubRateLimitErrors = promauto .NewCounterVec (
317341 prometheus.CounterOpts {
318342 Name : "github_rate_limit_errors_total" ,
319343 Help : "GitHub API requests rejected due to rate limiting (403/429 with rate limit headers)" ,
320344 },
321- []string {"resource" , "organization" , "service_name" , "code" , "rate_limit_type" },
345+ []string {"resource" , "organization" , "app_id" , "installation_id" , " service_name" , "code" , "rate_limit_type" },
322346 )
323347 mGitHubRetryAfterSeconds = promauto .NewHistogramVec (
324348 prometheus.HistogramOpts {
325349 Name : "github_retry_after_seconds" ,
326350 Help : "Retry-After values from GitHub rate limit responses" ,
327351 Buckets : []float64 {1 , 5 , 15 , 30 , 60 , 120 , 300 , 900 , 1800 , 3600 },
328352 },
329- []string {"organization" , "service_name" , "rate_limit_type" },
353+ []string {"organization" , "app_id" , "installation_id" , " service_name" , "rate_limit_type" },
330354 )
331355)
332356
@@ -368,6 +392,13 @@ func instrumentGitHubRateLimits(next http.RoundTripper) promhttp.RoundTripperFun
368392 // Extract organization from the request URL
369393 organization := extractOrgFromGitHubURL (r .URL .Path )
370394
395+ // Read caller-supplied app/installation IDs from the request context.
396+ // These are set by callers via WithGitHubAppID and WithGitHubInstallationID.
397+ // Empty string when not set — callers that do not set these values produce
398+ // time series with app_id="" and installation_id="".
399+ appID , _ := r .Context ().Value (githubAppIDKey ).(string )
400+ installationID , _ := r .Context ().Value (githubInstallationIDKey ).(string )
401+
371402 val := func (key string ) float64 {
372403 val := resp .Header .Get (key )
373404 if val == "" {
@@ -380,8 +411,10 @@ func instrumentGitHubRateLimits(next http.RoundTripper) promhttp.RoundTripperFun
380411 return float64 (i )
381412 }
382413 labels := prometheus.Labels {
383- "resource" : resource ,
384- "organization" : organization ,
414+ "resource" : resource ,
415+ "organization" : organization ,
416+ "app_id" : appID ,
417+ "installation_id" : installationID ,
385418 }
386419
387420 remaining := val ("X-RateLimit-Remaining" )
@@ -446,6 +479,8 @@ func instrumentGitHubRateLimits(next http.RoundTripper) promhttp.RoundTripperFun
446479 mGitHubRateLimitErrors .With (prometheus.Labels {
447480 "resource" : resource ,
448481 "organization" : organization ,
482+ "app_id" : appID ,
483+ "installation_id" : installationID ,
449484 "service_name" : env .KnativeServiceName ,
450485 "code" : strconv .Itoa (resp .StatusCode ),
451486 "rate_limit_type" : rateLimitType ,
@@ -456,6 +491,8 @@ func instrumentGitHubRateLimits(next http.RoundTripper) promhttp.RoundTripperFun
456491 if seconds , parseErr := strconv .Atoi (retryAfter ); parseErr == nil {
457492 mGitHubRetryAfterSeconds .With (prometheus.Labels {
458493 "organization" : organization ,
494+ "app_id" : appID ,
495+ "installation_id" : installationID ,
459496 "service_name" : env .KnativeServiceName ,
460497 "rate_limit_type" : rateLimitType ,
461498 }).Observe (float64 (seconds ))
0 commit comments