1- import type {
2- AxiosError ,
3- AxiosResponse ,
4- InternalAxiosRequestConfig ,
5- } from "axios" ;
1+ import type { AxiosError , AxiosResponse } from "axios" ;
62import { isAxiosError } from "axios" ;
73import { getErrorMessage } from "coder/site/src/api/errors" ;
84import { getErrorDetail } from "../error" ;
@@ -22,109 +18,142 @@ import {
2218} from "./types" ;
2319import { createRequestId , shortId } from "./utils" ;
2420
21+ /**
22+ * Creates metadata for tracking HTTP requests.
23+ */
2524export function createRequestMeta ( ) : RequestMeta {
2625 return {
2726 requestId : createRequestId ( ) ,
2827 startedAt : Date . now ( ) ,
2928 } ;
3029}
3130
31+ /**
32+ * Logs an outgoing HTTP RESTful request.
33+ */
3234export function logRequest (
3335 logger : Logger ,
34- requestId : string ,
35- config : InternalAxiosRequestConfig ,
36+ config : RequestConfigWithMeta ,
3637 logLevel : HttpClientLogLevel ,
3738) : void {
3839 if ( logLevel === HttpClientLogLevel . NONE ) {
3940 return ;
4041 }
4142
42- const method = formatMethod ( config . method ) ;
43- const url = formatUri ( config ) ;
43+ const { requestId, method, url } = parseConfig ( config ) ;
4444 const len = formatContentLength ( config . headers , config . data ) ;
4545
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" ) ) ;
5651}
5752
53+ /**
54+ * Logs an incoming HTTP RESTful response.
55+ */
5856export function logResponse (
5957 logger : Logger ,
60- meta : RequestMeta ,
6158 response : AxiosResponse ,
6259 logLevel : HttpClientLogLevel ,
6360) : void {
6461 if ( logLevel === HttpClientLogLevel . NONE ) {
6562 return ;
6663 }
6764
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 ) ;
7166 const len = formatContentLength ( response . headers , response . data ) ;
7267
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" ) ) ;
8473}
8574
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 (
8781 logger : Logger ,
8882 error : AxiosError | unknown ,
83+ logLevel : HttpClientLogLevel ,
8984) : void {
9085 if ( isAxiosError ( error ) ) {
9186 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 ) ;
9788
98- const msg = getErrorMessage ( error , "" ) ;
89+ const errMsg = getErrorMessage ( error , "" ) ;
9990 const detail = getErrorDetail ( error ) ?? "" ;
91+ const errorParts = [ errMsg , detail ]
92+ . map ( ( part ) => part . trim ( ) )
93+ . filter ( Boolean ) ;
10094
95+ let logPrefix : string ;
96+ let extraLines : string [ ] ;
10197 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 (
109100 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+ ) ;
113104 }
114105
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+ ) ;
118112 } 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 ,
125121 ) ;
126122 }
123+
124+ const msg = [ [ logPrefix , ...errorParts ] . join ( " - " ) , ...extraLines ] ;
125+ logger . error ( msg . join ( "\n" ) ) ;
127126 } else {
128127 logger . error ( "Request error" , error ) ;
129128 }
130129}
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