From 45276c9e56cb85c36ee29fb761ba5cab282fdb79 Mon Sep 17 00:00:00 2001 From: akash-codemonk <67054171+akash-codemonk@users.noreply.github.com> Date: Thu, 8 Jul 2021 11:01:08 +0530 Subject: [PATCH] Analytics for debugger errors (#5660) --- app/client/src/actions/debuggerActions.ts | 20 +++- .../src/constants/ReduxActionConstants.tsx | 1 + app/client/src/sagas/DebuggerSagas.ts | 93 ++++++++++++++++++- app/client/src/sagas/EvaluationsSaga.ts | 26 ++++++ app/client/src/utils/AnalyticsUtil.tsx | 5 +- 5 files changed, 139 insertions(+), 6 deletions(-) diff --git a/app/client/src/actions/debuggerActions.ts b/app/client/src/actions/debuggerActions.ts index a0ca54e4a7..ce7beb04cd 100644 --- a/app/client/src/actions/debuggerActions.ts +++ b/app/client/src/actions/debuggerActions.ts @@ -1,5 +1,15 @@ import { ReduxActionTypes } from "constants/ReduxActionConstants"; -import { Message } from "entities/AppsmithConsole"; +import { Message, ENTITY_TYPE } from "entities/AppsmithConsole"; +import { EventName } from "utils/AnalyticsUtil"; + +export interface LogDebuggerErrorAnalyticsPayload { + entityName: string; + entityId: string; + entityType: ENTITY_TYPE; + eventName: EventName; + propertyPath: string; + errorMessages: { message: string }[]; +} export const debuggerLogInit = (payload: Message) => ({ type: ReduxActionTypes.DEBUGGER_LOG_INIT, @@ -29,3 +39,11 @@ export const updateErrorLog = (payload: Message) => ({ type: ReduxActionTypes.DEBUGGER_UPDATE_ERROR_LOG, payload, }); + +// Only used for analytics +export const logDebuggerErrorAnalytics = ( + payload: LogDebuggerErrorAnalyticsPayload, +) => ({ + type: ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS, + payload, +}); diff --git a/app/client/src/constants/ReduxActionConstants.tsx b/app/client/src/constants/ReduxActionConstants.tsx index 01909c1dee..15f548bd99 100644 --- a/app/client/src/constants/ReduxActionConstants.tsx +++ b/app/client/src/constants/ReduxActionConstants.tsx @@ -118,6 +118,7 @@ export const ReduxActionTypes: { [key: string]: string } = { DEBUGGER_ERROR_LOG: "DEBUGGER_ERROR_LOG", DEBUGGER_UPDATE_ERROR_LOG: "DEBUGGER_UPDATE_ERROR_LOG", DEBUGGER_UPDATE_ERROR_LOGS: "DEBUGGER_UPDATE_ERROR_LOGS", + DEBUGGER_ERROR_ANALYTICS: "DEBUGGER_ERROR_ANALYTICS", CLEAR_DEBUGGER_LOGS: "CLEAR_DEBUGGER_LOGS", SHOW_DEBUGGER: "SHOW_DEBUGGER", SET_THEME: "SET_THEME", diff --git a/app/client/src/sagas/DebuggerSagas.ts b/app/client/src/sagas/DebuggerSagas.ts index 6e77e3ff6b..121d6579b1 100644 --- a/app/client/src/sagas/DebuggerSagas.ts +++ b/app/client/src/sagas/DebuggerSagas.ts @@ -1,4 +1,10 @@ -import { debuggerLog, errorLog, updateErrorLog } from "actions/debuggerActions"; +import { + debuggerLog, + errorLog, + logDebuggerErrorAnalytics, + LogDebuggerErrorAnalyticsPayload, + updateErrorLog, +} from "actions/debuggerActions"; import { ReduxAction, ReduxActionTypes } from "constants/ReduxActionConstants"; import { ENTITY_TYPE, @@ -16,7 +22,7 @@ import { } from "redux-saga/effects"; import { get, set } from "lodash"; import { getDebuggerErrors } from "selectors/debuggerSelectors"; -import { getAction } from "selectors/entitiesSelector"; +import { getAction, getPlugin } from "selectors/entitiesSelector"; import { Action, PluginType } from "entities/Action"; import LOG_TYPE from "entities/AppsmithConsole/logtype"; import { DataTree } from "entities/DataTree/dataTreeFactory"; @@ -35,6 +41,11 @@ import { createMessage, WIDGET_PROPERTIES_UPDATED, } from "constants/messages"; +import AnalyticsUtil from "utils/AnalyticsUtil"; +import { Plugin } from "api/PluginApi"; +import { getCurrentPageId } from "selectors/editorSelectors"; +import { getWidget } from "./selectors"; +import { WidgetProps } from "widgets/BaseWidget"; function* formatActionRequestSaga(payload: LogActionPayload, request?: any) { if (!payload.source || !payload.state || !request || !request.headers) { @@ -141,6 +152,9 @@ function* logDependentEntityProperties(payload: Message) { function* debuggerLogSaga(action: ReduxAction) { const { payload } = action; + const debuggerErrors: Record = yield select( + getDebuggerErrors, + ); switch (payload.logType) { case LOG_TYPE.WIDGET_UPDATE: @@ -166,6 +180,19 @@ function* debuggerLogSaga(action: ReduxAction) { const res = yield call(formatActionRequestSaga, payload, payload.state); const log = { ...payload }; res && set(log, "state.headers", res); + if (!((payload.source?.id as string) in debuggerErrors)) { + yield put( + logDebuggerErrorAnalytics({ + eventName: "DEBUGGER_NEW_ERROR", + errorMessages: payload.messages ?? [], + entityType: ENTITY_TYPE.ACTION, + entityId: payload.source?.id ?? "", + entityName: payload.source?.name ?? "", + propertyPath: "", + }), + ); + } + yield put(errorLog(log)); yield put(debuggerLog(log)); } @@ -178,6 +205,19 @@ function* debuggerLogSaga(action: ReduxAction) { payload.state?.request ?? {}, ); + if ((payload.source?.id as string) in debuggerErrors) { + yield put( + logDebuggerErrorAnalytics({ + eventName: "DEBUGGER_RESOLVED_ERROR", + errorMessages: + debuggerErrors[payload.source?.id ?? ""].messages ?? [], + entityType: ENTITY_TYPE.ACTION, + entityId: payload.source?.id ?? "", + entityName: payload.source?.name ?? "", + propertyPath: "", + }), + ); + } yield put( updateErrorLog({ ...payload, @@ -198,6 +238,51 @@ function* debuggerLogSaga(action: ReduxAction) { } } -export default function* debuggerSagasListeners() { - yield all([takeEvery(ReduxActionTypes.DEBUGGER_LOG_INIT, debuggerLogSaga)]); +// This saga is intended for analytics only +function* logDebuggerErrorAnalyticsSaga( + action: ReduxAction, +) { + const { payload } = action; + const currentPageId = yield select(getCurrentPageId); + + if (payload.entityType === ENTITY_TYPE.WIDGET) { + const widget: WidgetProps = yield select(getWidget, payload.entityId); + const widgetType = widget.type; + const propertyPath = `${widgetType}.${payload.propertyPath}`; + + // Sending widget type for widgets + AnalyticsUtil.logEvent(payload.eventName, { + entityType: widgetType, + propertyPath, + errorMessages: payload.errorMessages, + pageId: currentPageId, + }); + } else if (payload.entityType === ENTITY_TYPE.ACTION) { + const action: Action = yield select(getAction, payload.entityId); + const plugin: Plugin = yield select(getPlugin, action.pluginId); + const pluginName = plugin.name.replace(/ /g, ""); + let propertyPath = `${pluginName}`; + + if (payload.propertyPath) { + propertyPath += `.${payload.propertyPath}`; + } + + // Sending plugin name for actions + AnalyticsUtil.logEvent(payload.eventName, { + entityType: pluginName, + propertyPath, + errorMessages: payload.errorMessages, + pageId: currentPageId, + }); + } +} + +export default function* debuggerSagasListeners() { + yield all([ + takeEvery(ReduxActionTypes.DEBUGGER_LOG_INIT, debuggerLogSaga), + takeEvery( + ReduxActionTypes.DEBUGGER_ERROR_ANALYTICS, + logDebuggerErrorAnalyticsSaga, + ), + ]); } diff --git a/app/client/src/sagas/EvaluationsSaga.ts b/app/client/src/sagas/EvaluationsSaga.ts index d61b9270d8..2cb67fe053 100644 --- a/app/client/src/sagas/EvaluationsSaga.ts +++ b/app/client/src/sagas/EvaluationsSaga.ts @@ -57,6 +57,8 @@ import { } from "constants/messages"; import { getAppMode } from "selectors/applicationSelectors"; import { APP_MODE } from "reducers/entityReducers/appReducer"; +import store from "store"; +import { logDebuggerErrorAnalytics } from "actions/debuggerActions"; let widgetTypeConfigMap: WidgetTypeConfigMap; @@ -112,6 +114,19 @@ function getLatestEvalPropertyErrors( message: e.errorMessage, })); + if (!(debuggerKey in updatedDebuggerErrors)) { + store.dispatch( + logDebuggerErrorAnalytics({ + eventName: "DEBUGGER_NEW_ERROR", + entityId: idField, + entityName: nameField, + entityType, + propertyPath, + errorMessages, + }), + ); + } + // Add or update updatedDebuggerErrors[debuggerKey] = { logType: LOG_TYPE.EVAL_ERROR, @@ -132,6 +147,17 @@ function getLatestEvalPropertyErrors( }, }; } else if (debuggerKey in updatedDebuggerErrors) { + store.dispatch( + logDebuggerErrorAnalytics({ + eventName: "DEBUGGER_RESOLVED_ERROR", + entityId: idField, + entityName: nameField, + entityType, + propertyPath: + updatedDebuggerErrors[debuggerKey].source?.propertyPath ?? "", + errorMessages: updatedDebuggerErrors[debuggerKey].messages ?? [], + }), + ); // Remove delete updatedDebuggerErrors[debuggerKey]; } diff --git a/app/client/src/utils/AnalyticsUtil.tsx b/app/client/src/utils/AnalyticsUtil.tsx index b5b633f497..6a0f246e00 100644 --- a/app/client/src/utils/AnalyticsUtil.tsx +++ b/app/client/src/utils/AnalyticsUtil.tsx @@ -124,7 +124,10 @@ export type EventName = | "GSHEET_AUTH_COMPLETE" | "CYCLICAL_DEPENDENCY_ERROR" | "DISCORD_LINK_CLICK" - | "BINDING_SUCCESS"; + | "BINDING_SUCCESS" + | "SLASH_COMMAND" + | "DEBUGGER_NEW_ERROR" + | "DEBUGGER_RESOLVED_ERROR"; function getApplicationId(location: Location) { const pathSplit = location.pathname.split("/");