-
Notifications
You must be signed in to change notification settings - Fork 427
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: better payload for proxy logs and operations #2631
Changes from all commits
72332f6
897123f
34e8192
b3c6e53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import type { Request, Response, NextFunction } from 'express'; | ||
import type { OutgoingHttpHeaders } from 'http'; | ||
import type { OutgoingHttpHeaders, IncomingHttpHeaders } from 'http'; | ||
import type { TransformCallback } from 'stream'; | ||
import type stream from 'stream'; | ||
import { Readable, Transform, PassThrough } from 'stream'; | ||
|
@@ -161,6 +161,31 @@ class ProxyController { | |
} | ||
metrics.increment(metrics.Types.PROXY_FAILURE); | ||
next(err); | ||
} finally { | ||
const getHeaders = (hs: IncomingHttpHeaders | OutgoingHttpHeaders): Record<string, string> => { | ||
const headers: Record<string, string> = {}; | ||
for (const [key, value] of Object.entries(hs)) { | ||
if (typeof value === 'string') { | ||
headers[key] = value; | ||
} else if (Array.isArray(value)) { | ||
headers[key] = value.join(', '); | ||
} | ||
} | ||
return headers; | ||
}; | ||
const reqHeaders = getHeaders(req.headers); | ||
reqHeaders['authorization'] = 'REDACTED'; | ||
await logCtx?.enrichOperation({ | ||
request: { | ||
url: `${req.protocol}://${req.get('host')}${req.originalUrl}`, | ||
method: req.method, | ||
headers: reqHeaders | ||
}, | ||
response: { | ||
code: res.statusCode, | ||
headers: getHeaders(res.getHeaders()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we are gonna log way more content with the headers. Is it gonna be ok with ES? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need to increase the disk size anyway. It will increase the storage a bit but most logs are empty (!= operation) |
||
} | ||
}); | ||
} | ||
} | ||
|
||
|
@@ -213,7 +238,17 @@ class ProxyController { | |
logCtx: LogContext; | ||
}) { | ||
const safeHeaders = proxyService.stripSensitiveHeaders(config.headers, config); | ||
await logCtx.info(`${config.method.toUpperCase()} ${url} was successful`, { headers: safeHeaders }); | ||
await logCtx.http(`${config.method.toUpperCase()} ${url} was successful`, { | ||
request: { | ||
method: config.method, | ||
url, | ||
headers: safeHeaders | ||
}, | ||
response: { | ||
code: responseStream.status, | ||
headers: responseStream.headers as Record<string, string> | ||
} | ||
}); | ||
|
||
const contentType = responseStream.headers['content-type']; | ||
const isJsonResponse = contentType && contentType.includes('application/json'); | ||
|
@@ -309,8 +344,16 @@ class ProxyController { | |
chunks.push(data); | ||
}); | ||
stringify.on('end', () => { | ||
const data = chunks.length > 0 ? Buffer.concat(chunks).toString() : 'unknown error'; | ||
void this.reportError(error, url, config, data, logCtx); | ||
const data = chunks.length > 0 ? Buffer.concat(chunks).toString() : ''; | ||
let errorData: string | Record<string, string> = data; | ||
if (error.response?.headers?.['content-type']?.includes('application/json')) { | ||
try { | ||
errorData = JSON.parse(data); | ||
} catch { | ||
// Intentionally left blank - errorData will be a string | ||
} | ||
} | ||
void this.reportError(error, url, config, errorData, logCtx); | ||
}); | ||
} else { | ||
await logCtx.error('Unknown error'); | ||
|
@@ -379,14 +422,27 @@ class ProxyController { | |
} | ||
} | ||
|
||
private async reportError(error: AxiosError, url: string, config: ApplicationConstructedProxyConfiguration, errorMessage: string, logCtx: LogContext) { | ||
private async reportError( | ||
error: AxiosError, | ||
url: string, | ||
config: ApplicationConstructedProxyConfiguration, | ||
errorContent: string | Record<string, string>, | ||
logCtx: LogContext | ||
) { | ||
const safeHeaders = proxyService.stripSensitiveHeaders(config.headers, config); | ||
await logCtx.error(`${error.request?.method.toUpperCase()} ${url} failed with status '${error.response?.status}'`, { | ||
code: error.response?.status, | ||
url, | ||
error: new Error(errorMessage), | ||
requestHeaders: safeHeaders, | ||
responseHeaders: error.response?.headers | ||
await logCtx.http(`${error.request?.method.toUpperCase()} ${url} failed with status '${error.response?.status}'`, { | ||
meta: { | ||
content: errorContent | ||
}, | ||
request: { | ||
method: config.method, | ||
url, | ||
headers: safeHeaders | ||
}, | ||
response: { | ||
code: error.response?.status || 500, | ||
headers: error.response?.headers as Record<string, string> | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note we can also modify the client to build the object automatically (like the way I did with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure it make sense to tie logs to Axios. |
||
}); | ||
await logCtx.failed(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't use proxy.service->stripSensitiveHeaders ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it requires a proxy config but things can fail before having a valid config