-
Notifications
You must be signed in to change notification settings - Fork 444
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
feat(sdk): automatically log http calls to API #3081
Changes from all commits
d55b0f5
74afa85
c77ef96
6ee1546
7086780
74b3e36
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 |
---|---|---|
|
@@ -23,6 +23,7 @@ import { validateData } from './dataValidation.js'; | |
import { NangoError } from '../utils/error.js'; | ||
import type { DBTeam, GetPublicIntegration, MessageRowInsert, RunnerFlags } from '@nangohq/types'; | ||
import { getProvider } from '../services/providers.js'; | ||
import { redactHeaders, redactURL } from '../utils/http.js'; | ||
|
||
const logger = getLogger('SDK'); | ||
|
||
|
@@ -475,6 +476,14 @@ export class NangoAction { | |
}; | ||
} | ||
} | ||
if (!config.axios?.response) { | ||
// Leave the priority to saving response instead of logging | ||
axiosSettings.interceptors = { | ||
response: { | ||
onFulfilled: this.logAPICall.bind(this) | ||
} | ||
}; | ||
} | ||
|
||
if (config.environmentName) { | ||
this.environmentName = config.environmentName; | ||
|
@@ -760,7 +769,15 @@ export class NangoAction { | |
const level = userDefinedLevel?.level ?? 'info'; | ||
|
||
if (this.dryRun) { | ||
logger[logLevelToLogger[level] ?? 'info'].apply(null, args as any); | ||
const logLevel = logLevelToLogger[level] ?? 'info'; | ||
|
||
// TODO: we shouldn't use a floating logger, it should be passed from dryrun or runner | ||
if (args.length > 1 && 'type' in args[1] && args[1].type === 'http') { | ||
logger[logLevel].apply(null, [args[0], { status: args[1]?.response?.code || 'xxx' }] as any); | ||
} else { | ||
logger[logLevel].apply(null, args as any); | ||
} | ||
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. Would something like this be easier to read
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. honestly I don't know ahah |
||
|
||
return; | ||
} | ||
|
||
|
@@ -909,10 +926,51 @@ export class NangoAction { | |
} | ||
|
||
if (response.status > 299) { | ||
logger.error(`Request to persist API (log) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}'`, this.stringify()); | ||
logger.error( | ||
`Request to persist API (log) failed: errorCode=${response.status} response='${JSON.stringify(response.data)}' log=${JSON.stringify(log)}`, | ||
this.stringify() | ||
); | ||
throw new Error(`Failed to log: ${JSON.stringify(response.data)}`); | ||
} | ||
} | ||
|
||
private logAPICall(res: AxiosResponse): AxiosResponse { | ||
if (!res.config.url) { | ||
return res; | ||
} | ||
|
||
// We compte on the fly because connection's credentials can change during a single run | ||
// We could further optimize this and cache it when the memoizedConnection is updated | ||
const valuesToFilter: 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. Just a small thought for the future: Could we compute our filter array once up front before any runner work and have the logger lean on it across all logging? 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. agreed. The valuesToFilter should not changed within a single execution 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. actually it's changing because connection's credentials can change during execution, but the value could be cached indeed. I'll add a comment |
||
...Array.from(this.memoizedConnections.values()).reduce<string[]>((acc, conn) => { | ||
if (!conn) { | ||
return acc; | ||
} | ||
acc.push(...Object.values(conn.connection.credentials)); | ||
return acc; | ||
}, []), | ||
this.nango.secretKey | ||
]; | ||
|
||
const method = res.config.method?.toLocaleUpperCase(); // axios put it in lowercase; | ||
void this.log( | ||
`${method} ${res.config.url}`, | ||
{ | ||
type: 'http', | ||
request: { | ||
method: method, | ||
url: redactURL({ url: res.config.url, valuesToFilter }), | ||
headers: redactHeaders({ headers: res.config.headers, valuesToFilter }) | ||
}, | ||
response: { | ||
code: res.status, | ||
headers: redactHeaders({ headers: res.headers, valuesToFilter }) | ||
} | ||
}, | ||
{ level: res.status > 299 ? 'error' : 'info' } | ||
); | ||
return res; | ||
} | ||
} | ||
|
||
export class NangoSync extends NangoAction { | ||
|
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.
do I read correctly that it doesn't override the interceptors defined a few lines above that is used for snapshoting in dry-mode?
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.
yes exactly, I'll add a comment