Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions packages/sdk-client/src/api/api-client-options-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ export const buildOAuth2ApiClientOptions = (params: SinchClientParameters, apiNa
}
const apiClientOptions: ApiClientOptions = {
projectId: params.projectId,
requestPlugins: [new Oauth2TokenRequest(params.keyId, params.keySecret, params.authHostname)],
requestPlugins: [
new Oauth2TokenRequest(params.keyId, params.keySecret, params.authHostname, params.logger),
],
useServicePlanId: false,
logger: params.logger,
};
addPlugins(apiClientOptions, params);
return apiClientOptions;
Expand All @@ -31,6 +34,7 @@ export const buildApplicationSignedApiClientOptions = (
new XTimestampRequest(),
new SigningRequest(params.applicationKey, params.applicationSecret),
],
logger: params.logger,
};
addPlugins(apiClientOptions, params);
return apiClientOptions;
Expand All @@ -44,15 +48,19 @@ export const buildFlexibleOAuth2OrApiTokenApiClientOptions = (params: SinchClien
projectId: params.servicePlanId,
requestPlugins: [new ApiTokenRequest(params.apiToken)],
useServicePlanId: true,
logger: params.logger,
};
if (params.projectId || params.keyId || params.keySecret) {
console.warn('As the servicePlanId and the apiToken are provided, all other credentials will be disregarded.');
}
} else if (params.projectId && params.keyId && params.keySecret) {
apiClientOptions = {
projectId: params.projectId,
requestPlugins: [new Oauth2TokenRequest(params.keyId, params.keySecret, params.authHostname)],
requestPlugins: [
new Oauth2TokenRequest(params.keyId, params.keySecret, params.authHostname, params.logger),
],
useServicePlanId: false,
logger: params.logger,
};
}
if (!apiClientOptions) {
Expand Down
3 changes: 2 additions & 1 deletion packages/sdk-client/src/api/api-client-options.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RequestPlugin } from '../plugins/core/request-plugin';
import { ResponsePlugin } from '../plugins/core/response-plugin';
import { LoggerParameters } from '../domain';

interface BaseApiClientOptions {
/**
Expand Down Expand Up @@ -30,4 +31,4 @@ interface BaseApiClientOptions {
useServicePlanId?: boolean;
}

export interface ApiClientOptions extends Partial<BaseApiClientOptions> {}
export interface ApiClientOptions extends Partial<BaseApiClientOptions>, LoggerParameters {}
1 change: 1 addition & 0 deletions packages/sdk-client/src/api/api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export class ApiClient {
opts = await plugin.load().transform(opts);
}
}
opts.logger = this.apiClientOptions.logger;

return opts;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk-client/src/client/api-fetch-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class ApiFetchClient extends ApiClient {
...options,
requestPlugins: [new VersionRequest(), ...(options.requestPlugins || [])],
responsePlugins: [
new ExceptionResponse(),
new ExceptionResponse(undefined, options.logger),
...(options.responsePlugins || []),
],
});
Expand Down
9 changes: 8 additions & 1 deletion packages/sdk-client/src/domain/domain-interface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RequestPlugin } from '../plugins/core/request-plugin';
import { ResponsePlugin } from '../plugins/core/response-plugin';
import { Logger } from '../logger';

/**
* Global object that holds the API configuration.
Expand All @@ -13,7 +14,8 @@ export interface SinchClientParameters extends
Partial<ServicePlanIdCredentials>,
Partial<ApplicationCredentials>,
ApiHostname,
ApiPlugins {}
ApiPlugins,
LoggerParameters {}

export interface UnifiedCredentials {
/** The project ID associated with the API Client. You can find this on your [Dashboard](https://dashboard.sinch.com/account/access-keys). */
Expand Down Expand Up @@ -158,3 +160,8 @@ export type ConversationRegion = SupportedConversationRegion | string;
export const ConversationRegion = {
...SupportedConversationRegion,
};

export interface LoggerParameters {
/** Logger instance to be used by the SDK */
logger?: Logger;
}
1 change: 1 addition & 0 deletions packages/sdk-client/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './api';
export * from './client';
export * from './domain';
export * from './logger';
export * from './plugins';
export * from './utils';
1 change: 1 addition & 0 deletions packages/sdk-client/src/logger/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './logger';
6 changes: 6 additions & 0 deletions packages/sdk-client/src/logger/logger.ts

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️
May be adding some unit tests to ensure proper/format and log level.
Not sure we want to go to this direction for console logger and this PR, but other logging frameworks (e.g.: winston pointed by PR comment) are enabling to configure log level to not flood logs output/destination

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Logger {
debug(message: string, ...meta: any[]): void;
info(message: string, ...meta: any[]): void;
warn(message: string, ...meta: any[]): void;
error(message: string, ...meta: any[]): void;
}
3 changes: 2 additions & 1 deletion packages/sdk-client/src/plugins/core/request-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Plugin, PluginRunner } from './plugin';
import { Headers, RequestInit } from 'node-fetch';
import FormData = require('form-data');
import { LoggerParameters } from '../../domain';

export type RequestBody = string | FormData;

Expand All @@ -14,7 +15,7 @@ export enum RequestPluginEnum {
X_TIMESTAMP_REQUEST = 'XTimestampRequest'
}

export interface RequestOptions extends RequestInit {
export interface RequestOptions extends RequestInit, LoggerParameters {
/** Query Parameters */
queryParams?: { [key: string]: string };
/** Force body to string */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { EmptyResponseError, RequestFailedError } from '../../api/api-errors';
import { PluginRunner } from '../core';
import { ResponsePlugin, ResponsePluginContext } from '../core/response-plugin';
import { Logger } from '../../logger';

/**
* Plugin to fire an exception on wrong response / data
Expand All @@ -13,14 +14,19 @@ export class ExceptionResponse<
* Initialize an instance of the class, with an optional callback function for exception handling.
*
* @param {Function} [callback] - A function called in case of an exception. If provided, this function is responsible for throwing the exception or not.
* @param {Logger} logger
*/
constructor(private callback?: (res: V, error: Error | undefined) => V) {}
constructor(
private callback?: (res: V, error: Error | undefined) => V,
private logger: Logger = console,
) {}

public load(
context: ResponsePluginContext,
): PluginRunner<V | Record<string, unknown>, V> {
return {
transform: (res: V) => {
this.debug(context);
if (context.exception) {
return res;
}
Expand Down Expand Up @@ -72,4 +78,27 @@ export class ExceptionResponse<
},
};
}

private debug(context: ResponsePluginContext) {
if (!context.response?.ok) {
this.logger.debug(
`[Sinch SDK][Debug][${context.apiName}][${context.operationId}][${context.response?.status}]\nHTTP method: ${context.requestOptions.method}\nURL: ${context.url}\nResponse Headers: ${this.formatHeaders(context.response?.headers)}`,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about having the logger itself adding these formatting information ?

  • this.logger: will know "it is" SDK -> it will add it when emitting log
  • this.logger.debug: logger.debug function will know it is debug level then it will be added when emitting log

PROS:

  • all calls to logger will be prefixed by same ... prefix
  • all calls to logger./debug/info/..will have same prefix regarding log level
  • all logs will have same pattern [Sinch SDK][level] and no human error to forgot them services will call logger function

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

);
}
}

private formatHeaders(headers: any) {
if (!headers || typeof headers !== 'object') {
return '';
}

return Object.entries(Object.fromEntries(headers.entries()))
.map(([key, value]: [any, any]) => {
if (value === undefined) { return `${key}=undefined`; }
if (value === null) { return `${key}=null`; }
if (typeof value === 'object') { return `${key}=${JSON.stringify(value)}`; }
return `${key}=${String(value)}`;
})
.join(', ');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { OAuth2Api } from './oauth2-api';
import { BasicAuthenticationRequest } from '../basicAuthentication';
import { ApiFetchClient } from '../../client/api-fetch-client';
import { AUTH_HOSTNAME } from '../../domain';
import { Logger } from '../../logger';

export class Oauth2TokenRequest implements RequestPlugin {
private readonly apiClient: ApiClient;
Expand All @@ -20,6 +21,7 @@ export class Oauth2TokenRequest implements RequestPlugin {
clientId: string,
clientSecret: string,
authenticationUrl?: string,
logger?: Logger,
) {
const basicAuthenticationPlugin = new BasicAuthenticationRequest(
clientId,
Expand All @@ -31,6 +33,7 @@ export class Oauth2TokenRequest implements RequestPlugin {
this.apiClient = new ApiFetchClient({
hostname: authenticationUrl,
requestPlugins: [basicAuthenticationPlugin],
logger,
});
}

Expand Down
3 changes: 3 additions & 0 deletions packages/sdk-core/src/sinch-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export class SinchClient {
* @param {SinchClientParameters} params - The object containing the Sinch credentials.
*/
constructor(params: SinchClientParameters) {
if (!params.logger) {
params.logger = console;
}
this.conversation = new ConversationService(params);
this.elasticSipTrunking = new ElasticSipTrunkingService(params);
this.fax = new FaxService(params);
Expand Down
Loading