11use prometheus:: { core:: Collector , IntGauge , Opts } ;
22
33use crate :: Config ;
4+ use anyhow:: { Context , 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 , Error > {
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,49 +39,50 @@ 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
4951impl GitHubRateLimit {
50- pub async fn new ( config : & Config ) -> Self {
52+ pub async fn new ( config : & Config ) -> Result < Self , Error > {
5153 let tokens: Vec < String > = config
5254 . gh_rate_limit_tokens
5355 . split ( ',' )
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+ let users = Self :: get_users_for_tokens ( tokens)
60+ . await
61+ . context ( "Unable to get usernames for rate limit stats" ) ?;
5962
60- let rv = Self {
61- users,
62- descriptions,
63- } ;
63+ let rv = Self { users } ;
6464
6565 let refresh_rate = config. gh_rate_limit_stats_cache_refresh ;
6666 let mut rv2 = rv. clone ( ) ;
6767 tokio:: spawn ( async move {
6868 loop {
69- rv2. update_stats ( ) . await ;
69+ if let Err ( e) = rv2. update_stats ( ) . await {
70+ error ! ( "{:#?}" , e) ;
71+ }
72+
7073 tokio:: time:: delay_for ( Duration :: from_secs ( refresh_rate) ) . await ;
7174 }
7275 } ) ;
7376
74- rv
77+ Ok ( rv )
7578 }
7679
77- async fn get_users_for_tokens ( tokens : Vec < String > ) -> Vec < User > {
80+ async fn get_users_for_tokens ( tokens : Vec < String > ) -> Result < Vec < User > , Error > {
7881 let ns = String :: from ( "monitorbot_github_rate_limit" ) ;
7982 let mut rv: Vec < User > = Vec :: new ( ) ;
8083 for token in tokens. into_iter ( ) {
8184 let ns2 = ns. clone ( ) ;
82- let username = GitHubRateLimit :: get_github_api_username ( & token) . await ;
85+ let username = GitHubRateLimit :: get_github_api_username ( & token) . await ? ;
8386 let user_future = tokio:: task:: spawn_blocking ( move || {
8487 let rate_limit = IntGauge :: with_opts (
8588 Opts :: new ( "limit" , "Rate limit." )
@@ -119,50 +122,45 @@ impl GitHubRateLimit {
119122 rv. push ( user) ;
120123 }
121124
122- rv
125+ Ok ( rv )
123126 }
124127
125- async fn get_github_api_username ( token : & str ) -> String {
128+ async fn get_github_api_username ( token : & str ) -> Result < String , Error > {
126129 #[ derive( serde:: Deserialize ) ]
127130 struct GithubUser {
128131 pub login : String ,
129132 }
130133
131134 let client = reqwest:: Client :: new ( ) ;
132- let req = GithubReqBuilder :: User
133- . build_request ( & client, & token)
134- . unwrap ( ) ;
135- let u = client
136- . execute ( req)
137- . await
138- . unwrap ( )
139- . json :: < GithubUser > ( )
140- . await
141- . unwrap ( ) ;
135+ let req = GithubReqBuilder :: User . build_request ( & client, & token) ?;
136+ let u = client. execute ( req) . await ?. json :: < GithubUser > ( ) . await ?;
142137
143- u. login
138+ Ok ( u. login )
144139 }
145140
146- async fn update_stats ( & mut self ) {
141+ async fn update_stats ( & mut self ) -> Result < ( ) , Error > {
142+ debug ! ( "Updating rate limit stats" ) ;
143+
147144 #[ derive( Debug , serde:: Deserialize ) ]
148145 struct GithubRateLimit {
149146 pub rate : HashMap < String , usize > ,
150147 }
151148
152149 let client = reqwest:: Client :: new ( ) ;
153-
154- //FIXME: we will (might?) need a RWLock on users structure
155150 for u in self . users . iter_mut ( ) {
156151 let req = GithubReqBuilder :: RateLimit
157152 . build_request ( & client, & u. token )
158- . unwrap ( ) ;
159- let mut data = client
153+ . context ( "Unable to build request to update stats" ) ?;
154+
155+ let response = client
160156 . execute ( req)
161157 . await
162- . unwrap ( )
158+ . context ( "Unable to execute request to update stats" ) ?;
159+
160+ let mut data = response
163161 . json :: < GithubRateLimit > ( )
164162 . await
165- . unwrap ( ) ;
163+ . context ( "Unable to deserialize rate limit stats" ) ? ;
166164
167165 let remaining = data. rate . remove ( "remaining" ) . unwrap_or ( 0 ) ;
168166 let limit = data. rate . remove ( "limit" ) . unwrap_or ( 0 ) ;
@@ -172,12 +170,15 @@ impl GitHubRateLimit {
172170 u. reset . set ( reset as i64 ) ;
173171 u. limit . set ( limit as i64 ) ;
174172 }
173+
174+ Ok ( ( ) )
175175 }
176176}
177177
178178impl Collector for GitHubRateLimit {
179179 fn desc ( & self ) -> std:: vec:: Vec < & prometheus:: core:: Desc > {
180- self . descriptions . iter ( ) . collect ( )
180+ // descriptions are being defined in the initialization of the metrics options
181+ Vec :: default ( )
181182 }
182183
183184 fn collect ( & self ) -> std:: vec:: Vec < prometheus:: proto:: MetricFamily > {
0 commit comments