From 5db37b871e5d02d5eef29534c05933af3a0c1c6e Mon Sep 17 00:00:00 2001 From: Favour Ohanekwu Date: Fri, 9 Jun 2023 06:41:07 +0100 Subject: [PATCH] chore: Log JS Function execution (#24163) --- .../ActionExecution/ActionExecutionSagas.ts | 8 ++- .../ActionConstants.tsx | 4 ++ app/client/src/sagas/EvalWorkerActionSagas.ts | 16 ++++- app/client/src/sagas/EvaluationsSaga.ts | 6 +- .../Evaluation/fns/utils/ExecutionMetaData.ts | 4 +- .../Evaluation/fns/utils/TriggerEmitter.ts | 16 +++-- .../Evaluation/fns/utils/jsObjectFnFactory.ts | 66 +++++++++++++++---- 7 files changed, 98 insertions(+), 22 deletions(-) diff --git a/app/client/src/ce/sagas/ActionExecution/ActionExecutionSagas.ts b/app/client/src/ce/sagas/ActionExecution/ActionExecutionSagas.ts index a1702fc6f0..57e1f8baa4 100644 --- a/app/client/src/ce/sagas/ActionExecution/ActionExecutionSagas.ts +++ b/app/client/src/ce/sagas/ActionExecution/ActionExecutionSagas.ts @@ -5,6 +5,7 @@ import type { ExecuteTriggerPayload, TriggerSource, } from "constants/AppsmithActionConstants/ActionConstants"; +import { TriggerKind } from "constants/AppsmithActionConstants/ActionConstants"; import * as log from "loglevel"; import { all, call, put, takeEvery, takeLatest } from "redux-saga/effects"; import { @@ -37,6 +38,7 @@ import type { ActionDescription } from "@appsmith/workers/Evaluation/fns"; export type TriggerMeta = { source?: TriggerSource; triggerPropertyName?: string; + triggerKind?: TriggerKind; }; /** @@ -123,7 +125,11 @@ export function* executeAppAction(payload: ExecuteTriggerPayload): any { evaluateAndExecuteDynamicTrigger, dynamicString, type, - { source, triggerPropertyName }, + { + source, + triggerPropertyName, + triggerKind: TriggerKind.EVENT_EXECUTION, + }, callbackData, globalContext, ); diff --git a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx index 4c431bdcbe..e3d1f31d5e 100644 --- a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx +++ b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx @@ -26,6 +26,10 @@ export type TriggerSource = { isJSAction?: boolean; actionId?: string; }; +export enum TriggerKind { + EVENT_EXECUTION = "EVENT_EXECUTION", // Eg. Button onClick + JS_FUNCTION_EXECUTION = "JS_FUNCTION_EXECUTION", // Executing js function from jsObject page +} export type ExecuteTriggerPayload = { dynamicString: string; diff --git a/app/client/src/sagas/EvalWorkerActionSagas.ts b/app/client/src/sagas/EvalWorkerActionSagas.ts index 0f32268ae3..5855d28e0b 100644 --- a/app/client/src/sagas/EvalWorkerActionSagas.ts +++ b/app/client/src/sagas/EvalWorkerActionSagas.ts @@ -30,6 +30,7 @@ export type UpdateDataTreeMessageData = { import { sortJSExecutionDataByCollectionId } from "workers/Evaluation/JSObject/utils"; import type { LintTreeSagaRequestData } from "workers/Linting/types"; +import AnalyticsUtil from "utils/AnalyticsUtil"; export function* handleEvalWorkerRequestSaga(listenerChannel: Channel) { while (true) { @@ -110,6 +111,19 @@ export function* processTriggerHandler(message: any) { if (messageType === MessageType.REQUEST) yield call(evalWorker.respond, message.messageId, result); } +export function* handleJSExecutionLog(data: TMessage<{ data: string[] }>) { + const { + body: { data: executedFns }, + } = data; + + for (const executedFn of executedFns) { + AnalyticsUtil.logEvent("EXECUTE_ACTION", { + type: "JS", + name: executedFn, + }); + } + yield call(logJSFunctionExecution, data); +} export function* handleEvalWorkerMessage(message: TMessage) { const { body } = message; @@ -136,7 +150,7 @@ export function* handleEvalWorkerMessage(message: TMessage) { break; } case MAIN_THREAD_ACTION.LOG_JS_FUNCTION_EXECUTION: { - yield call(logJSFunctionExecution, message); + yield call(handleJSExecutionLog, message); break; } case MAIN_THREAD_ACTION.PROCESS_BATCHED_TRIGGERS: { diff --git a/app/client/src/sagas/EvaluationsSaga.ts b/app/client/src/sagas/EvaluationsSaga.ts index 82fdf6db58..f2d898fec4 100644 --- a/app/client/src/sagas/EvaluationsSaga.ts +++ b/app/client/src/sagas/EvaluationsSaga.ts @@ -65,7 +65,10 @@ import { } from "actions/globalSearchActions"; import type { TriggerMeta } from "@appsmith/sagas/ActionExecution/ActionExecutionSagas"; import { executeActionTriggers } from "@appsmith/sagas/ActionExecution/ActionExecutionSagas"; -import { EventType } from "constants/AppsmithActionConstants/ActionConstants"; +import { + EventType, + TriggerKind, +} from "constants/AppsmithActionConstants/ActionConstants"; import { createMessage, SNIPPET_EXECUTION_FAILED, @@ -401,6 +404,7 @@ function* executeAsyncJSFunction( type: ENTITY_TYPE.JSACTION, }, triggerPropertyName: `${collectionName}.${action.name}`, + triggerKind: TriggerKind.JS_FUNCTION_EXECUTION, }; const eventType = EventType.ON_JS_FUNCTION_EXECUTE; const response: JSFunctionExecutionResponse = yield call( diff --git a/app/client/src/workers/Evaluation/fns/utils/ExecutionMetaData.ts b/app/client/src/workers/Evaluation/fns/utils/ExecutionMetaData.ts index 65cf67f5cf..1ef0b538b1 100644 --- a/app/client/src/workers/Evaluation/fns/utils/ExecutionMetaData.ts +++ b/app/client/src/workers/Evaluation/fns/utils/ExecutionMetaData.ts @@ -23,11 +23,13 @@ export default class ExecutionMetaData { } } static getExecutionMetaData() { - const { source, triggerPropertyName } = ExecutionMetaData.triggerMeta || {}; + const { source, triggerKind, triggerPropertyName } = + ExecutionMetaData.triggerMeta || {}; return { triggerMeta: { source: { ...source } as TriggerSource, triggerPropertyName, + triggerKind, }, eventType: ExecutionMetaData.eventType, enableJSVarUpdateTracking: ExecutionMetaData.enableJSVarUpdateTracking, diff --git a/app/client/src/workers/Evaluation/fns/utils/TriggerEmitter.ts b/app/client/src/workers/Evaluation/fns/utils/TriggerEmitter.ts index 3c48a10edd..099a3433a6 100644 --- a/app/client/src/workers/Evaluation/fns/utils/TriggerEmitter.ts +++ b/app/client/src/workers/Evaluation/fns/utils/TriggerEmitter.ts @@ -147,13 +147,15 @@ TriggerEmitter.on( jsVariableUpdatesHandlerWrapper, ); -export const fnInvokeLogHandler = priorityBatchedActionHandler((data) => { - const set = new Set([...data]); - WorkerMessenger.ping({ - method: MAIN_THREAD_ACTION.LOG_JS_FUNCTION_EXECUTION, - data: [...set], - }); -}); +export const fnInvokeLogHandler = priorityBatchedActionHandler( + (data) => { + const set = new Set([...data]); + WorkerMessenger.ping({ + method: MAIN_THREAD_ACTION.LOG_JS_FUNCTION_EXECUTION, + data: [...set], + }); + }, +); TriggerEmitter.on(BatchKey.process_batched_fn_invoke_log, fnInvokeLogHandler); diff --git a/app/client/src/workers/Evaluation/fns/utils/jsObjectFnFactory.ts b/app/client/src/workers/Evaluation/fns/utils/jsObjectFnFactory.ts index e5cb8ed8a3..6864d1f0b9 100644 --- a/app/client/src/workers/Evaluation/fns/utils/jsObjectFnFactory.ts +++ b/app/client/src/workers/Evaluation/fns/utils/jsObjectFnFactory.ts @@ -2,6 +2,7 @@ import { isPromise } from "workers/Evaluation/JSObject/utils"; import { postJSFunctionExecutionLog } from "@appsmith/workers/Evaluation/JSObject/postJSFunctionExecution"; import TriggerEmitter, { BatchKey } from "./TriggerEmitter"; import ExecutionMetaData from "./ExecutionMetaData"; +import { TriggerKind } from "constants/AppsmithActionConstants/ActionConstants"; declare global { interface Window { @@ -11,48 +12,91 @@ declare global { ) => any; } } +export type PostProcessorArg = { + executionMetaData: ReturnType; + jsFnFullName: string; + executionResponse: unknown; +}; + +export type PostProcessor = (args: PostProcessorArg) => void; export interface JSExecutionData { data: unknown; funcName: string; } -function saveExecutionData(name: string, data: unknown) { +function saveExecutionData({ + executionResponse, + jsFnFullName, +}: PostProcessorArg) { TriggerEmitter.emit(BatchKey.process_batched_fn_execution, { - name, - data, + name: jsFnFullName, + data: executionResponse, }); } +function logJSExecution({ executionMetaData, jsFnFullName }: PostProcessorArg) { + switch (executionMetaData.triggerMeta.triggerKind) { + case TriggerKind.EVENT_EXECUTION: { + TriggerEmitter.emit(BatchKey.process_batched_fn_invoke_log, jsFnFullName); + break; + } + default: { + break; + } + } + postJSFunctionExecutionLog(jsFnFullName); +} + export function jsObjectFunctionFactory

>( fn: (...args: P) => unknown, name: string, - postProcessors: Array<(name: string, res: unknown) => void> = [ - saveExecutionData, - postJSFunctionExecutionLog, - ], + postProcessors: PostProcessor[] = [saveExecutionData, logJSExecution], ) { return function (this: unknown, ...args: P) { if (!ExecutionMetaData.getExecutionMetaData().enableJSFnPostProcessors) { return fn.call(this, ...args); } + const executionMetaData = ExecutionMetaData.getExecutionMetaData(); try { const result = fn.call(this, ...args); if (isPromise(result)) { result.then((res) => { - postProcessors.forEach((p) => p(name, res)); + postProcessors.forEach((p) => + p({ + executionMetaData, + jsFnFullName: name, + executionResponse: res, + }), + ); return res; }); result.catch((e) => { - postProcessors.forEach((p) => p(name, undefined)); + postProcessors.forEach((p) => + p({ + executionMetaData, + jsFnFullName: name, + executionResponse: undefined, + }), + ); throw e; }); } else { - postProcessors.forEach((p) => p(name, result)); + postProcessors.forEach((p) => + p({ + executionMetaData, + jsFnFullName: name, + executionResponse: result, + }), + ); } return result; } catch (e) { postProcessors.forEach((postProcessor) => { - postProcessor(name, undefined); + postProcessor({ + executionMetaData, + jsFnFullName: name, + executionResponse: undefined, + }); }); throw e; }