(options: LoggingOptions = {})
| 154 | * @returns A fetch middleware function |
| 155 | */ |
| 156 | export const withLogging = (options: LoggingOptions = {}): Middleware => { |
| 157 | const { logger, includeRequestHeaders = false, includeResponseHeaders = false, statusLevel = 0 } = options; |
| 158 | |
| 159 | const defaultLogger: RequestLogger = input => { |
| 160 | const { method, url, status, statusText, duration, requestHeaders, responseHeaders, error } = input; |
| 161 | |
| 162 | let message = error |
| 163 | ? `HTTP ${method} ${url} failed: ${error.message} (${duration}ms)` |
| 164 | : `HTTP ${method} ${url} ${status} ${statusText} (${duration}ms)`; |
| 165 | |
| 166 | // Add headers to message if requested |
| 167 | if (includeRequestHeaders && requestHeaders) { |
| 168 | const reqHeaders = Array.from(requestHeaders.entries()) |
| 169 | .map(([key, value]) => `${key}: ${value}`) |
| 170 | .join(', '); |
| 171 | message += `\n Request Headers: {${reqHeaders}}`; |
| 172 | } |
| 173 | |
| 174 | if (includeResponseHeaders && responseHeaders) { |
| 175 | const resHeaders = Array.from(responseHeaders.entries()) |
| 176 | .map(([key, value]) => `${key}: ${value}`) |
| 177 | .join(', '); |
| 178 | message += `\n Response Headers: {${resHeaders}}`; |
| 179 | } |
| 180 | |
| 181 | if (error || status >= 400) { |
| 182 | // eslint-disable-next-line no-console |
| 183 | console.error(message); |
| 184 | } else { |
| 185 | // eslint-disable-next-line no-console |
| 186 | console.log(message); |
| 187 | } |
| 188 | }; |
| 189 | |
| 190 | const logFn = logger || defaultLogger; |
| 191 | |
| 192 | return next => async (input, init) => { |
| 193 | const startTime = performance.now(); |
| 194 | const method = init?.method || 'GET'; |
| 195 | const url = typeof input === 'string' ? input : input.toString(); |
| 196 | const requestHeaders = includeRequestHeaders ? new Headers(init?.headers) : undefined; |
| 197 | |
| 198 | try { |
| 199 | const response = await next(input, init); |
| 200 | const duration = performance.now() - startTime; |
| 201 | |
| 202 | // Only log if status meets the log level threshold |
| 203 | if (response.status >= statusLevel) { |
| 204 | logFn({ |
| 205 | method, |
| 206 | url, |
| 207 | status: response.status, |
| 208 | statusText: response.statusText, |
| 209 | duration, |
| 210 | requestHeaders, |
| 211 | responseHeaders: includeResponseHeaders ? response.headers : undefined |
| 212 | }); |
| 213 | } |
no test coverage detected
searching dependent graphs…