@@ -28,6 +28,52 @@ interface RateLimitResult {
2828 } | undefined ;
2929}
3030
31+ function isObject ( value : unknown ) : value is Record < string , unknown > {
32+ return typeof value === 'object' && value !== null ;
33+ }
34+
35+ export function getErrorCode ( e : unknown ) : string | undefined {
36+ if ( ! isObject ( e ) ) {
37+ return undefined ;
38+ }
39+
40+ if ( e . status !== undefined ) {
41+ return String ( e . status ) ;
42+ }
43+
44+ const networkError = e . networkError ;
45+ if ( isObject ( networkError ) && networkError . statusCode !== undefined ) {
46+ return String ( networkError . statusCode ) ;
47+ }
48+
49+ const graphQLErrors = e . graphQLErrors ;
50+ if ( Array . isArray ( graphQLErrors ) ) {
51+ const firstGraphQLError = graphQLErrors [ 0 ] ;
52+ if ( isObject ( firstGraphQLError ) ) {
53+ const extensions = firstGraphQLError . extensions ;
54+ if ( isObject ( extensions ) && extensions . code !== undefined ) {
55+ return String ( extensions . code ) ;
56+ }
57+ }
58+ }
59+
60+ if ( e . code !== undefined ) {
61+ return String ( e . code ) ;
62+ }
63+
64+ if ( typeof e . name === 'string' && e . name ) {
65+ const message = typeof e . message === 'string' ? e . message : '' ;
66+ if ( e . name !== 'Error' ) {
67+ return message ? `${ e . name } : ${ message } ` : e . name ;
68+ }
69+ if ( message ) {
70+ return message ;
71+ }
72+ }
73+
74+ return undefined ;
75+ }
76+
3177export class RateLogger {
3278 private bulkhead : BulkheadPolicy = bulkhead ( 140 ) ;
3379 private static ID = 'RateLimit' ;
@@ -111,6 +157,25 @@ export class RateLogger {
111157 }
112158 }
113159
160+ public logApiError ( info : string | undefined , apiResult : Promise < unknown > ) : void {
161+ apiResult . catch ( e => {
162+ const properties : { operation : string ; errorCode ?: string } = {
163+ operation : RateLogger . sanitizeOperationName ( info ?? 'unknown' ) ,
164+ } ;
165+ const errorCode = getErrorCode ( e ) ;
166+ if ( errorCode ) {
167+ properties . errorCode = errorCode ;
168+ }
169+ /* __GDPR__
170+ "pr.apiCallFailed" : {
171+ "operation": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
172+ "errorCode": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
173+ }
174+ */
175+ this . telemetry . sendTelemetryErrorEvent ( 'pr.apiCallFailed' , properties ) ;
176+ } ) ;
177+ }
178+
114179 public async logRestRateLimit ( info : string | undefined , restResponse : Promise < RestResponse > ) {
115180 let result ;
116181 try {
@@ -139,6 +204,7 @@ export class LoggingApolloClient {
139204 throw new Error ( 'API call count has exceeded a rate limit.' ) ;
140205 }
141206 this . _rateLogger . logRateLimit ( logInfo , result as Promise < RateLimitResult > ) ;
207+ this . _rateLogger . logApiError ( logInfo , result ) ;
142208 return result ;
143209 }
144210
@@ -149,6 +215,7 @@ export class LoggingApolloClient {
149215 throw new Error ( 'API call count has exceeded a rate limit.' ) ;
150216 }
151217 this . _rateLogger . logRateLimit ( logInfo , result as Promise < RateLimitResult > ) ;
218+ this . _rateLogger . logApiError ( logInfo , result ) ;
152219 return result ;
153220 }
154221}
@@ -163,6 +230,7 @@ export class LoggingOctokit {
163230 throw new Error ( 'API call count has exceeded a rate limit.' ) ;
164231 }
165232 this . _rateLogger . logRestRateLimit ( logInfo , result as Promise < unknown > as Promise < RestResponse > ) ;
233+ this . _rateLogger . logApiError ( logInfo , result ) ;
166234 return result ;
167235 }
168236}
0 commit comments