1
- import type {
2
- AxiosError ,
3
- AxiosResponse ,
4
- InternalAxiosRequestConfig ,
5
- } from "axios" ;
1
+ import type { AxiosError , AxiosResponse } from "axios" ;
6
2
import { isAxiosError } from "axios" ;
7
3
import { getErrorMessage } from "coder/site/src/api/errors" ;
8
4
import { getErrorDetail } from "../error" ;
@@ -22,109 +18,142 @@ import {
22
18
} from "./types" ;
23
19
import { createRequestId , shortId } from "./utils" ;
24
20
21
+ /**
22
+ * Creates metadata for tracking HTTP requests.
23
+ */
25
24
export function createRequestMeta ( ) : RequestMeta {
26
25
return {
27
26
requestId : createRequestId ( ) ,
28
27
startedAt : Date . now ( ) ,
29
28
} ;
30
29
}
31
30
31
+ /**
32
+ * Logs an outgoing HTTP RESTful request.
33
+ */
32
34
export function logRequest (
33
35
logger : Logger ,
34
- requestId : string ,
35
- config : InternalAxiosRequestConfig ,
36
+ config : RequestConfigWithMeta ,
36
37
logLevel : HttpClientLogLevel ,
37
38
) : void {
38
39
if ( logLevel === HttpClientLogLevel . NONE ) {
39
40
return ;
40
41
}
41
42
42
- const method = formatMethod ( config . method ) ;
43
- const url = formatUri ( config ) ;
43
+ const { requestId, method, url } = parseConfig ( config ) ;
44
44
const len = formatContentLength ( config . headers , config . data ) ;
45
45
46
- let msg = `→ ${ shortId ( requestId ) } ${ method } ${ url } ${ len } ` ;
47
- if ( logLevel >= HttpClientLogLevel . HEADERS ) {
48
- msg += `\n${ formatHeaders ( config . headers ) } ` ;
49
- }
50
-
51
- if ( logLevel >= HttpClientLogLevel . BODY ) {
52
- msg += `\n${ formatBody ( config . data ) } ` ;
53
- }
54
-
55
- logger . trace ( msg ) ;
46
+ const msg = [
47
+ `→ ${ shortId ( requestId ) } ${ method } ${ url } ${ len } ` ,
48
+ ...buildExtraLogs ( config . headers , config . data , logLevel ) ,
49
+ ] ;
50
+ logger . trace ( msg . join ( "\n" ) ) ;
56
51
}
57
52
53
+ /**
54
+ * Logs an incoming HTTP RESTful response.
55
+ */
58
56
export function logResponse (
59
57
logger : Logger ,
60
- meta : RequestMeta ,
61
58
response : AxiosResponse ,
62
59
logLevel : HttpClientLogLevel ,
63
60
) : void {
64
61
if ( logLevel === HttpClientLogLevel . NONE ) {
65
62
return ;
66
63
}
67
64
68
- const method = formatMethod ( response . config . method ) ;
69
- const url = formatUri ( response . config ) ;
70
- const time = formatTime ( Date . now ( ) - meta . startedAt ) ;
65
+ const { requestId, method, url, time } = parseConfig ( response . config ) ;
71
66
const len = formatContentLength ( response . headers , response . data ) ;
72
67
73
- let msg = `← ${ shortId ( meta . requestId ) } ${ response . status } ${ method } ${ url } ${ len } ${ time } ` ;
74
-
75
- if ( logLevel >= HttpClientLogLevel . HEADERS ) {
76
- msg += `\n${ formatHeaders ( response . headers ) } ` ;
77
- }
78
-
79
- if ( logLevel >= HttpClientLogLevel . BODY ) {
80
- msg += `\n${ formatBody ( response . data ) } ` ;
81
- }
82
-
83
- logger . trace ( msg ) ;
68
+ const msg = [
69
+ `← ${ shortId ( requestId ) } ${ response . status } ${ method } ${ url } ${ len } ${ time } ` ,
70
+ ...buildExtraLogs ( response . headers , response . data , logLevel ) ,
71
+ ] ;
72
+ logger . trace ( msg . join ( "\n" ) ) ;
84
73
}
85
74
86
- export function logRequestError (
75
+ /**
76
+ * Logs HTTP RESTful request errors and failures.
77
+ *
78
+ * Note: Errors are always logged regardless of log level.
79
+ */
80
+ export function logError (
87
81
logger : Logger ,
88
82
error : AxiosError | unknown ,
83
+ logLevel : HttpClientLogLevel ,
89
84
) : void {
90
85
if ( isAxiosError ( error ) ) {
91
86
const config = error . config as RequestConfigWithMeta | undefined ;
92
- const meta = config ?. metadata ;
93
- const method = formatMethod ( config ?. method ) ;
94
- const url = formatUri ( config ) ;
95
- const requestId = meta ?. requestId || "unknown" ;
96
- const time = meta ? formatTime ( Date . now ( ) - meta . startedAt ) : "?ms" ;
87
+ const { requestId, method, url, time } = parseConfig ( config ) ;
97
88
98
- const msg = getErrorMessage ( error , "" ) ;
89
+ const errMsg = getErrorMessage ( error , "" ) ;
99
90
const detail = getErrorDetail ( error ) ?? "" ;
91
+ const errorParts = [ errMsg , detail ]
92
+ . map ( ( part ) => part . trim ( ) )
93
+ . filter ( Boolean ) ;
100
94
95
+ let logPrefix : string ;
96
+ let extraLines : string [ ] ;
101
97
if ( error . response ) {
102
- const msgParts = [
103
- `← ${ shortId ( requestId ) } ${ error . response . status } ${ method } ${ url } ${ time } ` ,
104
- msg ,
105
- detail ,
106
- ] ;
107
- if ( msg . trim ( ) . length === 0 && detail . trim ( ) . length === 0 ) {
108
- const responseData =
98
+ if ( errorParts . length === 0 ) {
99
+ errorParts . push (
109
100
error . response . statusText ||
110
- String ( error . response . data ) . slice ( 0 , 100 ) ||
111
- "No error info" ;
112
- msgParts . push ( responseData ) ;
101
+ String ( error . response . data ) . slice ( 0 , 100 ) ||
102
+ "No error info" ,
103
+ ) ;
113
104
}
114
105
115
- const fullMsg = msgParts . map ( ( str ) => str . trim ( ) ) . join ( " - " ) ;
116
- const headers = formatHeaders ( error . response . headers ) ;
117
- logger . error ( `${ fullMsg } \n${ headers } ` , error ) ;
106
+ logPrefix = `← ${ shortId ( requestId ) } ${ error . response . status } ${ method } ${ url } ${ time } ` ;
107
+ extraLines = buildExtraLogs (
108
+ error . response . headers ,
109
+ error . response . data ,
110
+ logLevel ,
111
+ ) ;
118
112
} else {
119
- const reason = error . code || error . message || "Network error" ;
120
- const errorInfo = [ msg , detail , reason ] . filter ( Boolean ) . join ( " - " ) ;
121
- const headers = formatHeaders ( config ?. headers ?? { } ) ;
122
- logger . error (
123
- `✗ ${ shortId ( requestId ) } ${ method } ${ url } ${ time } - ${ errorInfo } \n${ headers } ` ,
124
- error ,
113
+ if ( errorParts . length === 0 ) {
114
+ errorParts . push ( error . code || "Network error" ) ;
115
+ }
116
+ logPrefix = `✗ ${ shortId ( requestId ) } ${ method } ${ url } ${ time } ` ;
117
+ extraLines = buildExtraLogs (
118
+ error ?. config ?. headers ?? { } ,
119
+ error . config ?. data ,
120
+ logLevel ,
125
121
) ;
126
122
}
123
+
124
+ const msg = [ [ logPrefix , ...errorParts ] . join ( " - " ) , ...extraLines ] ;
125
+ logger . error ( msg . join ( "\n" ) ) ;
127
126
} else {
128
127
logger . error ( "Request error" , error ) ;
129
128
}
130
129
}
130
+
131
+ function buildExtraLogs (
132
+ headers : Record < string , unknown > ,
133
+ body : unknown ,
134
+ logLevel : HttpClientLogLevel ,
135
+ ) {
136
+ const msg = [ ] ;
137
+ if ( logLevel >= HttpClientLogLevel . HEADERS ) {
138
+ msg . push ( formatHeaders ( headers ) ) ;
139
+ }
140
+ if ( logLevel >= HttpClientLogLevel . BODY ) {
141
+ msg . push ( formatBody ( body ) ) ;
142
+ }
143
+ return msg ;
144
+ }
145
+
146
+ function parseConfig ( config : RequestConfigWithMeta | undefined ) : {
147
+ requestId : string ;
148
+ method : string ;
149
+ url : string ;
150
+ time : string ;
151
+ } {
152
+ const meta = config ?. metadata ;
153
+ return {
154
+ requestId : meta ?. requestId || "unknown" ,
155
+ method : formatMethod ( config ?. method ) ,
156
+ url : formatUri ( config ) ,
157
+ time : meta ? formatTime ( Date . now ( ) - meta . startedAt ) : "?ms" ,
158
+ } ;
159
+ }
0 commit comments