chore: Added profiling for widget components performance (#34912)
## Description Capturing telemetry of widget renders and only enabling the profiled build for community users. This should cause a minor performance overhead and in case performance degrades too much we can disable the widget profiled telemetry by disabling the new relic flag(set this to false `APPSMITH_NEW_RELIC_ACCOUNT_ENABLE`). Fixes #35184 > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Sanity" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/10111247316> > Commit: 38310d7341e7a2acb30491e478edaedbbc16a739 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10111247316&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Sanity` > Spec: > <hr>Fri, 26 Jul 2024 12:55:43 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Introduced `WidgetProfiler` component to track rendering performance metrics. - Added a new function for enhanced telemetry span management. - **Improvements** - Updated build script to allow for profiled builds based on environment variables, improving performance analysis. - Implemented GZIP compression for OTLP trace data transmission, optimizing bandwidth usage. - **Refactor** - Removed `Sentry.withProfiler` for widget profiling, simplifying performance monitoring. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
20aac6bdb6
commit
4bf6671cc4
|
|
@ -18,6 +18,12 @@ export REACT_APP_SENTRY_RELEASE=$GIT_SHA
|
|||
export REACT_APP_CLIENT_LOG_LEVEL=ERROR
|
||||
# Disable CRA built-in ESLint checks since we have our own config and a separate step for this
|
||||
export DISABLE_ESLINT_PLUGIN=true
|
||||
craco --max-old-space-size=7168 build --config craco.build.config.js
|
||||
if [ "$APPSMITH_CLOUD_HOSTING" == "true" ]; then
|
||||
echo "Building profiled build"
|
||||
craco --max-old-space-size=7168 build --profile --config craco.build.config.js --verbose
|
||||
else
|
||||
craco --max-old-space-size=7168 build --config craco.build.config.js
|
||||
fi
|
||||
|
||||
|
||||
echo "build finished"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ const tracerProvider = new WebTracerProvider({
|
|||
|
||||
const nrTracesExporter = new OTLPTraceExporter({
|
||||
url: `${otlpEndpoint}/v1/traces`,
|
||||
compression: CompressionAlgorithm.GZIP,
|
||||
headers: {
|
||||
"api-key": otlpLicenseKey,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -91,3 +91,15 @@ export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => any) {
|
|||
const parentContext = trace.setSpan(context.active(), parentSpan);
|
||||
return context.with(parentContext, fn);
|
||||
}
|
||||
|
||||
export function startAndEndSpan(
|
||||
spanName: string,
|
||||
startTime: number,
|
||||
difference: number,
|
||||
spanAttributes: SpanAttributes = {},
|
||||
) {
|
||||
const endTime = startTime + Math.floor(difference);
|
||||
|
||||
const span = startRootSpan(spanName, spanAttributes, startTime);
|
||||
span.end(endTime);
|
||||
}
|
||||
|
|
|
|||
27
app/client/src/widgets/BaseWidgetHOC/WidgetProfiler.tsx
Normal file
27
app/client/src/widgets/BaseWidgetHOC/WidgetProfiler.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import React, { Profiler, useCallback } from "react";
|
||||
import { startAndEndSpan } from "UITelemetry/generateTraces";
|
||||
export const WidgetProfiler = ({
|
||||
children,
|
||||
type,
|
||||
widgetId,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
type: string;
|
||||
widgetId: string;
|
||||
}) => {
|
||||
const onRender = useCallback(
|
||||
(id: string, phase: string, actualDuration: number) => {
|
||||
startAndEndSpan("widgetRender", Date.now(), actualDuration, {
|
||||
widgetType: type,
|
||||
// mount or update phase
|
||||
phase,
|
||||
});
|
||||
},
|
||||
[type],
|
||||
);
|
||||
return (
|
||||
<Profiler id={widgetId} onRender={onRender}>
|
||||
{children}
|
||||
</Profiler>
|
||||
);
|
||||
};
|
||||
|
|
@ -3,7 +3,6 @@ import withMeta from "widgets/MetaHOC";
|
|||
import { withLazyRender } from "widgets/withLazyRender";
|
||||
import type BaseWidget from "widgets/BaseWidget";
|
||||
import withWidgetProps from "widgets/withWidgetProps";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { withLayoutSystemWidgetHOC } from "../../layoutSystems/withLayoutSystemWidgetHOC";
|
||||
import { flow, identity } from "lodash";
|
||||
|
||||
|
|
@ -26,8 +25,5 @@ export const withBaseWidgetHOC = (
|
|||
|
||||
// Adds/Enhances widget props
|
||||
withWidgetProps,
|
||||
|
||||
// Wraps the widget to be profiled via sentry
|
||||
Sentry.withProfiler,
|
||||
])(Widget);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ import { getLayoutSystemType } from "selectors/layoutSystemSelectors";
|
|||
import { isWidgetSelectedForPropertyPane } from "selectors/propertyPaneSelectors";
|
||||
import WidgetFactory from "WidgetProvider/factory";
|
||||
import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors";
|
||||
import { WidgetProfiler } from "./BaseWidgetHOC/WidgetProfiler";
|
||||
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||
const { newRelic } = getAppsmithConfigs();
|
||||
|
||||
const WIDGETS_WITH_CHILD_WIDGETS = ["LIST_WIDGET", "FORM_WIDGET"];
|
||||
const WIDGETS_REQUIRING_SELECTED_ANCESTRY = ["MODAL_WIDGET", "TABS_WIDGET"];
|
||||
|
|
@ -353,7 +356,15 @@ function withWidgetProps(WrappedWidget: typeof BaseWidget) {
|
|||
}
|
||||
}
|
||||
|
||||
return <WrappedWidget {...widgetProps} />;
|
||||
if (!newRelic.enableNewRelic) {
|
||||
return <WrappedWidget {...widgetProps} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<WidgetProfiler type={type} widgetId={widgetId}>
|
||||
<WrappedWidget {...widgetProps} />
|
||||
</WidgetProfiler>
|
||||
);
|
||||
}
|
||||
|
||||
return WrappedPropsComponent;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user