Skip to content

Commit 575cc46

Browse files
authored
Merge pull request #4169 from RedisInsight/be/feature/RI-6215-investigate-sso-errors
RI-6215 added logging to cloud module
2 parents 7befd01 + 90ef016 commit 575cc46

File tree

12 files changed

+78
-27
lines changed

12 files changed

+78
-27
lines changed
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { HttpException, InternalServerErrorException } from '@nestjs/common';
2+
import { AxiosError } from 'axios';
23

3-
export const wrapHttpError = (error: Error, message?: string) => {
4+
export const wrapHttpError = (error: Error | AxiosError, message?: string) => {
45
if (error instanceof HttpException) {
56
return error;
67
}
78

8-
return new InternalServerErrorException(error.message || message);
9+
const { response } = error as any;
10+
const errorMessage = error.message || message || response?.data?.message;
11+
const descriptionOrOptions = response?.data?.description || response?.data?.options;
12+
13+
return new InternalServerErrorException(errorMessage, descriptionOrOptions);
914
};

redisinsight/api/src/modules/ai/chat/exceptions/conv-ai.error.handler.spec.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,50 @@ describe('wrapConvAiError', () => {
1818
it('Should return ConvAiBadRequestException of status code is 400', async () => {
1919
const error = wrapConvAiError(mockAiChatBadRequestError);
2020
expect(error).toBeInstanceOf(ConvAiBadRequestException);
21-
expect(error).toEqual(new ConvAiBadRequestException());
21+
expect(error).toEqual(new ConvAiBadRequestException(mockAiChatBadRequestError.message));
2222
});
2323
it('Should return ConvAiUnauthorizedException of status code is 401', async () => {
2424
const error = wrapConvAiError(mockAiChatUnauthorizedError);
2525
expect(error).toBeInstanceOf(ConvAiUnauthorizedException);
26-
expect(error).toEqual(new ConvAiUnauthorizedException());
26+
expect(error).toEqual(new ConvAiUnauthorizedException(mockAiChatUnauthorizedError.message));
2727
});
2828
it('Should return ConvAiForbiddenException of status code is 403', async () => {
2929
const error = wrapConvAiError(mockAiChatAccessDeniedError);
3030
expect(error).toBeInstanceOf(ConvAiForbiddenException);
31-
expect(error).toEqual(new ConvAiForbiddenException());
31+
expect(error).toEqual(new ConvAiForbiddenException(mockAiChatAccessDeniedError.message));
3232
});
3333
it('Should return ConvAiNotFoundException of status code is 404', async () => {
3434
const error = wrapConvAiError(mockAiChatNotFoundError);
3535
expect(error).toBeInstanceOf(ConvAiNotFoundException);
36-
expect(error).toEqual(new ConvAiNotFoundException());
36+
expect(error).toEqual(new ConvAiNotFoundException(mockAiChatNotFoundError.message));
3737
});
3838
it('Should return ConvAiInternalServerErrorException of status code is 500', async () => {
3939
const error = wrapConvAiError(mockAiChatInternalServerError);
4040
expect(error).toBeInstanceOf(ConvAiInternalServerErrorException);
41-
expect(error).toEqual(new ConvAiInternalServerErrorException());
41+
expect(error).toEqual(new ConvAiInternalServerErrorException(mockAiChatInternalServerError.message));
4242
});
4343
it('Should return ConvAiInternalServerErrorException by default', async () => {
44+
const errorMessage = 'Unreachable error';
4445
const mockAxiosError = {
4546
response: {
4647
status: 503,
4748
data: {
48-
message: 'Unreachable error',
49+
message: errorMessage,
4950
},
5051
},
5152
} as AxiosError;
5253

5354
const error = wrapConvAiError(mockAxiosError);
5455
expect(error).toBeInstanceOf(ConvAiInternalServerErrorException);
55-
expect(error).toEqual(new ConvAiInternalServerErrorException());
56+
expect(error).toEqual(new ConvAiInternalServerErrorException(errorMessage));
5657
});
5758
it('Should return ConvAiInternalServerErrorException if no response field', async () => {
58-
const mockAxiosError = new Error('some other error') as AxiosError;
59+
const errorMessage = 'some other error';
60+
const mockAxiosError = new Error(errorMessage) as AxiosError;
5961

6062
const error = wrapConvAiError(mockAxiosError);
6163
expect(error).toBeInstanceOf(ConvAiInternalServerErrorException);
62-
expect(error).toEqual(new ConvAiInternalServerErrorException());
64+
expect(error).toEqual(new ConvAiInternalServerErrorException(errorMessage));
6365
});
6466
it('Should return HttpException if passed children of it', async () => {
6567
const mockAxiosError = new BadRequestException() as unknown as AxiosError;

redisinsight/api/src/modules/ai/chat/exceptions/conv-ai.error.handler.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,28 @@ export const wrapConvAiError = (error: AxiosError, message?: string): HttpExcept
1313
}
1414

1515
const { response } = error;
16+
let errorMessage = message || error?.message;
17+
18+
if (!errorMessage) {
19+
const data = response?.data as any;
20+
errorMessage = data?.message;
21+
}
1622

1723
if (response) {
1824
const errorOptions = { cause: new Error(response?.data as string) };
1925
switch (response?.status) {
2026
case 401:
21-
return new ConvAiUnauthorizedException(message, errorOptions);
27+
return new ConvAiUnauthorizedException(errorMessage, errorOptions);
2228
case 403:
23-
return new ConvAiForbiddenException(message, errorOptions);
29+
return new ConvAiForbiddenException(errorMessage, errorOptions);
2430
case 400:
25-
return new ConvAiBadRequestException(message, errorOptions);
31+
return new ConvAiBadRequestException(errorMessage, errorOptions);
2632
case 404:
27-
return new ConvAiNotFoundException(message, errorOptions);
33+
return new ConvAiNotFoundException(errorMessage, errorOptions);
2834
default:
29-
return new ConvAiInternalServerErrorException(message, errorOptions);
35+
return new ConvAiInternalServerErrorException(errorMessage, errorOptions);
3036
}
3137
}
3238

33-
return new ConvAiInternalServerErrorException(message);
39+
return new ConvAiInternalServerErrorException(errorMessage);
3440
};

redisinsight/api/src/modules/cloud/auth/cloud-auth.service.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ export class CloudAuthService {
156156
*/
157157
private async getAuthRequestInfo(query): Promise<CloudAuthRequestInfo> {
158158
if (!this.authRequests.has(query?.state)) {
159+
this.logger.log(
160+
`${query?.state ? 'Auth Request matching query state not found' : 'Query state field is empty'}`,
161+
);
159162
throw new CloudOauthUnknownAuthorizationRequestException();
160163
}
161164

@@ -175,12 +178,17 @@ export class CloudAuthService {
175178
*/
176179
private async callback(query): Promise<Function | void> {
177180
if (!this.authRequests.has(query?.state)) {
181+
this.logger.log(
182+
`${query?.state ? 'Auth Request matching query state not found' : 'Query state field is empty'}`,
183+
);
178184
throw new CloudOauthUnknownAuthorizationRequestException();
179185
}
180186

181187
const authRequest = this.authRequests.get(query.state);
182188

183189
if (query?.error) {
190+
this.logger.error(`Query has error field: query.error: ${query.error},
191+
query.error_description: ${query.error_description}`);
184192
throw CloudAuthService.getAuthorizationServerRedirectError(query, authRequest);
185193
}
186194

@@ -228,6 +236,7 @@ export class CloudAuthService {
228236
* @param from
229237
*/
230238
async handleCallback(query, from = CloudSsoFeatureStrategy.DeepLink): Promise<CloudAuthResponse> {
239+
this.logger.log(`Handling a callback with a query having ${Object.keys(query || {}).toString()} keys`);
231240
let result: CloudAuthResponse = {
232241
status: CloudAuthStatus.Succeed,
233242
message: 'Successfully authenticated',
@@ -240,7 +249,7 @@ export class CloudAuthService {
240249
callback = await this.callback(query);
241250
this.analytics.sendCloudSignInSucceeded(from, reqInfo?.action);
242251
} catch (e) {
243-
this.logger.error(`Error on ${from} cloud oauth callback`, e);
252+
this.logger.error(`Error on ${from} cloud oauth callback: ${e.message}`, e);
244253

245254
this.analytics.sendCloudSignInFailed(e, from, reqInfo?.action);
246255

@@ -251,6 +260,9 @@ export class CloudAuthService {
251260
}
252261

253262
try {
263+
if (!callback) {
264+
this.logger.log('Callback is undefined');
265+
}
254266
callback?.(result)?.catch((e: Error) => this.logger.error('Async callback failed', e));
255267
} catch (e) {
256268
this.logger.error('Callback failed', e);
@@ -278,7 +290,8 @@ export class CloudAuthService {
278290
apiSessionId: null,
279291
});
280292
} catch (e) {
281-
throw new CloudApiUnauthorizedException();
293+
this.logger.error('Unable to renew tokens', e);
294+
throw new CloudApiUnauthorizedException(e.message);
282295
}
283296
}
284297

redisinsight/api/src/modules/cloud/autodiscovery/cloud-autodiscovery.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export class CloudAutodiscoveryService {
4747
try {
4848
return await this.cloudUserCapiService.getCurrentAccount(authDto);
4949
} catch (e) {
50+
this.logger.error('Error when getting current user account', e);
5051
throw wrapHttpError(e);
5152
}
5253
}
@@ -67,6 +68,7 @@ export class CloudAutodiscoveryService {
6768
this.analytics.sendGetRECloudSubsSucceedEvent(subscriptions, type, authType);
6869
return subscriptions;
6970
} catch (e) {
71+
this.logger.error('Failed get redis cloud subscriptions', e);
7072
this.analytics.sendGetRECloudSubsFailedEvent(e, type, authType);
7173
throw wrapHttpError(e);
7274
}
@@ -117,6 +119,7 @@ export class CloudAutodiscoveryService {
117119
this.analytics.sendGetRECloudDbsSucceedEvent(result, authType);
118120
return result;
119121
} catch (e) {
122+
this.logger.error('Error when discovering cloud databases from subscription(s)', e);
120123
this.analytics.sendGetRECloudDbsFailedEvent(e, authType);
121124

122125
throw wrapHttpError(e);
@@ -181,6 +184,7 @@ export class CloudAutodiscoveryService {
181184
databaseDetails: database,
182185
};
183186
} catch (error) {
187+
this.logger.error('Adding cloud database failed with an error', error);
184188
return {
185189
...dto,
186190
status: ActionStatus.Fail,

redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export class CloudCapiKeyService {
4747
let currentAccount = CloudUserApiService.getCurrentAccount(user);
4848

4949
if (!currentAccount) {
50+
this.logger.error('Cannot get current account');
5051
throw new CloudApiBadRequestException('No active account');
5152
}
5253

@@ -87,13 +88,15 @@ export class CloudCapiKeyService {
8788

8889
this.analytics.sendCloudAccountKeyGenerated();
8990
} catch (e) {
91+
this.logger.error('Failed to create new capi key', e);
9092
this.analytics.sendCloudAccountKeyGenerationFailed(e);
9193
throw e;
9294
}
9395
}
9496

9597
// Throw an error. User action required in this case
9698
if (capiKey.valid === false) {
99+
this.logger.error('Capi key is not valid');
97100
return Promise.reject(new CloudCapiKeyUnauthorizedException(
98101
undefined,
99102
{ resourceId: capiKey.id },
@@ -114,6 +117,7 @@ export class CloudCapiKeyService {
114117

115118
this.analytics.sendCloudAccountSecretGenerated();
116119
} catch (e) {
120+
this.logger.error('Failed create capi secret');
117121
this.analytics.sendCloudAccountSecretGenerationFailed(e);
118122
throw e;
119123
}

redisinsight/api/src/modules/cloud/common/exceptions/cloud-api.error.handler.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,27 @@ export const wrapCloudApiError = (error: AxiosError, message?: string): HttpExce
1515

1616
const { response } = error;
1717

18+
let errorMessage = message || error.message;
19+
if (!errorMessage) {
20+
const data = response?.data as any;
21+
errorMessage = data?.message;
22+
}
23+
1824
if (response) {
1925
const errorOptions = { cause: new Error(response?.data as string) };
2026
switch (response?.status) {
2127
case 401:
22-
return new CloudApiUnauthorizedException(message, errorOptions);
28+
return new CloudApiUnauthorizedException(errorMessage, errorOptions);
2329
case 403:
24-
return new CloudApiForbiddenException(message, errorOptions);
30+
return new CloudApiForbiddenException(errorMessage, errorOptions);
2531
case 400:
26-
return new CloudApiBadRequestException(message, errorOptions);
32+
return new CloudApiBadRequestException(errorMessage, errorOptions);
2733
case 404:
28-
return new CloudApiNotFoundException(message, errorOptions);
34+
return new CloudApiNotFoundException(errorMessage, errorOptions);
2935
default:
30-
return new CloudApiInternalServerErrorException(message, errorOptions);
36+
return new CloudApiInternalServerErrorException(errorMessage, errorOptions);
3137
}
3238
}
3339

34-
return new CloudApiInternalServerErrorException(message);
40+
return new CloudApiInternalServerErrorException(errorMessage);
3541
};

redisinsight/api/src/modules/cloud/common/exceptions/cloud-capi.error.handler.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ export const wrapCloudCapiError = (error: AxiosError, message?: string): HttpExc
99
}
1010

1111
if (error.response?.status === 401) {
12-
return new CloudCapiUnauthorizedException(message, { cause: new Error(error.response?.data as string) });
12+
return new CloudCapiUnauthorizedException(
13+
message || error.message,
14+
{ cause: new Error(error.response?.data as string) },
15+
);
1316
}
1417

1518
return wrapCloudApiError(error, message);

redisinsight/api/src/modules/cloud/subscription/cloud-subscription.api.service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export class CloudSubscriptionApiService {
6969
details: find(regions, { regionId: plan.regionId }),
7070
}));
7171
} catch (e) {
72+
this.logger.error('Error getting subscription plans', e);
7273
throw wrapHttpError(await this.cloudCapiKeyService.handleCapiKeyUnauthorizedError(e, sessionMetadata));
7374
}
7475
});
@@ -89,6 +90,7 @@ export class CloudSubscriptionApiService {
8990

9091
return parseCloudSubscriptionsCloudRegionsApiResponse(regions);
9192
} catch (error) {
93+
this.logger.error('Error getting cloud regions', error);
9294
throw wrapHttpError(error);
9395
}
9496
}

redisinsight/api/src/modules/cloud/subscription/cloud-subscription.capi.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export class CloudSubscriptionCapiService {
6868

6969
return parseCloudSubscriptionsCapiResponse(subscriptions, type);
7070
} catch (error) {
71+
this.logger.error(`Error getting ${type} subscriptions`, error);
7172
throw wrapHttpError(error);
7273
}
7374
}
@@ -91,6 +92,7 @@ export class CloudSubscriptionCapiService {
9192

9293
return parseCloudSubscriptionCapiResponse(subscription, type);
9394
} catch (error) {
95+
this.logger.error(`Error getting ${type} subscription`, error);
9496
throw wrapHttpError(error);
9597
}
9698
}
@@ -112,6 +114,7 @@ export class CloudSubscriptionCapiService {
112114

113115
return parseCloudSubscriptionsPlansCapiResponse(plans, type);
114116
} catch (error) {
117+
this.logger.error('Error getting subscriptions plans', error);
115118
throw wrapHttpError(error);
116119
}
117120
}
@@ -137,6 +140,7 @@ export class CloudSubscriptionCapiService {
137140

138141
return parseCloudTaskCapiResponse(task);
139142
} catch (error) {
143+
this.logger.error('Error when creating free subscription task', error);
140144
throw wrapHttpError(error);
141145
}
142146
}

0 commit comments

Comments
 (0)