From 1f7f742f3ac4fe092c5ee4ec2d5fdde4936018c7 Mon Sep 17 00:00:00 2001 From: Manish Prajapati <129747412+manishprajapati52@users.noreply.github.com> Date: Wed, 11 Sep 2024 18:23:54 +0530 Subject: [PATCH] ID:FPCO-29696;DONE:100;HOURS:4; Add uncaughtException handler (#299) * ID:FPCO-29696;DONE:100;HOURS:4; Add uncaughtException handler * ID:FPCO-29696;DONE:100;HOURS:4; Add more info in sentry * ID:FPCO-29696;DONE:100;HOURS:4; Add needed details in sentry * ID: FPCO-41454; Update --host readme description * Remove replicated example --------- Co-authored-by: vivek prajapati <35590295+vivek8690@users.noreply.github.com> --- src/fdk.ts | 37 +++++++++++++++++++++++++++++- src/helper/serve.utils.ts | 10 +++++++- src/lib/api/helper/interceptors.ts | 2 +- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/fdk.ts b/src/fdk.ts index 94fb5f43..e0698c34 100644 --- a/src/fdk.ts +++ b/src/fdk.ts @@ -42,6 +42,38 @@ async function checkTokenExpired(auth_token) { } } +const extraSentryDetails = () => { + const auth_token = configStore.get(CONFIG_KEYS.AUTH_TOKEN); + const organization = configStore.get(CONFIG_KEYS.ORGANIZATION); + const user = {}; + if (auth_token?.current_user) { + const activeEmail = auth_token.current_user?.emails?.find?.((e) => e.active && e.primary)?.email ?? 'Not primary email set'; + const name = `${auth_token.current_user?.first_name} ${auth_token.current_user?.last_name}`; + user['name'] = name; + user['email'] = activeEmail; + } + return { + command: `fdk ${process?.argv?.slice?.(2)?.join(" ")}`, + env: configStore.get(CONFIG_KEYS.CURRENT_ENV_VALUE), + user, + organization, + } +} + +// catch unhandled error +process.on('uncaughtException', (err: any) => { + Logger.error(err); + Debug(err.stack); + if(err.code == 403 || err.code == 401){ + // if user is not authenticated, we won't send sentry + } else{ + Sentry?.captureException?.(err, { + extra: extraSentryDetails() + }); + } + process.exit(1); +}); + // asyncAction is a wrapper for all commands/actions to be executed after commander is done // parsing the command input export type Action = (...args: any[]) => void; @@ -201,7 +233,10 @@ Command.prototype.asyncAction = async function (asyncFn: Action) { Logger.error(message); } else { // on report call sentry capture exception - Sentry.captureException(err); + Sentry.captureException(err, { + // add extra details in sentry + extra: extraSentryDetails() + }); Logger.error(err); } let parent = args[1].parent; diff --git a/src/helper/serve.utils.ts b/src/helper/serve.utils.ts index f4d0d3d0..d9883fab 100644 --- a/src/helper/serve.utils.ts +++ b/src/helper/serve.utils.ts @@ -1,6 +1,6 @@ import path from 'path'; import fs from 'fs'; -import Logger from '../lib/Logger'; +import Logger, { COMMON_LOG_MESSAGES } from '../lib/Logger'; import axios from 'axios'; import * as cheerio from 'cheerio'; import express from 'express'; @@ -23,6 +23,7 @@ import webpackDevMiddleware from 'webpack-dev-middleware'; import webpackHotMiddleware from 'webpack-hot-middleware'; import webpack from 'webpack'; import createBaseWebpackConfig from '../helper/theme.react.config'; +import CommandError from '../lib/CommandError'; import Debug from '../lib/Debug'; import { SupportedFrameworks } from '../lib/ExtensionSection'; import https from 'https'; @@ -215,6 +216,13 @@ export async function startServer({ domain, host, isSSR, port }) { '/.fdk/distServed/themeBundle.common.js', ); const User = Configstore.get(CONFIG_KEYS.AUTH_TOKEN); + // If AUTH_TOKEN not available then this command won't execute + // but sometime it may happen that development is going on and auth token gets expired + // in that case API will give 401 error and AUTH_TOKEN from config will be removed + // if before code exits, if any request comes here then we need to check if it is exist or not + if(!User){ + throw new CommandError(COMMON_LOG_MESSAGES.RequireAuth, "401"); + } themeUrl = ( await UploadService.uploadFile( BUNDLE_PATH, diff --git a/src/lib/api/helper/interceptors.ts b/src/lib/api/helper/interceptors.ts index 1d9a24cc..d248159c 100644 --- a/src/lib/api/helper/interceptors.ts +++ b/src/lib/api/helper/interceptors.ts @@ -129,7 +129,7 @@ export function responseErrorInterceptor() { (error.response.status === 401 || error.response.status === 403) ) { ConfigStore.delete(CONFIG_KEYS.AUTH_TOKEN); - throw new CommandError(COMMON_LOG_MESSAGES.RequireAuth); + throw new CommandError(COMMON_LOG_MESSAGES.RequireAuth, error.response.status); } else if (error.response) { Debug(`Error Response : ${JSON.stringify(error.response.data)}`); throw new CommandError(