From 9b92564fe31990eb5d8399554991a6fc3ed6eb5f Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Wed, 23 Sep 2020 22:02:28 +0530 Subject: [PATCH 1/7] bumped sentry version modified performance monitor to use a queue internally to make synchronous logging easy added logging for api pane close / open and various different methods --- app/client/package.json | 4 +- .../components/editorComponents/Sidebar.tsx | 3 +- .../AppViewer/AppViewerPageContainer.tsx | 20 +- .../src/pages/Editor/APIEditor/index.tsx | 17 +- app/client/src/pages/Editor/Canvas.tsx | 2 +- .../Explorer/Entity/EntityProperties.tsx | 10 +- .../src/pages/Editor/PropertyPane/index.tsx | 10 +- app/client/src/pages/Editor/WidgetsEditor.tsx | 11 ++ app/client/src/pages/Editor/routes.tsx | 4 + app/client/src/sagas/ApiPaneSagas.ts | 8 +- app/client/src/selectors/dataTreeSelectors.ts | 71 ++++--- app/client/src/selectors/editorSelectors.tsx | 7 + app/client/src/utils/DynamicBindingUtils.ts | 56 +++--- app/client/src/utils/PerformanceTracker.ts | 180 ++++++++++++++++++ app/client/yarn.lock | 106 +++++------ 15 files changed, 388 insertions(+), 121 deletions(-) create mode 100644 app/client/src/utils/PerformanceTracker.ts diff --git a/app/client/package.json b/app/client/package.json index 6ad9d2f31214..9b7cd05f65d8 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -16,8 +16,8 @@ "@craco/craco": "^5.6.1", "@manaflair/redux-batch": "^1.0.0", "@optimizely/optimizely-sdk": "^4.0.0", - "@sentry/react": "^5.22.3", - "@sentry/tracing": "^5.22.3", + "@sentry/react": "^5.24.2", + "@sentry/tracing": "^5.24.2", "@sentry/webpack-plugin": "^1.12.1", "@types/chance": "^1.0.7", "@types/lodash": "^4.14.120", diff --git a/app/client/src/components/editorComponents/Sidebar.tsx b/app/client/src/components/editorComponents/Sidebar.tsx index c82d9b169593..25692ae48ae5 100644 --- a/app/client/src/components/editorComponents/Sidebar.tsx +++ b/app/client/src/components/editorComponents/Sidebar.tsx @@ -3,6 +3,7 @@ import styled from "styled-components"; import ExplorerSidebar from "pages/Editor/Explorer"; import { PanelStack, Classes } from "@blueprintjs/core"; import { Colors } from "constants/Colors"; +import * as Sentry from "@sentry/react"; const SidebarWrapper = styled.div` background-color: ${Colors.MINE_SHAFT}; @@ -32,4 +33,4 @@ export const Sidebar = memo(() => { Sidebar.displayName = "Sidebar"; -export default Sidebar; +export default Sentry.withProfiler(Sidebar); diff --git a/app/client/src/pages/AppViewer/AppViewerPageContainer.tsx b/app/client/src/pages/AppViewer/AppViewerPageContainer.tsx index 10c38b1f4db2..e68975be6030 100644 --- a/app/client/src/pages/AppViewer/AppViewerPageContainer.tsx +++ b/app/client/src/pages/AppViewer/AppViewerPageContainer.tsx @@ -17,6 +17,9 @@ import { getCurrentPageName, } from "selectors/editorSelectors"; import ConfirmRunModal from "pages/Editor/ConfirmRunModal"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; const Section = styled.section` background: ${props => props.theme.colors.bodyBG}; @@ -108,11 +111,18 @@ class AppViewerPageContainer extends Component { } } -const mapStateToProps = (state: AppState) => ({ - isFetchingPage: getIsFetchingPage(state), - widgets: getCanvasWidgetDsl(state), - currentPageName: getCurrentPageName(state), -}); +const mapStateToProps = (state: AppState) => { + PerformanceTracker.startTracking( + PerformanceTransactionName.GENERATE_VIEW_MODE_PROPS, + ); + const props = { + isFetchingPage: getIsFetchingPage(state), + widgets: getCanvasWidgetDsl(state), + currentPageName: getCurrentPageName(state), + }; + PerformanceTracker.stopTracking(); + return props; +}; const mapDispatchToProps = (dispatch: any) => ({ fetchPage: (pageId: string, bustCache = false) => diff --git a/app/client/src/pages/Editor/APIEditor/index.tsx b/app/client/src/pages/Editor/APIEditor/index.tsx index edd5c3895bc0..d8f310276ac5 100644 --- a/app/client/src/pages/Editor/APIEditor/index.tsx +++ b/app/client/src/pages/Editor/APIEditor/index.tsx @@ -29,6 +29,10 @@ import Spinner from "components/editorComponents/Spinner"; import styled from "styled-components"; import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper"; import { changeApi } from "actions/apiPaneActions"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; +import * as Sentry from "@sentry/react"; const LoadingContainer = styled(CenteredWrapper)` height: 50%; @@ -67,6 +71,7 @@ type Props = ReduxActionProps & class ApiEditor extends React.Component { componentDidMount() { + PerformanceTracker.stopTracking(PerformanceTransactionName.OPEN_API); this.props.changeAPIPage(this.props.match.params.apiId); } handleDeleteClick = () => { @@ -157,7 +162,6 @@ class ApiEditor extends React.Component { match={this.props.match} /> ); - return (
{ const apiAction = getActionById(state, props); const apiName = getApiName(state, props.match.params.apiId); const { isDeleting, isRunning, isCreating } = state.ui.apiPane; - return { + PerformanceTracker.startTracking( + PerformanceTransactionName.GENERATE_API_PROPS, + ); + const apiEditorState = { actions: state.entities.actions, currentApplication: getCurrentApplication(state), currentPageName: getCurrentPageName(state), @@ -229,6 +236,8 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => { isCreating, isEditorInitialized: getIsEditorInitialized(state), }; + PerformanceTracker.stopTracking(); + return apiEditorState; }; const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({ @@ -240,4 +249,6 @@ const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({ changeAPIPage: (actionId: string) => dispatch(changeApi(actionId)), }); -export default connect(mapStateToProps, mapDispatchToProps)(ApiEditor); +export default Sentry.withProfiler( + connect(mapStateToProps, mapDispatchToProps)(ApiEditor), +); diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index 5fba906bc266..e5362725bf4e 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -1,4 +1,4 @@ -import React, { memo } from "react"; +import React, { memo, useEffect } from "react"; import WidgetFactory from "utils/WidgetFactory"; import { RenderModes } from "constants/WidgetConstants"; import { ContainerWidgetProps } from "widgets/ContainerWidget"; diff --git a/app/client/src/pages/Editor/Explorer/Entity/EntityProperties.tsx b/app/client/src/pages/Editor/Explorer/Entity/EntityProperties.tsx index ff367c25baca..9a3adbb3645d 100644 --- a/app/client/src/pages/Editor/Explorer/Entity/EntityProperties.tsx +++ b/app/client/src/pages/Editor/Explorer/Entity/EntityProperties.tsx @@ -10,6 +10,10 @@ import { } from "entities/DataTree/dataTreeFactory"; import { useSelector } from "react-redux"; import { evaluateDataTreeWithoutFunctions } from "selectors/dataTreeSelectors"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; +import * as Sentry from "@sentry/react"; export const EntityProperties = (props: { entityType: ENTITY_TYPE; @@ -18,6 +22,9 @@ export const EntityProperties = (props: { step: number; entity?: any; }) => { + PerformanceTracker.startTracking( + PerformanceTransactionName.ENTITY_EXPLORER_ENTITY, + ); let entity: any; const dataTree: DataTree = useSelector(evaluateDataTreeWithoutFunctions); if (props.isCurrentPage && dataTree[props.entityName]) { @@ -78,6 +85,7 @@ export const EntityProperties = (props: { }); break; } + PerformanceTracker.stopTracking(); return ( <> {entityProperties.map(entityProperty => ( @@ -87,4 +95,4 @@ export const EntityProperties = (props: { ); }; -export default EntityProperties; +export default Sentry.withProfiler(EntityProperties); diff --git a/app/client/src/pages/Editor/PropertyPane/index.tsx b/app/client/src/pages/Editor/PropertyPane/index.tsx index 74a03c18653c..f4749366c0c0 100644 --- a/app/client/src/pages/Editor/PropertyPane/index.tsx +++ b/app/client/src/pages/Editor/PropertyPane/index.tsx @@ -27,6 +27,9 @@ import PropertyControl from "pages/Editor/PropertyPane/PropertyControl"; import AnalyticsUtil from "utils/AnalyticsUtil"; import * as log from "loglevel"; import PaneWrapper from "pages/common/PaneWrapper"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; const PropertySectionLabel = styled.div` color: ${props => props.theme.colors.paneSectionLabel}; @@ -224,12 +227,17 @@ class PropertyPane extends Component< } const mapStateToProps = (state: AppState): PropertyPaneProps => { - return { + PerformanceTracker.startTracking( + PerformanceTransactionName.GENERATE_PROPERTY_PANE_PROPS, + ); + const props = { propertySections: getPropertyConfig(state), widgetId: getCurrentWidgetId(state), widgetProperties: getWidgetPropsForPropertyPane(state), isVisible: getIsPropertyPaneVisible(state), }; + PerformanceTracker.stopTracking(); + return props; }; const mapDispatchToProps = (dispatch: any): PropertyPaneFunctions => { diff --git a/app/client/src/pages/Editor/WidgetsEditor.tsx b/app/client/src/pages/Editor/WidgetsEditor.tsx index b0c27a46c601..9b732363921d 100644 --- a/app/client/src/pages/Editor/WidgetsEditor.tsx +++ b/app/client/src/pages/Editor/WidgetsEditor.tsx @@ -18,6 +18,9 @@ import { getCanvasClassName } from "utils/generators"; import { flashElementById } from "utils/helpers"; import { useParams } from "react-router"; import { fetchPage } from "actions/pageActions"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; const EditorWrapper = styled.div` display: flex; @@ -46,6 +49,9 @@ const CanvasContainer = styled.section` /* eslint-disable react/display-name */ const WidgetsEditor = () => { + PerformanceTracker.startTracking( + PerformanceTransactionName.GENERATE_WIDGET_EDITOR_PROPS, + ); const { focusWidget, selectWidget } = useWidgetSelection(); const params = useParams<{ applicationId: string; pageId: string }>(); const dispatch = useDispatch(); @@ -55,6 +61,10 @@ const WidgetsEditor = () => { const currentPageId = useSelector(getCurrentPageId); const currentPageName = useSelector(getCurrentPageName); + useEffect(() => { + PerformanceTracker.stopTracking(PerformanceTransactionName.CLOSE_API); + }); + // Switch page useEffect(() => { if (currentPageId !== params.pageId && !!params.pageId) { @@ -101,6 +111,7 @@ const WidgetsEditor = () => { node = ; } log.debug("Canvas rendered"); + PerformanceTracker.stopTracking(); return ( diff --git a/app/client/src/pages/Editor/routes.tsx b/app/client/src/pages/Editor/routes.tsx index de253e8c9042..5b962bccc82c 100644 --- a/app/client/src/pages/Editor/routes.tsx +++ b/app/client/src/pages/Editor/routes.tsx @@ -28,6 +28,9 @@ import { } from "utils/hooks/dragResizeHooks"; import { closeAllModals } from "actions/widgetActions"; import { useDispatch } from "react-redux"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; const Wrapper = styled.div<{ isVisible: boolean }>` position: absolute; @@ -78,6 +81,7 @@ class EditorsRouter extends React.Component< } handleClose = (e: React.MouseEvent) => { + PerformanceTracker.startTracking(PerformanceTransactionName.CLOSE_API); e.stopPropagation(); const { applicationId, pageId } = this.props.match.params; this.setState({ diff --git a/app/client/src/sagas/ApiPaneSagas.ts b/app/client/src/sagas/ApiPaneSagas.ts index dfb8ae459969..8b14ed8cd693 100644 --- a/app/client/src/sagas/ApiPaneSagas.ts +++ b/app/client/src/sagas/ApiPaneSagas.ts @@ -49,6 +49,9 @@ import { PLUGIN_PACKAGE_DBS } from "constants/QueryEditorConstants"; import { RestAction } from "entities/Action"; import { getCurrentOrgId } from "selectors/organizationSelectors"; import log from "loglevel"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; function* syncApiParamsSaga( actionPayload: ReduxActionWithMeta, @@ -57,7 +60,7 @@ function* syncApiParamsSaga( const field = actionPayload.meta.field; const value = actionPayload.payload; const padQueryParams = { key: "", value: "" }; - + PerformanceTracker.startTracking(PerformanceTransactionName.SYNC_PARAMS_SAGA); if (field === "actionConfiguration.path") { if (value.indexOf("?") > -1) { const paramsString = value.substr(value.indexOf("?") + 1); @@ -122,6 +125,7 @@ function* syncApiParamsSaga( ), ); } + PerformanceTracker.stopTracking(); } function* initializeExtraFormDataSaga() { @@ -162,6 +166,7 @@ function* changeApiSaga(actionPayload: ReduxAction<{ id: string }>) { // // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // // @ts-ignore // document.activeElement.blur(); + PerformanceTracker.startTracking(PerformanceTransactionName.CHANGE_API_SAGA); const { id } = actionPayload.payload; const action = yield select(getAction, id); if (!action) return; @@ -187,6 +192,7 @@ function* changeApiSaga(actionPayload: ReduxAction<{ id: string }>) { id, ); } + PerformanceTracker.stopTracking(); } function* updateFormFields( diff --git a/app/client/src/selectors/dataTreeSelectors.ts b/app/client/src/selectors/dataTreeSelectors.ts index 252959c1d6fa..7b2dc945cdb6 100644 --- a/app/client/src/selectors/dataTreeSelectors.ts +++ b/app/client/src/selectors/dataTreeSelectors.ts @@ -7,39 +7,50 @@ import { getWidgets, getWidgetsMeta } from "sagas/selectors"; import * as log from "loglevel"; import "url-search-params-polyfill"; import { getPageList } from "./appViewSelectors"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; -export const getUnevaluatedDataTree = (withFunctions?: boolean) => - createSelector( - getActionsForCurrentPage, - getWidgets, - getWidgetsMeta, - getPageList, - getAppData, - (actions, widgets, widgetsMeta, pageListPayload, appData) => { - const pageList = pageListPayload || []; - return DataTreeFactory.create( - { - actions, - widgets, - widgetsMeta, - pageList, - appData, - }, - withFunctions, - ); - }, - ); +export const getUnevaluatedDataTree = createSelector( + getActionsForCurrentPage, + getWidgets, + getWidgetsMeta, + getPageList, + getAppData, + (actions, widgets, widgetsMeta, pageListPayload, appData) => { + PerformanceTracker.startTracking( + PerformanceTransactionName.CONSTRUCT_UNEVAL_TREE, + ); + const pageList = pageListPayload || []; + const unevalTree = DataTreeFactory.create( + { + actions, + widgets, + widgetsMeta, + pageList, + appData, + }, + true, + ); + PerformanceTracker.stopTracking(); + return unevalTree; + }, +); -export const evaluateDataTree = (withFunctions?: boolean) => - createSelector( - getUnevaluatedDataTree(withFunctions), - (dataTree: DataTree): DataTree => { - return getEvaluatedDataTree(dataTree); - }, - ); +export const evaluateDataTree = createSelector( + getUnevaluatedDataTree, + (dataTree: DataTree): DataTree => { + PerformanceTracker.startTracking( + PerformanceTransactionName.DATA_TREE_EVALUATION, + ); + const evalDataTree = getEvaluatedDataTree(dataTree); + PerformanceTracker.stopTracking(); + return evalDataTree; + }, +); -export const evaluateDataTreeWithFunctions = evaluateDataTree(true); -export const evaluateDataTreeWithoutFunctions = evaluateDataTree(true); +export const evaluateDataTreeWithFunctions = evaluateDataTree; +export const evaluateDataTreeWithoutFunctions = evaluateDataTree; // For autocomplete. Use actions cached responses if // there isn't a response already diff --git a/app/client/src/selectors/editorSelectors.tsx b/app/client/src/selectors/editorSelectors.tsx index 7b96dc4f9d9e..f81a924fb0b5 100644 --- a/app/client/src/selectors/editorSelectors.tsx +++ b/app/client/src/selectors/editorSelectors.tsx @@ -20,6 +20,9 @@ import { DataTreeWidget } from "entities/DataTree/dataTreeFactory"; import { getActions } from "sagas/selectors"; import * as log from "loglevel"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; const getWidgetConfigs = (state: AppState) => state.entities.widgetConfig; const getWidgetSideBar = (state: AppState) => state.ui.widgetSidebar; @@ -107,6 +110,9 @@ export const getCanvasWidgetDsl = createSelector( entities: AppState["entities"], evaluatedDataTree, ): ContainerWidgetProps => { + PerformanceTracker.startTracking( + PerformanceTransactionName.CONSTRUCT_CANVAS_DSL, + ); log.debug("Evaluating data tree to get canvas widgets"); log.debug({ evaluatedDataTree }); const widgets = { ...entities.canvasWidgets }; @@ -121,6 +127,7 @@ export const getCanvasWidgetDsl = createSelector( const denormalizedWidgets = CanvasWidgetsNormalizer.denormalize("0", { canvasWidgets: widgets, }); + PerformanceTracker.stopTracking(); return denormalizedWidgets; }, ); diff --git a/app/client/src/utils/DynamicBindingUtils.ts b/app/client/src/utils/DynamicBindingUtils.ts index b7084ecf4492..960c5429212b 100644 --- a/app/client/src/utils/DynamicBindingUtils.ts +++ b/app/client/src/utils/DynamicBindingUtils.ts @@ -21,6 +21,9 @@ import WidgetFactory from "utils/WidgetFactory"; import { AppToaster } from "components/editorComponents/ToastComponent"; import { ToastType } from "react-toastify"; import { Action } from "entities/Action"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; export const removeBindingsFromActionObject = (obj: Action) => { const string = JSON.stringify(obj); @@ -261,52 +264,56 @@ let dependencyTreeCache: any = {}; let cachedDataTreeString = ""; export function getEvaluatedDataTree(dataTree: DataTree): DataTree { - const totalStart = performance.now(); // Create Dependencies DAG - const createDepsStart = performance.now(); const dataTreeString = JSON.stringify(dataTree); // Stringify before doing a fast equals because the data tree has functions and fast equal will always treat those as changed values // Better solve will be to prune functions - if (!equal(dataTreeString, cachedDataTreeString)) { + const shouldCreateDependencyTree = !equal( + dataTreeString, + cachedDataTreeString, + ); + PerformanceTracker.startTracking( + PerformanceTransactionName.CREATE_DEPENDENCIES, + { isCacheMiss: shouldCreateDependencyTree }, + ); + if (shouldCreateDependencyTree) { cachedDataTreeString = dataTreeString; dependencyTreeCache = createDependencyTree(dataTree); } - const createDepsEnd = performance.now(); const { dependencyMap, sortedDependencies, dependencyTree, } = dependencyTreeCache; - + PerformanceTracker.stopTracking(); // Evaluate Tree - const evaluatedTreeStart = performance.now(); + PerformanceTracker.startTracking( + PerformanceTransactionName.SORTED_DEPENDENCY_EVALUATION, + { + dependencies: sortedDependencies.length, + dataTreeSize: cachedDataTreeString.length, + }, + ); const evaluatedTree = dependencySortedEvaluateDataTree( dataTree, dependencyMap, sortedDependencies, ); - const evaluatedTreeEnd = performance.now(); + PerformanceTracker.stopTracking(); // Set Loading Widgets - const loadingTreeStart = performance.now(); + PerformanceTracker.startTracking( + PerformanceTransactionName.SET_WIDGET_LOADING, + ); const treeWithLoading = setTreeLoading(evaluatedTree, dependencyTree); - const loadingTreeEnd = performance.now(); + PerformanceTracker.stopTracking(); // Validate Widgets + PerformanceTracker.startTracking( + PerformanceTransactionName.VALIDATE_DATA_TREE, + ); const validated = getValidatedTree(treeWithLoading); - - // End counting total time - const endStart = performance.now(); - - // Log time taken and count - const timeTaken = { - total: (endStart - totalStart).toFixed(2), - createDeps: (createDepsEnd - createDepsStart).toFixed(2), - evaluate: (evaluatedTreeEnd - evaluatedTreeStart).toFixed(2), - loading: (loadingTreeEnd - loadingTreeStart).toFixed(2), - }; - log.debug("data tree evaluated"); - log.debug(timeTaken); + PerformanceTracker.stopTracking(); // dataTreeCache = validated; return validated; } @@ -572,7 +579,6 @@ function evaluateDynamicProperty( if (isCacheHit && cacheObj) { return cacheObj.evaluated; } else { - log.debug("eval " + propertyPath); const dynamicResult = getDynamicValue(unEvalPropertyValue, currentTree); dynamicPropValueCache.set(propertyPath, { evaluated: dynamicResult.result, @@ -654,6 +660,7 @@ export function dependencySortedEvaluateDataTree( try { return sortedDependencies.reduce( (currentTree: DataTree, propertyPath: string) => { + // PerformanceTracker.startTracking(PerformanceTransactionName.EVALUATE_BINDING, { binding: propertyPath }, true) const entityName = propertyPath.split(".")[0]; const entity: DataTreeEntity = currentTree[entityName]; const unEvalPropertyValue = _.get(currentTree as any, propertyPath); @@ -713,10 +720,13 @@ export function dependencySortedEvaluateDataTree( widgetEntity, ); } + // PerformanceTracker.stopTracking(); return _.set(currentTree, propertyPath, parsedValue); } + // PerformanceTracker.stopTracking(); return _.set(currentTree, propertyPath, evalPropertyValue); } else { + // PerformanceTracker.stopTracking(); return _.set(currentTree, propertyPath, evalPropertyValue); } }, diff --git a/app/client/src/utils/PerformanceTracker.ts b/app/client/src/utils/PerformanceTracker.ts new file mode 100644 index 000000000000..99108515972f --- /dev/null +++ b/app/client/src/utils/PerformanceTracker.ts @@ -0,0 +1,180 @@ +import * as Sentry from "@sentry/react"; +import { Span, SpanStatus } from "@sentry/tracing"; +import _ from "lodash"; + +export enum PerformanceTransactionName { + DEPLOY_APPLICATION = "DEPLOY_APPLICATION", + RUN_ACTION = "RUN_ACTION", + PAGE_SWITCH_EDIT = "PAGE_SWITCH_EDIT", + PAGE_SWITCH_VIEW = "PAGE_SWITCH_VIEW", + CREATE_ACTION = "CREATE_ACTION", + CURL_IMPORT = "CURL_IMPORT", + EXECUTE_WIDGET_ACTION = "EXECUTE_WIDGET_ACTION", + RUN_ACTION_WAIT_FOR_SAVE = "RUN_ACTION_WAIT_FOR_SAVE", + DATA_TREE_EVALUATION = "DATA_TREE_EVALUATION", + CONSTRUCT_UNEVAL_TREE = "CONSTRUCT_UNEVAL_TREE", + CONSTRUCT_CANVAS_DSL = "CONSTRUCT_CANVAS_DSL", + CREATE_DEPENDENCIES = "CREATE_DEPENDENCIES", + SORTED_DEPENDENCY_EVALUATION = "SORTED_DEPENDENCY_EVALUATION", + SET_WIDGET_LOADING = "SET_WIDGET_LOADING", + VALIDATE_DATA_TREE = "VALIDATE_DATA_TREE", + EXECUTE_PAGE_LOAD_ACTIONS = "EXECUTE_PAGE_LOAD_ACTIONS", + SAVE_PAGE_LAYOUT = "SAVE_PAGE_LAYOUT", + SAVE_ACTION = "SAVE_ACTION", + EVALUATE_BINDING = "EVALUATE_BINDING", + GENERATE_PROPERTY_PANE_PROPS = "GENERATE_PROPERTY_PANE_PROPS", + GENERATE_VIEW_MODE_PROPS = "GENERATE_VIEW_MODE_PROPS", + GENERATE_WIDGET_EDITOR_PROPS = "GENERATE_WIDGET_EDITOR_PROPS", + ENTITY_EXPLORER_ENTITY = "ENTITY_EXPLORER_ENTITY", + CLOSE_API = "CLOSE_API", + OPEN_API = "OPEN_API", + SET_STATE = "SET_STATE", + CANVAS_MOUNT = "CANVAS_MOUNT", + GENERATE_API_PROPS = "GENERATE_API_PROPS", + CHANGE_API_SAGA = "CHANGE_API_SAGA", + SYNC_PARAMS_SAGA = "SYNC_PARAMS_SAGA", +} + +export enum PerformanceTagNames { + PAGE_ID = "pageId", + APP_ID = "appId", + APP_MODE = "appMode", + TRANSACTION_SUCCESS = "transaction.success", +} + +export interface PerfLog { + sentrySpan: Span; + skipLog?: boolean; + eventName: string; +} + +class PerformanceTracker { + private static perfLogQueue: PerfLog[] = []; + + static startTracking = ( + eventName: PerformanceTransactionName, + data?: any, + skipLog = false, + ) => { + const currentTransaction = Sentry.getCurrentHub() + .getScope() + ?.getTransaction(); + if ( + PerformanceTracker.perfLogQueue.length === 0 && + currentTransaction !== undefined && + currentTransaction.status === SpanStatus.Ok + ) { + PerformanceTracker.perfLogQueue.push({ + sentrySpan: currentTransaction, + skipLog: skipLog, + eventName: eventName, + }); + } + if (PerformanceTracker.perfLogQueue.length === 0) { + if (!skipLog) { + console.log( + PerformanceTracker.generateSpaces( + PerformanceTracker.perfLogQueue.length + 1, + ) + + eventName + + " Track Transaction ", + ); + } + const newTransaction = Sentry.startTransaction({ name: eventName }); + Sentry.getCurrentHub().configureScope(scope => + scope.setSpan(newTransaction), + ); + PerformanceTracker.perfLogQueue.push({ + sentrySpan: newTransaction, + skipLog: skipLog, + eventName: eventName, + }); + } else { + if (!skipLog) { + console.log( + PerformanceTracker.generateSpaces( + PerformanceTracker.perfLogQueue.length + 1, + ) + + eventName + + " Track Span ", + ); + } + const currentPerfLog = + PerformanceTracker.perfLogQueue[ + PerformanceTracker.perfLogQueue.length - 1 + ]; + const currentRunningSpan = currentPerfLog.sentrySpan; + const span = currentRunningSpan.startChild({ op: eventName, data: data }); + PerformanceTracker.perfLogQueue.push({ + sentrySpan: span, + skipLog: skipLog, + eventName: eventName, + }); + } + }; + + static stopTracking = ( + data?: any, + eventName?: PerformanceTransactionName, + ) => { + if (eventName) { + let index = -1; + _.forEach(PerformanceTracker.perfLogQueue, (perfLog, i) => { + if (perfLog.eventName === eventName) { + index = i; + } + if (index !== -1 && i >= index) { + const currentSpan = perfLog.sentrySpan; + currentSpan.finish(); + if (!perfLog?.skipLog) { + PerformanceTracker.printDuration( + perfLog.eventName, + PerformanceTracker.perfLogQueue.length + 1, + currentSpan.startTimestamp, + currentSpan.endTimestamp, + ); + } + } + }); + PerformanceTracker.perfLogQueue = PerformanceTracker.perfLogQueue.splice( + index, + ); + } else { + const perfLog = PerformanceTracker.perfLogQueue.pop(); + if (perfLog) { + const currentRunningSpan = perfLog?.sentrySpan; + currentRunningSpan.setData("endData", data); + currentRunningSpan.finish(); + if (!perfLog?.skipLog) { + PerformanceTracker.printDuration( + perfLog.eventName, + PerformanceTracker.perfLogQueue.length + 1, + currentRunningSpan.startTimestamp, + currentRunningSpan.endTimestamp, + ); + } + } + } + }; + + static generateSpaces(num: number) { + let str = ""; + for (let i = 0; i < num; i++) { + str += " "; + } + return str; + } + + static printDuration( + eventName: string, + level: number, + startTime: number, + endTime?: number, + ) { + const duration = ((endTime || 0) - startTime) * 1000; + const spaces = PerformanceTracker.generateSpaces(level); + console.log(spaces + eventName + " Finish Tracking in " + duration + "ms"); + } +} + +export default PerformanceTracker; diff --git a/app/client/yarn.lock b/app/client/yarn.lock index 98cd74c4c7c3..d7a65c46e3c1 100644 --- a/app/client/yarn.lock +++ b/app/client/yarn.lock @@ -2719,14 +2719,14 @@ dependencies: any-observable "^0.3.0" -"@sentry/browser@5.22.3": - version "5.22.3" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.22.3.tgz#7a64bd1cf01bf393741a3e4bf35f82aa927f5b4e" - integrity sha512-2TzE/CoBa5ZkvxJizDdi1Iz1ldmXSJpFQ1mL07PIXBjCt0Wxf+WOuFSj5IP4L40XHfJE5gU8wEvSH0VDR8nXtA== - dependencies: - "@sentry/core" "5.22.3" - "@sentry/types" "5.22.3" - "@sentry/utils" "5.22.3" +"@sentry/browser@5.24.2": + version "5.24.2" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.24.2.tgz#e2c2786dbf07699ee12f12babf0138d633abc494" + integrity sha512-P/uZC/VrLRpU7MVEJnlZK5+AkEmuHu+mns5gC91Z4gjn7GamjR/CaXVedHGw/15ZrsQiAiwoWwuxpv4Ypd/+SA== + dependencies: + "@sentry/core" "5.24.2" + "@sentry/types" "5.24.2" + "@sentry/utils" "5.24.2" tslib "^1.9.3" "@sentry/cli@^1.55.0": @@ -2740,69 +2740,69 @@ progress "^2.0.3" proxy-from-env "^1.1.0" -"@sentry/core@5.22.3": - version "5.22.3" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.22.3.tgz#030f435f2b518f282ba8bd954dac90cd70888bd7" - integrity sha512-eGL5uUarw3o4i9QUb9JoFHnhriPpWCaqeaIBB06HUpdcvhrjoowcKZj1+WPec5lFg5XusE35vez7z/FPzmJUDw== +"@sentry/core@5.24.2": + version "5.24.2" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.24.2.tgz#1724652855c0887a690c3fc6acd2519d4072b511" + integrity sha512-nuAwCGU1l9hgMinl5P/8nIQGRXDP2FI9cJnq5h1qiP/XIOvJkJz2yzBR6nTyqr4vBth0tvxQJbIpDNGd7vHJLg== dependencies: - "@sentry/hub" "5.22.3" - "@sentry/minimal" "5.22.3" - "@sentry/types" "5.22.3" - "@sentry/utils" "5.22.3" + "@sentry/hub" "5.24.2" + "@sentry/minimal" "5.24.2" + "@sentry/types" "5.24.2" + "@sentry/utils" "5.24.2" tslib "^1.9.3" -"@sentry/hub@5.22.3": - version "5.22.3" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.22.3.tgz#08309a70d2ea8d5e313d05840c1711f34f2fffe5" - integrity sha512-INo47m6N5HFEs/7GMP9cqxOIt7rmRxdERunA3H2L37owjcr77MwHVeeJ9yawRS6FMtbWXplgWTyTIWIYOuqVbw== +"@sentry/hub@5.24.2": + version "5.24.2" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.24.2.tgz#64a02fd487599945e488ae23aba4ce4df44ee79e" + integrity sha512-xmO1Ivvpb5Qr9WgekinuZZlpl9Iw7iPETUe84HQOhUrXf+2gKO+LaUYMMsYSVDwXQEmR6/tTMyOtS6iavldC6w== dependencies: - "@sentry/types" "5.22.3" - "@sentry/utils" "5.22.3" + "@sentry/types" "5.24.2" + "@sentry/utils" "5.24.2" tslib "^1.9.3" -"@sentry/minimal@5.22.3": - version "5.22.3" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.22.3.tgz#706e4029ae5494123d3875c658ba8911aa5cc440" - integrity sha512-HoINpYnVYCpNjn2XIPIlqH5o4BAITpTljXjtAftOx6Hzj+Opjg8tR8PWliyKDvkXPpc4kXK9D6TpEDw8MO0wZA== +"@sentry/minimal@5.24.2": + version "5.24.2" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.24.2.tgz#14e8b136842398a32987459f0574359b6dc57a1f" + integrity sha512-biFpux5bI3R8xiD/Zzvrk1kRE6bqPtfWXmZYAHRtaUMCAibprTKSY9Ta8QYHynOAEoJ5Akedy6HUsEkK5DoZfA== dependencies: - "@sentry/hub" "5.22.3" - "@sentry/types" "5.22.3" + "@sentry/hub" "5.24.2" + "@sentry/types" "5.24.2" tslib "^1.9.3" -"@sentry/react@^5.22.3": - version "5.22.3" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-5.22.3.tgz#ed692f9e2aff718da6cd15d2941ddda4f1d63385" - integrity sha512-Or/tLayuxpOJhIWOXiDKdaJQZ981uRS9NT0QcPvU+Si1qTElSqtH1zB94GlwhgpglkbmLPiYq6VPrG2HOiZ79Q== +"@sentry/react@^5.24.2": + version "5.24.2" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-5.24.2.tgz#781ae4274ad5c3148b8f80b613c1b0a73f763e47" + integrity sha512-iVti69qCMFztgP2E0LMx6V+3+ppKdylMJalWnwMt4LyL9idnnuiwFzMCA9g3QEvXRCTSuqEO39Dk4XYXyxi8pA== dependencies: - "@sentry/browser" "5.22.3" - "@sentry/minimal" "5.22.3" - "@sentry/types" "5.22.3" - "@sentry/utils" "5.22.3" + "@sentry/browser" "5.24.2" + "@sentry/minimal" "5.24.2" + "@sentry/types" "5.24.2" + "@sentry/utils" "5.24.2" hoist-non-react-statics "^3.3.2" tslib "^1.9.3" -"@sentry/tracing@^5.22.3": - version "5.22.3" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.22.3.tgz#9b5a376e3164c007a22e8642ec094104468cac0c" - integrity sha512-Zp59kMCk5v56ZAyErqjv/QvGOWOQ5fRltzeVQVp8unIDTk6gEFXfhwPsYHOokJe1mfkmrgPDV6xAkYgtL3KCDQ== +"@sentry/tracing@^5.24.2": + version "5.24.2" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.24.2.tgz#a36b4f9bf699c5e07e99a148360091c8e727c51f" + integrity sha512-1uDgvGGVF8lb3hRXbhNnns+8DBUKjhRKOFR5Z3RExjrDFYTDbHmoNtV73Q12Ra+Iht9HTZnIBOqYD3oSZIbJ0w== dependencies: - "@sentry/hub" "5.22.3" - "@sentry/minimal" "5.22.3" - "@sentry/types" "5.22.3" - "@sentry/utils" "5.22.3" + "@sentry/hub" "5.24.2" + "@sentry/minimal" "5.24.2" + "@sentry/types" "5.24.2" + "@sentry/utils" "5.24.2" tslib "^1.9.3" -"@sentry/types@5.22.3": - version "5.22.3" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.22.3.tgz#d1d547b30ee8bd7771fa893af74c4f3d71f0fd18" - integrity sha512-cv+VWK0YFgCVDvD1/HrrBWOWYG3MLuCUJRBTkV/Opdy7nkdNjhCAJQrEyMM9zX0sac8FKWKOHT0sykNh8KgmYw== +"@sentry/types@5.24.2": + version "5.24.2" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.24.2.tgz#e2c25d1e75d8dbec5dbbd9a309a321425b61c2ca" + integrity sha512-HcOK00R0tQG5vzrIrqQ0jC28+z76jWSgQCzXiessJ5SH/9uc6NzdO7sR7K8vqMP2+nweCHckFohC8G0T1DLzuQ== -"@sentry/utils@5.22.3": - version "5.22.3" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.22.3.tgz#e3bda3e789239eb16d436f768daa12829f33d18f" - integrity sha512-AHNryXMBvIkIE+GQxTlmhBXD0Ksh+5w1SwM5qi6AttH+1qjWLvV6WB4+4pvVvEoS8t5F+WaVUZPQLmCCWp6zKw== +"@sentry/utils@5.24.2": + version "5.24.2" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.24.2.tgz#90b7dff939bbbf4bb8edcac6aac2d04a0552af80" + integrity sha512-oPGde4tNEDHKk0Cg9q2p0qX649jLDUOwzJXHKpd0X65w3A6eJByDevMr8CSzKV9sesjrUpxqAv6f9WWlz185tA== dependencies: - "@sentry/types" "5.22.3" + "@sentry/types" "5.24.2" tslib "^1.9.3" "@sentry/webpack-plugin@^1.12.1": From c90a037f2bded41e9aa238d3d555c1c13775b863 Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Wed, 23 Sep 2020 22:20:18 +0530 Subject: [PATCH 2/7] added use effect to stop tracking on mount of entity properties --- .../src/pages/Editor/Explorer/Entity/EntityProperties.tsx | 7 ++++--- app/client/src/utils/PerformanceTracker.ts | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/client/src/pages/Editor/Explorer/Entity/EntityProperties.tsx b/app/client/src/pages/Editor/Explorer/Entity/EntityProperties.tsx index 9a3adbb3645d..cfecce838254 100644 --- a/app/client/src/pages/Editor/Explorer/Entity/EntityProperties.tsx +++ b/app/client/src/pages/Editor/Explorer/Entity/EntityProperties.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import EntityProperty, { EntityPropertyProps } from "./EntityProperty"; import { isFunction } from "lodash"; import { entityDefinitions } from "utils/autocomplete/EntityDefinitions"; @@ -25,6 +25,9 @@ export const EntityProperties = (props: { PerformanceTracker.startTracking( PerformanceTransactionName.ENTITY_EXPLORER_ENTITY, ); + useEffect(() => { + PerformanceTracker.stopTracking(); + }); let entity: any; const dataTree: DataTree = useSelector(evaluateDataTreeWithoutFunctions); if (props.isCurrentPage && dataTree[props.entityName]) { @@ -34,7 +37,6 @@ export const EntityProperties = (props: { } else { return null; } - let config: any; let entityProperties: Array = []; switch (props.entityType) { @@ -85,7 +87,6 @@ export const EntityProperties = (props: { }); break; } - PerformanceTracker.stopTracking(); return ( <> {entityProperties.map(entityProperty => ( diff --git a/app/client/src/utils/PerformanceTracker.ts b/app/client/src/utils/PerformanceTracker.ts index 99108515972f..78a82bcbc00c 100644 --- a/app/client/src/utils/PerformanceTracker.ts +++ b/app/client/src/utils/PerformanceTracker.ts @@ -1,6 +1,7 @@ import * as Sentry from "@sentry/react"; import { Span, SpanStatus } from "@sentry/tracing"; import _ from "lodash"; +import * as log from "loglevel"; export enum PerformanceTransactionName { DEPLOY_APPLICATION = "DEPLOY_APPLICATION", @@ -28,7 +29,6 @@ export enum PerformanceTransactionName { ENTITY_EXPLORER_ENTITY = "ENTITY_EXPLORER_ENTITY", CLOSE_API = "CLOSE_API", OPEN_API = "OPEN_API", - SET_STATE = "SET_STATE", CANVAS_MOUNT = "CANVAS_MOUNT", GENERATE_API_PROPS = "GENERATE_API_PROPS", CHANGE_API_SAGA = "CHANGE_API_SAGA", @@ -72,7 +72,7 @@ class PerformanceTracker { } if (PerformanceTracker.perfLogQueue.length === 0) { if (!skipLog) { - console.log( + log.debug( PerformanceTracker.generateSpaces( PerformanceTracker.perfLogQueue.length + 1, ) + @@ -91,7 +91,7 @@ class PerformanceTracker { }); } else { if (!skipLog) { - console.log( + log.debug( PerformanceTracker.generateSpaces( PerformanceTracker.perfLogQueue.length + 1, ) + @@ -173,7 +173,7 @@ class PerformanceTracker { ) { const duration = ((endTime || 0) - startTime) * 1000; const spaces = PerformanceTracker.generateSpaces(level); - console.log(spaces + eventName + " Finish Tracking in " + duration + "ms"); + log.debug(spaces + eventName + " Finish Tracking in " + duration + "ms"); } } From b9e3525315f8a4071bd2824916e64633e26ebd3d Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Wed, 23 Sep 2020 22:22:47 +0530 Subject: [PATCH 3/7] removed open api tracking --- app/client/src/pages/Editor/APIEditor/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/client/src/pages/Editor/APIEditor/index.tsx b/app/client/src/pages/Editor/APIEditor/index.tsx index d8f310276ac5..bc2cdbb7b717 100644 --- a/app/client/src/pages/Editor/APIEditor/index.tsx +++ b/app/client/src/pages/Editor/APIEditor/index.tsx @@ -71,7 +71,6 @@ type Props = ReduxActionProps & class ApiEditor extends React.Component { componentDidMount() { - PerformanceTracker.stopTracking(PerformanceTransactionName.OPEN_API); this.props.changeAPIPage(this.props.match.params.apiId); } handleDeleteClick = () => { From 7be2233505479fc4684710edcdb99a8b36859534 Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Thu, 24 Sep 2020 12:01:01 +0530 Subject: [PATCH 4/7] fixed stop tracking to pop from the end instead of the beginning added tracking for editor mount and sidebar mount --- .../components/editorComponents/Sidebar.tsx | 9 +++- app/client/src/pages/Editor/WidgetsEditor.tsx | 6 +-- app/client/src/utils/PerformanceTracker.ts | 45 +++++++++++-------- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/app/client/src/components/editorComponents/Sidebar.tsx b/app/client/src/components/editorComponents/Sidebar.tsx index 25692ae48ae5..ad8e3a9322cc 100644 --- a/app/client/src/components/editorComponents/Sidebar.tsx +++ b/app/client/src/components/editorComponents/Sidebar.tsx @@ -1,9 +1,12 @@ -import React, { memo } from "react"; +import React, { memo, useEffect } from "react"; import styled from "styled-components"; import ExplorerSidebar from "pages/Editor/Explorer"; import { PanelStack, Classes } from "@blueprintjs/core"; import { Colors } from "constants/Colors"; import * as Sentry from "@sentry/react"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; const SidebarWrapper = styled.div` background-color: ${Colors.MINE_SHAFT}; @@ -24,6 +27,10 @@ const SidebarWrapper = styled.div` const initialPanel = { component: ExplorerSidebar }; export const Sidebar = memo(() => { + PerformanceTracker.startTracking(PerformanceTransactionName.SIDE_BAR_MOUNT); + useEffect(() => { + PerformanceTracker.stopTracking(); + }); return ( diff --git a/app/client/src/pages/Editor/WidgetsEditor.tsx b/app/client/src/pages/Editor/WidgetsEditor.tsx index 9b732363921d..abd8bb85e550 100644 --- a/app/client/src/pages/Editor/WidgetsEditor.tsx +++ b/app/client/src/pages/Editor/WidgetsEditor.tsx @@ -49,9 +49,7 @@ const CanvasContainer = styled.section` /* eslint-disable react/display-name */ const WidgetsEditor = () => { - PerformanceTracker.startTracking( - PerformanceTransactionName.GENERATE_WIDGET_EDITOR_PROPS, - ); + PerformanceTracker.startTracking(PerformanceTransactionName.EDITOR_MOUNT); const { focusWidget, selectWidget } = useWidgetSelection(); const params = useParams<{ applicationId: string; pageId: string }>(); const dispatch = useDispatch(); @@ -62,6 +60,7 @@ const WidgetsEditor = () => { const currentPageName = useSelector(getCurrentPageName); useEffect(() => { + PerformanceTracker.stopTracking(PerformanceTransactionName.EDITOR_MOUNT); PerformanceTracker.stopTracking(PerformanceTransactionName.CLOSE_API); }); @@ -111,7 +110,6 @@ const WidgetsEditor = () => { node = ; } log.debug("Canvas rendered"); - PerformanceTracker.stopTracking(); return ( diff --git a/app/client/src/utils/PerformanceTracker.ts b/app/client/src/utils/PerformanceTracker.ts index 78a82bcbc00c..55cea9040fca 100644 --- a/app/client/src/utils/PerformanceTracker.ts +++ b/app/client/src/utils/PerformanceTracker.ts @@ -29,6 +29,8 @@ export enum PerformanceTransactionName { ENTITY_EXPLORER_ENTITY = "ENTITY_EXPLORER_ENTITY", CLOSE_API = "CLOSE_API", OPEN_API = "OPEN_API", + EDITOR_MOUNT = "EDITOR_MOUNT", + SIDE_BAR_MOUNT = "SIDE_BAR_MOUNT", CANVAS_MOUNT = "CANVAS_MOUNT", GENERATE_API_PROPS = "GENERATE_API_PROPS", CHANGE_API_SAGA = "CHANGE_API_SAGA", @@ -118,27 +120,32 @@ class PerformanceTracker { eventName?: PerformanceTransactionName, ) => { if (eventName) { - let index = -1; - _.forEach(PerformanceTracker.perfLogQueue, (perfLog, i) => { - if (perfLog.eventName === eventName) { - index = i; - } - if (index !== -1 && i >= index) { - const currentSpan = perfLog.sentrySpan; - currentSpan.finish(); - if (!perfLog?.skipLog) { - PerformanceTracker.printDuration( - perfLog.eventName, - PerformanceTracker.perfLogQueue.length + 1, - currentSpan.startTimestamp, - currentSpan.endTimestamp, - ); + const index = _.findLastIndex( + PerformanceTracker.perfLogQueue, + (perfLog, i) => { + return perfLog.eventName === eventName; + }, + ); + if (index !== -1) { + for (let i = PerformanceTracker.perfLogQueue.length - 1; i >= 0; i--) { + const perfLog = PerformanceTracker.perfLogQueue[i]; + if (i >= index) { + const currentSpan = perfLog.sentrySpan; + currentSpan.finish(); + if (!perfLog?.skipLog) { + PerformanceTracker.printDuration( + perfLog.eventName, + i + 1, + currentSpan.startTimestamp, + currentSpan.endTimestamp, + ); + } } } - }); - PerformanceTracker.perfLogQueue = PerformanceTracker.perfLogQueue.splice( - index, - ); + PerformanceTracker.perfLogQueue = PerformanceTracker.perfLogQueue.splice( + index, + ); + } } else { const perfLog = PerformanceTracker.perfLogQueue.pop(); if (perfLog) { From 09853ce634090b9f6aa3820053aea0a279e5dc7d Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Thu, 24 Sep 2020 12:13:14 +0530 Subject: [PATCH 5/7] added tracking for entity explorer --- app/client/src/pages/Editor/Explorer/index.tsx | 10 ++++++++-- app/client/src/utils/PerformanceTracker.ts | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/client/src/pages/Editor/Explorer/index.tsx b/app/client/src/pages/Editor/Explorer/index.tsx index 38299d667e8f..2c24b53bb773 100644 --- a/app/client/src/pages/Editor/Explorer/index.tsx +++ b/app/client/src/pages/Editor/Explorer/index.tsx @@ -1,4 +1,4 @@ -import React, { useRef, MutableRefObject, useCallback } from "react"; +import React, { useRef, MutableRefObject, useCallback, useEffect } from "react"; import styled from "styled-components"; import Divider from "components/editorComponents/Divider"; import { @@ -18,6 +18,9 @@ import history from "utils/history"; import { useParams } from "react-router"; import { ExplorerURLParams } from "./helpers"; import JSDependencies from "./JSDependencies"; +import PerformanceTracker, { + PerformanceTransactionName, +} from "utils/PerformanceTracker"; const Wrapper = styled.div` height: 100%; @@ -40,7 +43,10 @@ const EntityExplorer = (props: IPanelProps) => { const searchInputRef: MutableRefObject = useRef( null, ); - + PerformanceTracker.startTracking(PerformanceTransactionName.ENTITY_EXPLORER); + useEffect(() => { + PerformanceTracker.stopTracking(); + }); const explorerRef = useRef(null); const { searchKeyword, clearSearch } = useFilteredEntities(searchInputRef); const datasources = useFilteredDatasources(searchKeyword); diff --git a/app/client/src/utils/PerformanceTracker.ts b/app/client/src/utils/PerformanceTracker.ts index 55cea9040fca..79c9e53c3746 100644 --- a/app/client/src/utils/PerformanceTracker.ts +++ b/app/client/src/utils/PerformanceTracker.ts @@ -27,6 +27,7 @@ export enum PerformanceTransactionName { GENERATE_VIEW_MODE_PROPS = "GENERATE_VIEW_MODE_PROPS", GENERATE_WIDGET_EDITOR_PROPS = "GENERATE_WIDGET_EDITOR_PROPS", ENTITY_EXPLORER_ENTITY = "ENTITY_EXPLORER_ENTITY", + ENTITY_EXPLORER = "ENTITY_EXPLORER", CLOSE_API = "CLOSE_API", OPEN_API = "OPEN_API", EDITOR_MOUNT = "EDITOR_MOUNT", From f89309f4ba5adb93c8be28f8ff961074003cac89 Mon Sep 17 00:00:00 2001 From: Nikhil Nandagopal Date: Thu, 24 Sep 2020 16:33:06 +0530 Subject: [PATCH 6/7] moved from app route to sentry app route because passing JSX to app route causes re-renders --- app/client/src/AppRouter.tsx | 77 ++++++++++--------- app/client/src/pages/AppViewer/index.tsx | 8 +- app/client/src/pages/Editor/Canvas.tsx | 2 +- app/client/src/pages/Editor/MainContainer.tsx | 15 ++-- app/client/src/pages/Editor/routes.tsx | 42 +++++----- app/client/src/pages/UserAuth/index.tsx | 28 +++---- app/client/src/pages/common/AppRoute.tsx | 33 ++++---- app/client/src/pages/organization/index.tsx | 14 ++-- .../src/pages/organization/settings.tsx | 17 ++-- 9 files changed, 106 insertions(+), 130 deletions(-) diff --git a/app/client/src/AppRouter.tsx b/app/client/src/AppRouter.tsx index d31948a59ade..436de1b9ccaa 100644 --- a/app/client/src/AppRouter.tsx +++ b/app/client/src/AppRouter.tsx @@ -1,8 +1,7 @@ import React, { Suspense } from "react"; import history from "utils/history"; import AppHeader from "pages/common/AppHeader"; -import { Redirect, Router, Switch } from "react-router-dom"; -import AppRoute from "pages/common/AppRoute"; +import { Redirect, Route, Router, Switch } from "react-router-dom"; import { APP_VIEW_URL, APPLICATIONS_URL, @@ -28,70 +27,72 @@ import Users from "pages/users"; import PageNotFound from "pages/common/PageNotFound"; import PageLoadingBar from "pages/common/PageLoadingBar"; import ServerUnavailable from "pages/common/ServerUnavailable"; +import { getThemeDetails } from "selectors/themeSelectors"; +import { ThemeMode } from "reducers/uiReducers/themeReducer"; +import { AppState } from "reducers"; +import { setThemeMode } from "actions/themeActions"; +import { connect } from "react-redux"; + +import * as Sentry from "@sentry/react"; +const SentryRoute = Sentry.withSentryRouting(Route); const loadingIndicator = ; class AppRouter extends React.Component { render() { + const { currentTheme } = this.props; + if ( + window.location.pathname === "/applications" || + window.location.pathname.indexOf("/settings/") !== -1 + ) { + document.body.style.backgroundColor = + currentTheme.colors.homepageBackground; + } else { + document.body.style.backgroundColor = currentTheme.colors.appBackground; + } + return ( - + - - - - + + + - - - + + - - + ); } } +const mapStateToProps = (state: AppState) => ({ + currentTheme: getThemeDetails(state).theme, +}); +const mapDispatchToProps = (dispatch: any) => ({ + setTheme: (mode: ThemeMode) => { + dispatch(setThemeMode(mode)); + }, +}); -export default AppRouter; +export default connect(mapStateToProps, mapDispatchToProps)(AppRouter); diff --git a/app/client/src/pages/AppViewer/index.tsx b/app/client/src/pages/AppViewer/index.tsx index 5134c091bd66..1e27718a2a32 100644 --- a/app/client/src/pages/AppViewer/index.tsx +++ b/app/client/src/pages/AppViewer/index.tsx @@ -1,7 +1,7 @@ import React, { Component } from "react"; import styled from "styled-components"; import { connect } from "react-redux"; -import { withRouter, RouteComponentProps } from "react-router"; +import { withRouter, RouteComponentProps, Route } from "react-router"; import { Switch } from "react-router-dom"; import { AppState } from "reducers"; import { @@ -21,9 +21,9 @@ import { resetChildrenMetaProperty, updateWidgetMetaProperty, } from "actions/metaActions"; -import AppRoute from "pages/common/AppRoute"; import { editorInitializer } from "utils/EditorUtils"; import * as Sentry from "@sentry/react"; +const SentryRoute = Sentry.withSentryRouting(Route); const AppViewerBody = styled.section` display: flex; @@ -84,12 +84,10 @@ class AppViewer extends Component< {isInitialized && this.state.registered && ( - )} diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index e5362725bf4e..5fba906bc266 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -1,4 +1,4 @@ -import React, { memo, useEffect } from "react"; +import React, { memo } from "react"; import WidgetFactory from "utils/WidgetFactory"; import { RenderModes } from "constants/WidgetConstants"; import { ContainerWidgetProps } from "widgets/ContainerWidget"; diff --git a/app/client/src/pages/Editor/MainContainer.tsx b/app/client/src/pages/Editor/MainContainer.tsx index 93e09a0429ba..890fc72248a7 100644 --- a/app/client/src/pages/Editor/MainContainer.tsx +++ b/app/client/src/pages/Editor/MainContainer.tsx @@ -3,10 +3,12 @@ import EditorsRouter from "./routes"; import WidgetsEditor from "./WidgetsEditor"; import styled from "styled-components"; import Sidebar from "components/editorComponents/Sidebar"; -import { Switch } from "react-router"; -import AppRoute from "../common/AppRoute"; +import { Route, Switch } from "react-router"; import { BUILDER_URL } from "constants/routes"; +import * as Sentry from "@sentry/react"; +const SentryRoute = Sentry.withSentryRouting(Route); + const Container = styled.div` display: flex; height: calc(100vh - ${props => props.theme.headerHeight}); @@ -23,13 +25,8 @@ const MainContainer = () => { - - + + diff --git a/app/client/src/pages/Editor/routes.tsx b/app/client/src/pages/Editor/routes.tsx index 5b962bccc82c..e11560552de9 100644 --- a/app/client/src/pages/Editor/routes.tsx +++ b/app/client/src/pages/Editor/routes.tsx @@ -1,5 +1,10 @@ import React, { useEffect, ReactNode } from "react"; -import { Switch, withRouter, RouteComponentProps } from "react-router-dom"; +import { + Switch, + withRouter, + RouteComponentProps, + Route, +} from "react-router-dom"; import ApiEditor from "./APIEditor"; import QueryEditor from "./QueryEditor"; import DataSourceEditor from "./DataSourceEditor"; @@ -21,7 +26,6 @@ import { getProviderTemplatesURL, } from "constants/routes"; import styled from "styled-components"; -import AppRoute from "pages/common/AppRoute"; import { useShowPropertyPane, useWidgetSelection, @@ -32,6 +36,9 @@ import PerformanceTracker, { PerformanceTransactionName, } from "utils/PerformanceTracker"; +import * as Sentry from "@sentry/react"; +const SentryRoute = Sentry.withSentryRouting(Route); + const Wrapper = styled.div<{ isVisible: boolean }>` position: absolute; top: 0; @@ -102,60 +109,47 @@ class EditorsRouter extends React.Component< onClick={this.preventClose} > - - + - - - - - - - diff --git a/app/client/src/pages/UserAuth/index.tsx b/app/client/src/pages/UserAuth/index.tsx index 27deeb86a31f..80633c5248a0 100644 --- a/app/client/src/pages/UserAuth/index.tsx +++ b/app/client/src/pages/UserAuth/index.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Switch, useRouteMatch, useLocation } from "react-router-dom"; +import { Switch, useRouteMatch, useLocation, Route } from "react-router-dom"; import Login from "./Login"; import Centered from "components/designSystems/appsmith/CenteredWrapper"; import { animated, useTransition } from "react-spring"; @@ -7,8 +7,10 @@ import { AuthContainer, AuthCard } from "./StyledComponents"; import SignUp from "./SignUp"; import ForgotPassword from "./ForgotPassword"; import ResetPassword from "./ResetPassword"; -import AppRoute from "pages/common/AppRoute"; import PageNotFound from "pages/common/PageNotFound"; +import * as Sentry from "@sentry/react"; +const SentryRoute = Sentry.withSentryRouting(Route); + const AnimatedAuthCard = animated(AuthContainer); export const UserAuth = () => { const { path } = useRouteMatch(); @@ -25,31 +27,19 @@ export const UserAuth = () => { - - - + + - - + diff --git a/app/client/src/pages/common/AppRoute.tsx b/app/client/src/pages/common/AppRoute.tsx index 4bef0352d79d..3ce4dbaecb43 100644 --- a/app/client/src/pages/common/AppRoute.tsx +++ b/app/client/src/pages/common/AppRoute.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Route } from "react-router-dom"; +import { Route, RouteComponentProps } from "react-router-dom"; import AnalyticsUtil from "utils/AnalyticsUtil"; import * as Sentry from "@sentry/react"; import { connect } from "react-redux"; @@ -7,29 +7,29 @@ import { getThemeDetails } from "selectors/themeSelectors"; import { AppState } from "reducers"; import { ThemeMode } from "reducers/uiReducers/themeReducer"; import { setThemeMode } from "actions/themeActions"; +import equal from "fast-deep-equal/es6"; const SentryRoute = Sentry.withSentryRouting(Route); -class AppRouteWithoutProps extends React.Component<{ +interface AppRouteProps { currentTheme: any; path?: string; - component: React.ReactType; + component: + | React.ComponentType> + | React.ComponentType; exact?: boolean; logDisable?: boolean; name: string; location?: any; setTheme: Function; -}> { - componentDidUpdate() { - if (!this.props.logDisable) { - AnalyticsUtil.logEvent("NAVIGATE_EDITOR", { - page: this.props.name, - path: this.props.location.pathname, - }); - } +} + +class AppRouteWithoutProps extends React.Component { + shouldComponentUpdate(prevProps: AppRouteProps, nextProps: AppRouteProps) { + return !equal(prevProps?.location, nextProps?.location); } + render() { const { component: Component, currentTheme, ...rest } = this.props; - if ( window.location.pathname === "/applications" || window.location.pathname.indexOf("/settings/") !== -1 @@ -39,14 +39,7 @@ class AppRouteWithoutProps extends React.Component<{ } else { document.body.style.backgroundColor = currentTheme.colors.appBackground; } - return ( - { - return ; - }} - /> - ); + return ; } } const mapStateToProps = (state: AppState) => ({ diff --git a/app/client/src/pages/organization/index.tsx b/app/client/src/pages/organization/index.tsx index 282a054dea4d..7b731c400933 100644 --- a/app/client/src/pages/organization/index.tsx +++ b/app/client/src/pages/organization/index.tsx @@ -1,21 +1,19 @@ import React from "react"; -import { Switch, useRouteMatch, useLocation } from "react-router-dom"; +import { Switch, useRouteMatch, useLocation, Route } from "react-router-dom"; import PageWrapper from "pages/common/PageWrapper"; import DefaultOrgPage from "./defaultOrgPage"; -import AppRoute from "pages/common/AppRoute"; import Settings from "./settings"; +import * as Sentry from "@sentry/react"; +const SentryRoute = Sentry.withSentryRouting(Route); + export const Organization = () => { const { path } = useRouteMatch(); const location = useLocation(); return ( - - + + ); diff --git a/app/client/src/pages/organization/settings.tsx b/app/client/src/pages/organization/settings.tsx index dac4ffb5ce82..3dfee288ad13 100644 --- a/app/client/src/pages/organization/settings.tsx +++ b/app/client/src/pages/organization/settings.tsx @@ -1,6 +1,11 @@ import React, { useEffect } from "react"; -import { useRouteMatch, useLocation, useParams, Link } from "react-router-dom"; -import AppRoute from "pages/common/AppRoute"; +import { + useRouteMatch, + useLocation, + useParams, + Link, + Route, +} from "react-router-dom"; import { getCurrentOrg } from "selectors/organizationSelectors"; import { useSelector, useDispatch } from "react-redux"; import { TabComponent, TabProp } from "components/ads/Tabs"; @@ -12,6 +17,8 @@ import MemberSettings from "./Members"; import IconComponent from "components/designSystems/appsmith/IconComponent"; import { fetchOrg } from "actions/orgActions"; import { GeneralSettings } from "./General"; +import * as Sentry from "@sentry/react"; +const SentryRoute = Sentry.withSentryRouting(Route); const LinkToApplications = styled(Link)` margin-top: 30px; @@ -41,17 +48,15 @@ export default function Settings() { const SettingsRenderer = (
- -
); From 95db5942ef91e8f8c3cacd875763be8ca7d6ccd3 Mon Sep 17 00:00:00 2001 From: Satbir Singh Date: Thu, 24 Sep 2020 17:03:08 +0530 Subject: [PATCH 7/7] Fixing theme and route change issues. --- app/client/src/AppRouter.tsx | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/app/client/src/AppRouter.tsx b/app/client/src/AppRouter.tsx index 436de1b9ccaa..d539b60e35b0 100644 --- a/app/client/src/AppRouter.tsx +++ b/app/client/src/AppRouter.tsx @@ -38,18 +38,27 @@ const SentryRoute = Sentry.withSentryRouting(Route); const loadingIndicator = ; +function changeAppBackground(currentTheme: any) { + if ( + window.location.pathname === "/applications" || + window.location.pathname.indexOf("/settings/") !== -1 + ) { + document.body.style.backgroundColor = + currentTheme.colors.homepageBackground; + } else { + document.body.style.backgroundColor = currentTheme.colors.appBackground; + } +} + class AppRouter extends React.Component { render() { const { currentTheme } = this.props; - if ( - window.location.pathname === "/applications" || - window.location.pathname.indexOf("/settings/") !== -1 - ) { - document.body.style.backgroundColor = - currentTheme.colors.homepageBackground; - } else { - document.body.style.backgroundColor = currentTheme.colors.appBackground; - } + // This is needed for the theme switch. + changeAppBackground(currentTheme); + // This is needed for the route switch. + history.listen(() => { + changeAppBackground(currentTheme); + }); return (