277 lines
7.9 KiB
TypeScript
277 lines
7.9 KiB
TypeScript
import * as Sentry from "@sentry/react";
|
|
import { Span, SpanStatus } from "@sentry/tracing";
|
|
import { getAppsmithConfigs } from "configs";
|
|
import _ from "lodash";
|
|
import * as log from "loglevel";
|
|
|
|
export enum PerformanceTransactionName {
|
|
DEPLOY_APPLICATION = "DEPLOY_APPLICATION",
|
|
DATA_TREE_EVALUATION = "DATA_TREE_EVALUATION",
|
|
DATA_TREE_WORKER_EVALUATION = "DATA_TREE_WORKER_EVALUATION",
|
|
EVAL_REDUX_UPDATE = "EVAL_REDUX_UPDATE",
|
|
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",
|
|
EVALUATE_BINDING = "EVALUATE_BINDING",
|
|
ENTITY_EXPLORER_ENTITY = "ENTITY_EXPLORER_ENTITY",
|
|
ENTITY_EXPLORER = "ENTITY_EXPLORER",
|
|
CLOSE_SIDE_PANE = "CLOSE_SIDE_PANE",
|
|
OPEN_ACTION = "OPEN_ACTION",
|
|
EDITOR_MOUNT = "EDITOR_MOUNT",
|
|
SIDE_BAR_MOUNT = "SIDE_BAR_MOUNT",
|
|
CANVAS_MOUNT = "CANVAS_MOUNT",
|
|
EXECUTE_ACTION = "EXECUTE_ACTION",
|
|
CHANGE_API_SAGA = "CHANGE_API_SAGA",
|
|
SYNC_PARAMS_SAGA = "SYNC_PARAMS_SAGA",
|
|
RUN_API_CLICK = "RUN_API_CLICK",
|
|
RUN_QUERY_CLICK = "RUN_QUERY_CLICK",
|
|
FETCH_ACTIONS_API = "FETCH_ACTIONS_API",
|
|
FETCH_PAGE_LIST_API = "FETCH_PAGE_LIST_API",
|
|
FETCH_PAGE_ACTIONS_API = "FETCH_PAGE_ACTIONS_API",
|
|
FETCH_PAGE_API = "FETCH_PAGE_API",
|
|
SAVE_PAGE_API = "SAVE_PAGE_API",
|
|
UPDATE_ACTION_API = "UPDATE_ACTION_API",
|
|
OPEN_PROPERTY_PANE = "OPEN_PROPERTY_PANE",
|
|
REFACTOR_ACTION_NAME = "REFACTOR_ACTION_NAME",
|
|
USER_ME_API = "USER_ME_API",
|
|
SIGN_UP = "SIGN_UP",
|
|
LOGIN_CLICK = "LOGIN_CLICK",
|
|
SET_EVALUATED = "SET_EVALUATED",
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
const appsmithConfigs = getAppsmithConfigs();
|
|
|
|
class PerformanceTracker {
|
|
private static perfLogQueue: PerfLog[] = [];
|
|
private static perfAsyncMap: Map<string, PerfLog> = new Map();
|
|
|
|
static startTracking = (
|
|
eventName: PerformanceTransactionName,
|
|
data?: any,
|
|
skipLog = false,
|
|
) => {
|
|
if (appsmithConfigs.sentry.enabled) {
|
|
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) {
|
|
log.debug(
|
|
PerformanceTracker.generateSpaces(
|
|
PerformanceTracker.perfLogQueue.length + 1,
|
|
) +
|
|
eventName +
|
|
" Track Transaction ",
|
|
);
|
|
}
|
|
const newTransaction = Sentry.startTransaction({ name: eventName });
|
|
newTransaction.setData("startData", data);
|
|
Sentry.getCurrentHub().configureScope((scope) =>
|
|
scope.setSpan(newTransaction),
|
|
);
|
|
PerformanceTracker.perfLogQueue.push({
|
|
sentrySpan: newTransaction,
|
|
skipLog: skipLog,
|
|
eventName: eventName,
|
|
});
|
|
} else {
|
|
if (!skipLog) {
|
|
log.debug(
|
|
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 = (
|
|
eventName?: PerformanceTransactionName,
|
|
data?: any,
|
|
) => {
|
|
if (appsmithConfigs.sentry.enabled) {
|
|
if (eventName) {
|
|
const index = _.findLastIndex(
|
|
PerformanceTracker.perfLogQueue,
|
|
(perfLog) => {
|
|
return perfLog.eventName === eventName;
|
|
},
|
|
);
|
|
if (index !== -1) {
|
|
for (
|
|
let i = PerformanceTracker.perfLogQueue.length - 1;
|
|
i >= index;
|
|
i--
|
|
) {
|
|
const perfLog = PerformanceTracker.perfLogQueue.pop();
|
|
if (perfLog) {
|
|
const currentSpan = perfLog.sentrySpan;
|
|
currentSpan.finish();
|
|
if (!perfLog?.skipLog) {
|
|
PerformanceTracker.printDuration(
|
|
perfLog.eventName,
|
|
i + 1,
|
|
currentSpan.startTimestamp,
|
|
currentSpan.endTimestamp,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} 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 startAsyncTracking = (
|
|
eventName: PerformanceTransactionName,
|
|
data?: any,
|
|
uniqueId?: string,
|
|
parentEventId?: string,
|
|
skipLog = false,
|
|
) => {
|
|
if (!skipLog) {
|
|
log.debug(
|
|
"Async " +
|
|
PerformanceTracker.generateSpaces(0) +
|
|
eventName +
|
|
" Track Transaction ",
|
|
);
|
|
}
|
|
if (!parentEventId) {
|
|
const newTransaction = Sentry.startTransaction({ name: eventName });
|
|
newTransaction.setData("startData", data);
|
|
PerformanceTracker.perfAsyncMap.set(uniqueId ? uniqueId : eventName, {
|
|
sentrySpan: newTransaction,
|
|
eventName: eventName,
|
|
skipLog: skipLog,
|
|
});
|
|
} else {
|
|
const perfLog = PerformanceTracker.perfAsyncMap.get(parentEventId);
|
|
const childSpan = perfLog?.sentrySpan.startChild({
|
|
op: eventName,
|
|
data: data,
|
|
});
|
|
if (childSpan) {
|
|
PerformanceTracker.perfAsyncMap.set(uniqueId ? uniqueId : eventName, {
|
|
sentrySpan: childSpan,
|
|
eventName: eventName,
|
|
skipLog: skipLog,
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
static stopAsyncTracking(
|
|
eventName: PerformanceTransactionName,
|
|
data?: any,
|
|
uniqueId?: string,
|
|
) {
|
|
const perfLog = PerformanceTracker.perfAsyncMap.get(
|
|
uniqueId ? uniqueId : eventName,
|
|
);
|
|
if (perfLog) {
|
|
const currentSpan = perfLog.sentrySpan;
|
|
currentSpan.setData("endData", data);
|
|
currentSpan.finish();
|
|
if (!perfLog?.skipLog) {
|
|
PerformanceTracker.printDuration(
|
|
perfLog.eventName,
|
|
0,
|
|
currentSpan.startTimestamp,
|
|
currentSpan.endTimestamp,
|
|
true,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
static generateSpaces(num: number) {
|
|
let str = "";
|
|
for (let i = 0; i < num; i++) {
|
|
str += "\t";
|
|
}
|
|
return str;
|
|
}
|
|
|
|
static printDuration(
|
|
eventName: string,
|
|
level: number,
|
|
startTime: number,
|
|
endTime?: number,
|
|
isAsync?: boolean,
|
|
) {
|
|
const duration = ((endTime || 0) - startTime) * 1000;
|
|
const spaces = PerformanceTracker.generateSpaces(level);
|
|
log.debug(
|
|
(isAsync ? "Async " : "") +
|
|
spaces +
|
|
eventName +
|
|
" Finish Tracking in " +
|
|
duration +
|
|
"ms",
|
|
);
|
|
}
|
|
}
|
|
|
|
export default PerformanceTracker;
|