11use prometheus:: { core:: Collector , IntGauge , Opts } ;
22
33use crate :: Config ;
4+ use anyhow:: { Error , Result } ;
5+ use log:: { debug, error} ;
46use reqwest:: header:: { ACCEPT , AUTHORIZATION , USER_AGENT } ;
57use reqwest:: { Client , Method , Request } ;
68use std:: collections:: HashMap ;
@@ -24,7 +26,7 @@ enum GithubReqBuilder {
2426}
2527
2628impl GithubReqBuilder {
27- fn build_request ( & self , client : & Client , token : & str ) -> Result < Request , reqwest :: Error > {
29+ fn build_request ( & self , client : & Client , token : & str ) -> Result < Request > {
2830 let rb = match self {
2931 Self :: User => client. request ( Method :: GET , GH_API_USER_ENDPOINT ) ,
3032 Self :: RateLimit => client. request ( Method :: GET , GH_API_RATE_LIMIT_ENDPOINT ) ,
@@ -37,12 +39,12 @@ impl GithubReqBuilder {
3739 . header ( AUTHORIZATION , format ! ( "{} {}" , "token" , token) )
3840 . header ( ACCEPT , "application/vnd.github.v3+json" )
3941 . build ( )
42+ . map_err ( Error :: from)
4043 }
4144}
4245
4346#[ derive( Clone ) ]
4447pub struct GitHubRateLimit {
45- descriptions : Vec < prometheus:: core:: Desc > ,
4648 users : Vec < User > ,
4749}
4850
@@ -54,14 +56,17 @@ impl GitHubRateLimit {
5456 . map ( |v| v. trim ( ) . to_string ( ) )
5557 . collect ( ) ;
5658
57- let users = Self :: get_users_for_tokens ( tokens) . await ;
58- let descriptions = Vec :: new ( ) ;
59-
60- let rv = Self {
61- users,
62- descriptions,
59+ let users = match Self :: get_users_for_tokens ( tokens) . await {
60+ Ok ( v) => v,
61+ Err ( e) => {
62+ error ! ( "Unable to get usernames for rate limit stats: {:?}" , e) ;
63+ //TODO: we going empty for now, how do we want to handle this in the future?
64+ Vec :: new ( )
65+ }
6366 } ;
6467
68+ let rv = Self { users } ;
69+
6570 let refresh_rate = config. gh_rate_limit_stats_cache_refresh ;
6671 let mut rv2 = rv. clone ( ) ;
6772 tokio:: spawn ( async move {
@@ -74,12 +79,12 @@ impl GitHubRateLimit {
7479 rv
7580 }
7681
77- async fn get_users_for_tokens ( tokens : Vec < String > ) -> Vec < User > {
82+ async fn get_users_for_tokens ( tokens : Vec < String > ) -> Result < Vec < User > > {
7883 let ns = String :: from ( "rustinfra_github_rate_limit" ) ;
7984 let mut rv: Vec < User > = Vec :: new ( ) ;
8085 for token in tokens. into_iter ( ) {
8186 let ns2 = ns. clone ( ) ;
82- let username = GitHubRateLimit :: get_github_api_username ( & token) . await ;
87+ let username = GitHubRateLimit :: get_github_api_username ( & token) . await ? ;
8388 let user_future = tokio:: task:: spawn_blocking ( move || {
8489 let rate_limit = IntGauge :: with_opts (
8590 Opts :: new ( "limit" , "Rate limit." )
@@ -119,10 +124,10 @@ impl GitHubRateLimit {
119124 rv. push ( user) ;
120125 }
121126
122- rv
127+ Ok ( rv )
123128 }
124129
125- async fn get_github_api_username ( token : & str ) -> String {
130+ async fn get_github_api_username ( token : & str ) -> Result < String > {
126131 #[ derive( serde:: Deserialize ) ]
127132 struct GithubUser {
128133 pub login : String ,
@@ -135,34 +140,47 @@ impl GitHubRateLimit {
135140 let u = client
136141 . execute ( req)
137142 . await
138- . unwrap ( )
143+ . map_err ( Error :: from ) ?
139144 . json :: < GithubUser > ( )
140145 . await
141- . unwrap ( ) ;
146+ . map_err ( Error :: from ) ? ;
142147
143- u. login
148+ Ok ( u. login )
144149 }
145150
146151 async fn update_stats ( & mut self ) {
152+ debug ! ( "Updating rate limit stats" ) ;
153+
147154 #[ derive( Debug , serde:: Deserialize ) ]
148155 struct GithubRateLimit {
149156 pub rate : HashMap < String , usize > ,
150157 }
151158
152159 let client = reqwest:: Client :: new ( ) ;
153-
154- //FIXME: we will (might?) need a RWLock on users structure
155160 for u in self . users . iter_mut ( ) {
156- let req = GithubReqBuilder :: RateLimit
157- . build_request ( & client, & u. token )
158- . unwrap ( ) ;
159- let mut data = client
160- . execute ( req)
161- . await
162- . unwrap ( )
163- . json :: < GithubRateLimit > ( )
164- . await
165- . unwrap ( ) ;
161+ let req = match GithubReqBuilder :: RateLimit . build_request ( & client, & u. token ) {
162+ Ok ( r) => r,
163+ Err ( e) => {
164+ error ! ( "Unable to build request to update stats: {:?}" , e) ;
165+ return ;
166+ }
167+ } ;
168+
169+ let response = match client. execute ( req) . await {
170+ Ok ( resp) => resp,
171+ Err ( e) => {
172+ error ! ( "Unable to execute request to update stats: {:?}" , e) ;
173+ return ;
174+ }
175+ } ;
176+
177+ let mut data = match response. json :: < GithubRateLimit > ( ) . await {
178+ Ok ( d) => d,
179+ Err ( e) => {
180+ error ! ( "Unable to deserialize rate limit stats: {:?}" , e) ;
181+ return ;
182+ }
183+ } ;
166184
167185 let remaining = data. rate . remove ( "remaining" ) . unwrap_or ( 0 ) ;
168186 let limit = data. rate . remove ( "limit" ) . unwrap_or ( 0 ) ;
@@ -177,7 +195,8 @@ impl GitHubRateLimit {
177195
178196impl Collector for GitHubRateLimit {
179197 fn desc ( & self ) -> std:: vec:: Vec < & prometheus:: core:: Desc > {
180- self . descriptions . iter ( ) . collect ( )
198+ // descriptions are being defined in the initialization of the metrics options
199+ Vec :: default ( )
181200 }
182201
183202 fn collect ( & self ) -> std:: vec:: Vec < prometheus:: proto:: MetricFamily > {
0 commit comments