diff --git a/packages/cli/lib/services/__snapshots__/model.service.unit.test.ts.snap b/packages/cli/lib/services/__snapshots__/model.service.unit.test.ts.snap index da0b6169ac..ca02182728 100644 --- a/packages/cli/lib/services/__snapshots__/model.service.unit.test.ts.snap +++ b/packages/cli/lib/services/__snapshots__/model.service.unit.test.ts.snap @@ -399,6 +399,7 @@ export declare class NangoAction { triggerAction(providerConfigKey: string, connectionId: string, actionName: string, input?: In): Promise; triggerSync(providerConfigKey: string, connectionId: string, syncName: string, fullResync?: boolean): Promise; private sendLogToPersist; + private logAPICall; } export declare class NangoSync extends NangoAction { lastSyncDate?: Date; diff --git a/packages/shared/lib/sdk/sync.ts b/packages/shared/lib/sdk/sync.ts index a765576123..23209ce9e9 100644 --- a/packages/shared/lib/sdk/sync.ts +++ b/packages/shared/lib/sdk/sync.ts @@ -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); + } + 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[] = [ + ...Array.from(this.memoizedConnections.values()).reduce((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 { diff --git a/packages/shared/lib/services/proxy.service.ts b/packages/shared/lib/services/proxy.service.ts index 33030576b0..2692aa3602 100644 --- a/packages/shared/lib/services/proxy.service.ts +++ b/packages/shared/lib/services/proxy.service.ts @@ -539,7 +539,7 @@ class ProxyService { }, response: { code: response.status, - headers: response.headers as Record + headers: (response.headers || {}) as Record } } ] @@ -574,7 +574,7 @@ class ProxyService { }, response: { code: error.response?.status || 500, - headers: error.response?.headers as Record + headers: (error.response?.headers || {}) as Record }, error: { name: error.name,