chore: Move sentry to faro for client side (#40220)
## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!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.All" ### 🔍 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/14401534892> > Commit: cad55550d2e517bec0031fe4043ec76cfb4d67e3 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14401534892&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Fri, 11 Apr 2025 12:38:06 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 - **Refactor** - Revamped the error reporting system across the platform with enhanced contextual logging for faster issue diagnosis. - **Chore** - Removed legacy error tracking integrations, streamlining overall error handling and system reliability. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
de7f73d508
commit
6b6e348203
|
|
@ -1,10 +1,10 @@
|
|||
import React, { Component } from "react";
|
||||
import styled from "styled-components";
|
||||
import AppCrashImage from "assets/images/404-image.png";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import log from "loglevel";
|
||||
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
||||
import { Button } from "@appsmith/ads";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -32,7 +32,7 @@ class AppErrorBoundary extends Component {
|
|||
|
||||
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
||||
log.error({ error, errorInfo });
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "AppErrorBoundary" });
|
||||
AnalyticsUtil.logEvent("APP_CRASH", { error, errorInfo });
|
||||
this.setState({
|
||||
hasError: true,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Tag } from "@blueprintjs/core";
|
|||
import styled from "styled-components";
|
||||
import { UIComponentTypes } from "entities/Plugin";
|
||||
import log from "loglevel";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import type { FormEvalOutput } from "reducers/evaluationReducers/formEvaluationReducer";
|
||||
import {
|
||||
checkIfSectionCanRender,
|
||||
|
|
@ -103,7 +103,7 @@ const FormRender = (props: Props) => {
|
|||
}
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "FormRenderError" });
|
||||
|
||||
return (
|
||||
<ErrorComponent
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import type { APP_MODE } from "entities/App";
|
|||
import type { CanvasWidgetsReduxState } from "ee/reducers/entityReducers/canvasWidgetsReducer";
|
||||
import type { ENTITY_TYPE } from "ee/entities/AppsmithConsole/utils";
|
||||
import type { Replayable } from "entities/Replay/ReplayEntity/ReplayEditor";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { DSLWidget } from "../WidgetProvider/constants";
|
||||
import type {
|
||||
LayoutOnLoadActionErrors,
|
||||
|
|
@ -30,6 +29,7 @@ import { ReplayOperation } from "entities/Replay/ReplayEntity/ReplayOperations";
|
|||
import type { PACKAGE_PULL_STATUS } from "ee/constants/ModuleConstants";
|
||||
import type { ApiResponse } from "api/ApiResponses";
|
||||
import type { EvaluationReduxAction } from "./EvaluationReduxActionTypes";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export interface FetchPageListPayload {
|
||||
applicationId: string;
|
||||
|
|
@ -322,13 +322,10 @@ export interface UpdatePageActionPayload {
|
|||
export const updatePageAction = (
|
||||
payload: UpdatePageActionPayload,
|
||||
): ReduxAction<UpdatePageActionPayload> => {
|
||||
// Update page *needs* id to be there. We found certain scenarios
|
||||
// where this was not happening and capturing the error to know gather
|
||||
// more info: https://github.com/appsmithorg/appsmith/issues/16435
|
||||
if (!payload.id) {
|
||||
Sentry.captureException(
|
||||
new Error("Attempting to update page without page id"),
|
||||
);
|
||||
captureException(new Error("Attempting to update page without page id"), {
|
||||
errorName: "PageActions_UpdatePage",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { CONTENT_TYPE_HEADER_KEY } from "PluginActionEditor/constants/CommonApiConstants";
|
||||
|
||||
|
|
@ -7,7 +7,8 @@ export const validateJsonResponseMeta = (response: AxiosResponse) => {
|
|||
response.headers[CONTENT_TYPE_HEADER_KEY] === "application/json" &&
|
||||
!response.data.responseMeta
|
||||
) {
|
||||
Sentry.captureException(new Error("Api responded without response meta"), {
|
||||
captureException(new Error("Api responded without response meta"), {
|
||||
errorName: "ValidateJsonResponseMeta",
|
||||
contexts: { response: response.data },
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import type { AxiosError } from "axios";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { ApiResponse } from "api/types";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export const handleMissingResponseMeta = async (
|
||||
error: AxiosError<ApiResponse>,
|
||||
) => {
|
||||
if (error.response?.data && !error.response.data.responseMeta) {
|
||||
Sentry.captureException(new Error("Api responded without response meta"), {
|
||||
captureException(new Error("Api responded without response meta"), {
|
||||
errorName: "MissingResponseMeta",
|
||||
contexts: { response: { ...error.response.data } },
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import {
|
|||
ERROR_CODES,
|
||||
SERVER_ERROR_CODES,
|
||||
} from "ee/constants/ApiConstants";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { AxiosError } from "axios";
|
||||
import type { ApiResponse } from "api/types";
|
||||
import { is404orAuthPath } from "api/helpers";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export async function handleNotFoundError(error: AxiosError<ApiResponse>) {
|
||||
if (is404orAuthPath()) return null;
|
||||
|
|
@ -20,7 +20,7 @@ export async function handleNotFoundError(error: AxiosError<ApiResponse>) {
|
|||
(SERVER_ERROR_CODES.RESOURCE_NOT_FOUND.includes(errorData.error?.code) ||
|
||||
SERVER_ERROR_CODES.UNABLE_TO_FIND_PAGE.includes(errorData?.error?.code))
|
||||
) {
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "NotFoundError" });
|
||||
|
||||
return Promise.reject({
|
||||
...error,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import store from "store";
|
||||
import type { AxiosError } from "axios";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { is404orAuthPath } from "api/helpers";
|
||||
import { logoutUser } from "actions/userActions";
|
||||
import { AUTH_LOGIN_URL } from "constants/routes";
|
||||
import { API_STATUS_CODES, ERROR_CODES } from "ee/constants/ApiConstants";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export const handleUnauthorizedError = async (error: AxiosError) => {
|
||||
if (is404orAuthPath()) return null;
|
||||
|
|
@ -20,7 +20,7 @@ export const handleUnauthorizedError = async (error: AxiosError) => {
|
|||
}),
|
||||
);
|
||||
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "UnauthorizedError" });
|
||||
|
||||
return Promise.reject({
|
||||
...error,
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ import { clearEvalCache } from "../../sagas/EvaluationsSaga";
|
|||
import { getQueryParams } from "utils/URLUtils";
|
||||
import log from "loglevel";
|
||||
import { migrateIncorrectDynamicBindingPathLists } from "utils/migrations/IncorrectDynamicBindingPathLists";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { ERROR_CODES } from "ee/constants/ApiConstants";
|
||||
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
||||
import DEFAULT_TEMPLATE from "templates/default";
|
||||
|
|
@ -152,6 +151,7 @@ import {
|
|||
selectCombinedPreviewMode,
|
||||
selectGitApplicationCurrentBranch,
|
||||
} from "selectors/gitModSelectors";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export const checkIfMigrationIsNeeded = (
|
||||
fetchPageResponse?: FetchPageResponse,
|
||||
|
|
@ -570,7 +570,9 @@ export function* savePageSaga(action: ReduxAction<{ isRetry?: boolean }>) {
|
|||
const { message } = incorrectBindingError;
|
||||
|
||||
if (isRetry) {
|
||||
Sentry.captureException(new Error("Failed to correct binding paths"));
|
||||
captureException(new Error("Failed to correct binding paths"), {
|
||||
errorName: "PageSagas_BindingPathCorrection",
|
||||
});
|
||||
yield put({
|
||||
type: ReduxActionErrorTypes.FAILED_CORRECTING_BINDING_PATHS,
|
||||
payload: {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import SegmentSingleton from "utils/Analytics/segment";
|
|||
import MixpanelSingleton, {
|
||||
type SessionRecordingConfig,
|
||||
} from "utils/Analytics/mixpanel";
|
||||
import SentryUtil from "utils/Analytics/sentry";
|
||||
import FaroUtil from "utils/Analytics/sentry";
|
||||
import SmartlookUtil from "utils/Analytics/smartlook";
|
||||
import TrackedUser from "ee/utils/Analytics/trackedUser";
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ async function initialize(
|
|||
user: User,
|
||||
sessionRecordingConfig: SessionRecordingConfig,
|
||||
) {
|
||||
SentryUtil.init();
|
||||
// SentryUtil.init();
|
||||
await SmartlookUtil.init();
|
||||
|
||||
segmentAnalytics = SegmentSingleton.getInstance();
|
||||
|
|
@ -94,7 +94,7 @@ async function identifyUser(userData: User, sendAdditionalData?: boolean) {
|
|||
await segmentAnalytics.identify(trackedUser.userId, userProperties);
|
||||
}
|
||||
|
||||
SentryUtil.identifyUser(trackedUser.userId, userData);
|
||||
FaroUtil.identifyUser(trackedUser.userId, userData);
|
||||
|
||||
if (trackedUser.email) {
|
||||
SmartlookUtil.identify(trackedUser.userId, trackedUser.email);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import { Route } from "react-router";
|
||||
|
||||
export const SentryRoute = Sentry.withSentryRouting(Route);
|
||||
export const SentryRoute = Route;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import { Classes, Collapse } from "@blueprintjs/core";
|
|||
import { UNDEFINED_VALIDATION } from "utils/validation/common";
|
||||
import copy from "copy-to-clipboard";
|
||||
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { CodeEditorExpected } from "components/editorComponents/CodeEditor/index";
|
||||
import type { Indices } from "constants/Layers";
|
||||
import { Layers } from "constants/Layers";
|
||||
|
|
@ -29,6 +28,7 @@ import { getPathNavigationUrl } from "selectors/navigationSelectors";
|
|||
import { Button, Icon, Link, toast, Tooltip } from "@appsmith/ads";
|
||||
import type { EvaluationError } from "utils/DynamicBindingUtils";
|
||||
import { DEBUGGER_TAB_KEYS } from "../Debugger/constants";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
const modifiers: IPopoverSharedProps["modifiers"] = {
|
||||
offset: {
|
||||
|
|
@ -290,8 +290,8 @@ export function PreparedStatementViewer(props: {
|
|||
const { parameters, value } = props.evaluatedValue;
|
||||
|
||||
if (!value) {
|
||||
Sentry.captureException("Prepared statement got no value", {
|
||||
level: "debug",
|
||||
captureException(new Error("Prepared statement got no value"), {
|
||||
errorName: "PreparedStatementError",
|
||||
extra: { props },
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ import { Button } from "@appsmith/ads";
|
|||
import "codemirror/addon/fold/brace-fold";
|
||||
import "codemirror/addon/fold/foldgutter";
|
||||
import "codemirror/addon/fold/foldgutter.css";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { EvaluationError, LintError } from "utils/DynamicBindingUtils";
|
||||
import { getEvalErrorPath, isDynamicValue } from "utils/DynamicBindingUtils";
|
||||
import {
|
||||
|
|
@ -1919,6 +1918,4 @@ const mapDispatchToProps = (dispatch: any) => ({
|
|||
resetActiveField: () => dispatch(resetActiveEditorField()),
|
||||
});
|
||||
|
||||
export default Sentry.withProfiler(
|
||||
connect(mapStateToProps, mapDispatchToProps)(CodeEditor),
|
||||
);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(CodeEditor);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import classNames from "classnames";
|
||||
import React, {
|
||||
memo,
|
||||
|
|
@ -173,4 +172,4 @@ export const EntityExplorerSidebar = memo(({ children }: Props) => {
|
|||
|
||||
EntityExplorerSidebar.displayName = "EntityExplorerSidebar";
|
||||
|
||||
export default Sentry.withProfiler(EntityExplorerSidebar);
|
||||
export default EntityExplorerSidebar;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import * as log from "loglevel";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
import type { ReactNode, CSSProperties } from "react";
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ class ErrorBoundary extends React.Component<Props, State> {
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
log.error({ error, errorInfo });
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "ErrorBoundary" });
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import React, {
|
|||
useMemo,
|
||||
useRef,
|
||||
} from "react";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getSelectedWidgets } from "selectors/ui";
|
||||
import WidgetPropertyPane from "pages/Editor/PropertyPane";
|
||||
|
|
@ -104,4 +103,4 @@ export const PropertyPaneSidebar = memo(() => {
|
|||
|
||||
PropertyPaneSidebar.displayName = "PropertyPaneSidebar";
|
||||
|
||||
export default Sentry.withProfiler(PropertyPaneSidebar);
|
||||
export default PropertyPaneSidebar;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import React, { Component } from "react";
|
|||
import type { AppState } from "ee/reducers";
|
||||
import { connect } from "react-redux";
|
||||
import type { Placement } from "popper.js";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import _ from "lodash";
|
||||
import type { ControlProps } from "./BaseControl";
|
||||
import BaseControl from "./BaseControl";
|
||||
|
|
@ -407,6 +406,6 @@ const mapStateToProps = (state: AppState): ReduxStateProps => ({
|
|||
datasources: state.entities.datasources,
|
||||
});
|
||||
|
||||
const EvaluatedValuePopupWrapper = Sentry.withProfiler(
|
||||
connect(mapStateToProps)(EvaluatedValuePopupWrapperClass),
|
||||
const EvaluatedValuePopupWrapper = connect(mapStateToProps)(
|
||||
EvaluatedValuePopupWrapperClass,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { AppState } from "ee/reducers";
|
||||
import * as Sentry from "@sentry/react";
|
||||
|
||||
import type { CodeEditorExpected } from "components/editorComponents/CodeEditor";
|
||||
import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig";
|
||||
import EvaluatedValuePopup from "components/editorComponents/CodeEditor/EvaluatedValuePopup";
|
||||
|
|
@ -548,6 +548,6 @@ const mapStateToProps = (
|
|||
};
|
||||
};
|
||||
|
||||
const EvaluatedValuePopupWrapper = Sentry.withProfiler(
|
||||
connect(mapStateToProps)(EvaluatedValuePopupWrapperClass),
|
||||
const EvaluatedValuePopupWrapper = connect(mapStateToProps)(
|
||||
EvaluatedValuePopupWrapperClass,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import React, { Component } from "react";
|
|||
import type { AppState } from "ee/reducers";
|
||||
import { connect } from "react-redux";
|
||||
import type { Placement } from "popper.js";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import _, { toString } from "lodash";
|
||||
import type { ControlProps } from "./BaseControl";
|
||||
import BaseControl from "./BaseControl";
|
||||
|
|
@ -497,6 +496,6 @@ const mapStateToProps = (
|
|||
};
|
||||
};
|
||||
|
||||
const EvaluatedValuePopupWrapper = Sentry.withProfiler(
|
||||
connect(mapStateToProps)(EvaluatedValuePopupWrapperClass),
|
||||
const EvaluatedValuePopupWrapper = connect(mapStateToProps)(
|
||||
EvaluatedValuePopupWrapperClass,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import isString from "lodash/isString";
|
|||
import isUndefined from "lodash/isUndefined";
|
||||
import includes from "lodash/includes";
|
||||
import map from "lodash/map";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
import { DraggableListControl } from "pages/Editor/PropertyPane/DraggableListControl";
|
||||
|
|
@ -131,10 +131,13 @@ class TabControl extends BaseControl<ControlProps, State> {
|
|||
|
||||
return parsedData;
|
||||
} catch (error) {
|
||||
Sentry.captureException({
|
||||
message: "Tab Migration Failed",
|
||||
oldData: this.props.propertyValue,
|
||||
});
|
||||
captureException(
|
||||
{
|
||||
message: "Tab Migration Failed",
|
||||
oldData: this.props.propertyValue,
|
||||
},
|
||||
{ errorName: "TabMigrationError" },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return this.props.propertyValue;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { sagas as CE_Sagas } from "ce/sagas";
|
|||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
import { call, all, spawn, race, take } from "redux-saga/effects";
|
||||
import log from "loglevel";
|
||||
import * as sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
const sagasArr = [...CE_Sagas];
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ export function* rootSaga(sagasToRun = sagasArr): any {
|
|||
break;
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
sentry.captureException(e);
|
||||
captureException(e, { errorName: "RootSagaError" });
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { captureException } from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import type { ApiResponse } from "api/types";
|
||||
import log from "loglevel";
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ export default function handleApiErrors(error?: Error, response?: ApiResponse) {
|
|||
}
|
||||
} else {
|
||||
log.error(error);
|
||||
captureException(error);
|
||||
captureException(error, { errorName: "GitApiError" });
|
||||
}
|
||||
|
||||
return apiError;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@ import {
|
|||
import log from "loglevel";
|
||||
import { isTracingEnabled } from "instrumentation/utils";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
faro: Faro | null;
|
||||
}
|
||||
}
|
||||
|
||||
const { appVersion, observability } = getAppsmithConfigs();
|
||||
const { deploymentName, serviceInstanceId, serviceName, tracingUrl } =
|
||||
observability;
|
||||
|
|
@ -36,29 +42,41 @@ if (isTracingEnabled()) {
|
|||
? InternalLoggerLevel.ERROR
|
||||
: InternalLoggerLevel.OFF;
|
||||
|
||||
faro = initializeFaro({
|
||||
url: tracingUrl,
|
||||
app: {
|
||||
name: serviceName,
|
||||
version: appVersion.sha,
|
||||
environment: deploymentName,
|
||||
},
|
||||
instrumentations: [new ReactIntegration(), ...getWebInstrumentations()],
|
||||
ignoreUrls,
|
||||
consoleInstrumentation: {
|
||||
consoleErrorAsLog: true,
|
||||
},
|
||||
trackResources: true,
|
||||
trackWebVitalsAttribution: true,
|
||||
internalLoggerLevel,
|
||||
sessionTracking: {
|
||||
generateSessionId: () => {
|
||||
// Disabling session tracing will not send any instrumentation data to the grafana backend
|
||||
// Instead, hardcoding the session id to a constant value to indirecly disable session tracing
|
||||
return "SESSION_ID";
|
||||
},
|
||||
},
|
||||
});
|
||||
try {
|
||||
if (!window.faro) {
|
||||
faro = initializeFaro({
|
||||
url: tracingUrl,
|
||||
app: {
|
||||
name: serviceName,
|
||||
version: appVersion.sha,
|
||||
environment: deploymentName,
|
||||
},
|
||||
instrumentations: [
|
||||
new ReactIntegration(),
|
||||
...getWebInstrumentations({}),
|
||||
],
|
||||
ignoreUrls,
|
||||
consoleInstrumentation: {
|
||||
consoleErrorAsLog: false,
|
||||
},
|
||||
trackResources: true,
|
||||
trackWebVitalsAttribution: true,
|
||||
internalLoggerLevel,
|
||||
sessionTracking: {
|
||||
generateSessionId: () => {
|
||||
// Disabling session tracing will not send any instrumentation data to the grafana backend
|
||||
// Instead, hardcoding the session id to a constant value to indirecly disable session tracing
|
||||
return "SESSION_ID";
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
faro = window.faro;
|
||||
|
||||
const tracerProvider = new WebTracerProvider({
|
||||
resource: new Resource({
|
||||
|
|
@ -68,18 +86,20 @@ if (isTracingEnabled()) {
|
|||
}),
|
||||
});
|
||||
|
||||
tracerProvider.addSpanProcessor(
|
||||
new FaroSessionSpanProcessor(
|
||||
new BatchSpanProcessor(new FaroTraceExporter({ ...faro })),
|
||||
faro.metas,
|
||||
),
|
||||
);
|
||||
if (faro) {
|
||||
tracerProvider.addSpanProcessor(
|
||||
new FaroSessionSpanProcessor(
|
||||
new BatchSpanProcessor(new FaroTraceExporter({ ...faro })),
|
||||
faro.metas,
|
||||
),
|
||||
);
|
||||
|
||||
tracerProvider.register({
|
||||
contextManager: new ZoneContextManager(),
|
||||
});
|
||||
tracerProvider.register({
|
||||
contextManager: new ZoneContextManager(),
|
||||
});
|
||||
|
||||
faro.api.initOTEL(trace, context);
|
||||
faro.api.initOTEL(trace, context);
|
||||
}
|
||||
}
|
||||
|
||||
export const getTraceAndContext = () => {
|
||||
|
|
@ -91,3 +111,5 @@ export const getTraceAndContext = () => {
|
|||
// return default OTEL context and trace if faro is not initialized
|
||||
return faro.api.getOTEL() || { trace, context };
|
||||
};
|
||||
|
||||
export { faro };
|
||||
|
|
|
|||
21
app/client/src/instrumentation/sendFaroErrors.ts
Normal file
21
app/client/src/instrumentation/sendFaroErrors.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function captureException(exception: any, hint?: any): string {
|
||||
const eventId = uuidv4();
|
||||
const context = hint || {};
|
||||
|
||||
try {
|
||||
window.faro?.api.pushError(
|
||||
exception instanceof Error ? exception : new Error(String(exception)),
|
||||
{ type: "error", context: context },
|
||||
);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return eventId;
|
||||
}
|
||||
|
||||
export default captureException;
|
||||
|
|
@ -20,7 +20,6 @@ import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
|||
import { getCurrentUser } from "selectors/usersSelectors";
|
||||
import type { User } from "constants/userConstants";
|
||||
import RequestConfirmationModal from "pages/Editor/RequestConfirmationModal";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { getTheme, ThemeMode } from "selectors/themeSelectors";
|
||||
import { ThemeProvider } from "styled-components";
|
||||
import type { Theme } from "constants/DefaultTheme";
|
||||
|
|
@ -222,6 +221,4 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||
};
|
||||
};
|
||||
|
||||
export default withRouter(
|
||||
connect(mapStateToProps, mapDispatchToProps)(Sentry.withProfiler(Editor)),
|
||||
);
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Editor));
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import {
|
|||
} from "selectors/appViewSelectors";
|
||||
import EditorContextProvider from "components/editorComponents/EditorContextProvider";
|
||||
import AppViewerPageContainer from "./AppViewerPageContainer";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import {
|
||||
getCurrentPageDescription,
|
||||
getIsAutoLayout,
|
||||
|
|
@ -259,4 +258,4 @@ function AppViewer(props: Props) {
|
|||
return <ThemeProvider theme={lightTheme}>{renderChildren()}</ThemeProvider>;
|
||||
}
|
||||
|
||||
export default withRouter(Sentry.withProfiler(AppViewer));
|
||||
export default withRouter(AppViewer);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import log from "loglevel";
|
||||
import React, { useCallback } from "react";
|
||||
import styled from "styled-components";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import type { CanvasWidgetStructure } from "WidgetProvider/constants";
|
||||
import useWidgetFocus from "utils/hooks/useWidgetFocus";
|
||||
|
|
@ -20,6 +19,7 @@ import { getAppThemeSettings } from "ee/selectors/applicationSelectors";
|
|||
import CodeModeTooltip from "pages/Editor/WidgetsEditor/components/CodeModeTooltip";
|
||||
import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors";
|
||||
import { focusWidget } from "actions/widgetActions";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
interface CanvasProps {
|
||||
widgetsStructure: CanvasWidgetStructure;
|
||||
|
|
@ -120,7 +120,7 @@ const Canvas = (props: CanvasProps) => {
|
|||
return renderChildren();
|
||||
} catch (error) {
|
||||
log.error("Error rendering DSL", error);
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "Canvas" });
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import React, { useRef } from "react";
|
||||
import {
|
||||
Button,
|
||||
|
|
@ -108,4 +107,4 @@ function ConversionButton() {
|
|||
|
||||
ConversionButton.displayName = "ConversionButton";
|
||||
|
||||
export default Sentry.withProfiler(ConversionButton);
|
||||
export default ConversionButton;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import React, { useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import type { AppState } from "ee/reducers";
|
||||
|
|
@ -130,4 +129,4 @@ export function SnapShotBannerCTA() {
|
|||
|
||||
SnapShotBannerCTA.displayName = "SnapShotBannerCTA";
|
||||
|
||||
export default Sentry.withProfiler(SnapShotBannerCTA);
|
||||
export default SnapShotBannerCTA;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
|
||||
import React from "react";
|
||||
import ConversionButton from "../CanvasLayoutConversion/ConversionButton";
|
||||
import styled from "styled-components";
|
||||
|
|
@ -47,4 +45,4 @@ export function CanvasPropertyPane() {
|
|||
|
||||
CanvasPropertyPane.displayName = "CanvasPropertyPane";
|
||||
|
||||
export default Sentry.withProfiler(CanvasPropertyPane);
|
||||
export default CanvasPropertyPane;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import React, { useCallback, useEffect } from "react";
|
|||
import EntityProperty from "./EntityProperty";
|
||||
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { AppState } from "ee/reducers";
|
||||
import classNames from "classnames";
|
||||
import styled from "styled-components";
|
||||
|
|
@ -177,4 +176,4 @@ export function EntityProperties() {
|
|||
);
|
||||
}
|
||||
|
||||
export default Sentry.withProfiler(EntityProperties);
|
||||
export default EntityProperties;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import React, { useMemo } from "react";
|
|||
import { useRouteMatch } from "react-router-dom";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import JsEditorForm from "./Form";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { getJSCollectionDataByBaseId } from "selectors/editorSelectors";
|
||||
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
||||
import Spinner from "components/editorComponents/Spinner";
|
||||
|
|
@ -12,6 +11,7 @@ import AppJSEditorContextMenu from "./AppJSEditorContextMenu";
|
|||
import { updateFunctionProperty } from "actions/jsPaneActions";
|
||||
import type { OnUpdateSettingsProps } from "./JSEditorToolbar";
|
||||
import { saveJSObjectName } from "actions/jsActionActions";
|
||||
|
||||
const LoadingContainer = styled(CenteredWrapper)`
|
||||
height: 50%;
|
||||
`;
|
||||
|
|
@ -67,4 +67,4 @@ function JSEditor() {
|
|||
return <EntityNotFoundPane />;
|
||||
}
|
||||
|
||||
export default Sentry.withProfiler(JSEditor);
|
||||
export default JSEditor;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import {
|
||||
createMessage,
|
||||
MULTI_SELECT_PROPERTY_PANE_MESSAGE,
|
||||
|
|
@ -57,4 +56,4 @@ function MultiSelectPropertyPane() {
|
|||
|
||||
MultiSelectPropertyPane.displayName = "MultiSelectPropertyPane";
|
||||
|
||||
export default Sentry.withProfiler(MultiSelectPropertyPane);
|
||||
export default MultiSelectPropertyPane;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { Collapse } from "@blueprintjs/core";
|
||||
|
|
@ -56,4 +55,4 @@ export function SettingSection(props: SettingSectionProps) {
|
|||
|
||||
SettingSection.displayName = "SettingSection";
|
||||
|
||||
export default Sentry.withProfiler(SettingSection);
|
||||
export default SettingSection;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { last } from "lodash";
|
||||
import classNames from "classnames";
|
||||
import styled from "styled-components";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import React, { useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
|
|
@ -246,4 +245,4 @@ export function ThemeCard(props: ThemeCard) {
|
|||
|
||||
ThemeCard.displayName = "ThemeCard";
|
||||
|
||||
export default Sentry.withProfiler(ThemeCard);
|
||||
export default ThemeCard;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { get, startCase } from "lodash";
|
|||
import { useDispatch, useSelector } from "react-redux";
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
import ThemeCard from "./ThemeCard";
|
||||
import { ThemeCard } from "./ThemeCard";
|
||||
import {
|
||||
AppThemingMode,
|
||||
getAppThemingStack,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React, { useMemo } from "react";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { last } from "lodash";
|
||||
|
||||
import ThemeEditor from "./ThemeEditor";
|
||||
|
|
@ -47,4 +46,4 @@ export function ThemePropertyPane() {
|
|||
|
||||
ThemePropertyPane.displayName = "ThemePropertyPane";
|
||||
|
||||
export default Sentry.withProfiler(ThemePropertyPane);
|
||||
export default ThemePropertyPane;
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ import Helmet from "react-helmet";
|
|||
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||
import { getHTMLPageTitle } from "ee/utils/BusinessFeatures/brandingPageHelpers";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import CsrfTokenInput from "pages/UserAuth/CsrfTokenInput";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import { getSafeErrorMessage } from "ee/constants/approvedErrorMessages";
|
||||
|
||||
const validate = (values: LoginFormValues, props: ValidateProps) => {
|
||||
|
|
@ -116,12 +116,7 @@ export function Login(props: LoginFormProps) {
|
|||
if (queryParams.get("error")) {
|
||||
errorMessage = queryParams.get("message") || queryParams.get("error") || "";
|
||||
showError = true;
|
||||
Sentry.captureException("Login failed", {
|
||||
level: "error",
|
||||
extra: {
|
||||
error: new Error(errorMessage),
|
||||
},
|
||||
});
|
||||
captureException(new Error(errorMessage), { errorName: "LoginError" });
|
||||
}
|
||||
|
||||
let loginURL = "/api/v1/" + LOGIN_SUBMIT_PATH;
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
|||
import { getHTMLPageTitle } from "ee/utils/BusinessFeatures/brandingPageHelpers";
|
||||
import log from "loglevel";
|
||||
import { SELF_HOSTING_DOC } from "constants/ThirdPartyConstants";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import CsrfTokenInput from "pages/UserAuth/CsrfTokenInput";
|
||||
import { useIsCloudBillingEnabled } from "hooks";
|
||||
import { isLoginHostname } from "utils/cloudBillingUtils";
|
||||
import { getIsAiAgentFlowEnabled } from "ee/selectors/aiAgentSelectors";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import { getSafeErrorMessage } from "ee/constants/approvedErrorMessages";
|
||||
|
||||
declare global {
|
||||
|
|
@ -145,11 +145,8 @@ export function SignUp(props: SignUpFormProps) {
|
|||
if (queryParams.get("error")) {
|
||||
errorMessage = queryParams.get("error") || "";
|
||||
showError = true;
|
||||
Sentry.captureException("Sign up failed", {
|
||||
level: "error",
|
||||
extra: {
|
||||
error: new Error(errorMessage),
|
||||
},
|
||||
captureException(new Error(errorMessage), {
|
||||
errorName: "SignUp",
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import React, { useEffect } from "react";
|
|||
import Container from "./Container";
|
||||
import type { RouteComponentProps } from "react-router-dom";
|
||||
import { Spinner } from "@appsmith/ads";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { EMAIL_VERIFICATION_PATH } from "ee/constants/ApiConstants";
|
||||
import { Redirect } from "react-router-dom";
|
||||
import { VerificationErrorType } from "./VerificationError";
|
||||
import CsrfTokenInput from "pages/UserAuth/CsrfTokenInput";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
const VerifyUser = (
|
||||
props: RouteComponentProps<{
|
||||
|
|
@ -24,7 +24,9 @@ const VerifyUser = (
|
|||
|
||||
useEffect(() => {
|
||||
if (!token || !email) {
|
||||
Sentry.captureMessage("User email verification link is damaged");
|
||||
captureException(new Error("User email verification link is damaged"), {
|
||||
errorName: "VerificationLinkDamaged",
|
||||
});
|
||||
}
|
||||
|
||||
const formElement: HTMLFormElement = document.getElementById(
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
|||
import { SubmissionError } from "redux-form";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import type { Dispatch } from "redux";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import UserApi from "ee/api/UserApi";
|
||||
import { toast } from "@appsmith/ads";
|
||||
import type { ApiResponse } from "../../api/ApiResponses";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export interface LoginFormValues {
|
||||
username?: string;
|
||||
|
|
@ -95,7 +95,9 @@ export const useResendEmailVerification = (
|
|||
if (!email) {
|
||||
const errorMessage = "Email not found for retry verification";
|
||||
|
||||
Sentry.captureMessage(errorMessage);
|
||||
captureException(new Error(errorMessage), {
|
||||
errorName: "EmailVerificationRetryError",
|
||||
});
|
||||
toast.show(errorMessage, { kind: "error" });
|
||||
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
|||
import { applyChange, type Diff } from "deep-diff";
|
||||
import type { DataTree } from "entities/DataTree/dataTreeTypes";
|
||||
import { createImmerReducer } from "utils/ReducerUtils";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export type EvaluatedTreeState = DataTree;
|
||||
|
||||
|
|
@ -32,7 +32,8 @@ const evaluatedTreeReducer = createImmerReducer(initialState, {
|
|||
|
||||
applyChange(state, undefined, update);
|
||||
} catch (e) {
|
||||
Sentry.captureException(e, {
|
||||
captureException(e, {
|
||||
errorName: "TreeReducer",
|
||||
extra: {
|
||||
update,
|
||||
updateLength: updates.length,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import {
|
|||
take,
|
||||
takeLatest,
|
||||
} from "redux-saga/effects";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import {
|
||||
clearActionResponse,
|
||||
executePageLoadActions,
|
||||
|
|
@ -170,6 +169,7 @@ import {
|
|||
selectGitOpsModalOpen,
|
||||
} from "selectors/gitModSelectors";
|
||||
import { createActionExecutionResponse } from "./PluginActionSagaUtils";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
interface FilePickerInstumentationObject {
|
||||
numberOfFiles: number;
|
||||
|
|
@ -989,11 +989,12 @@ function* executeOnPageLoadJSAction(pageAction: PageAction) {
|
|||
);
|
||||
|
||||
if (!collection) {
|
||||
Sentry.captureException(
|
||||
captureException(
|
||||
new Error(
|
||||
"Collection present in layoutOnLoadActions but no collection exists ",
|
||||
),
|
||||
{
|
||||
errorName: "MissingJSCollection",
|
||||
extra: {
|
||||
collectionId,
|
||||
actionId: pageAction.id,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ import {
|
|||
selectApplicationVersion,
|
||||
} from "selectors/editorSelectors";
|
||||
import { find } from "lodash";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import { getAllPageIdentities } from "./selectors";
|
||||
import type { SagaIterator } from "@redux-saga/types";
|
||||
import type { AxiosPromise } from "axios";
|
||||
|
|
@ -126,8 +126,8 @@ export function* fetchAppSelectedTheme(
|
|||
payload: response.data,
|
||||
});
|
||||
} else {
|
||||
Sentry.captureException("Unable to fetch the selected theme", {
|
||||
level: "fatal",
|
||||
captureException(new Error("Unable to fetch the selected theme"), {
|
||||
errorName: "ThemeFetchError",
|
||||
extra: {
|
||||
pageIdentities,
|
||||
applicationId,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import {
|
|||
} from "ee/constants/messages";
|
||||
import store from "store";
|
||||
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { getLoginUrl } from "ee/utils/adminSettingsHelpers";
|
||||
import type { PluginErrorDetails } from "api/ActionAPI";
|
||||
import showToast from "sagas/ToastSagas";
|
||||
|
|
@ -42,6 +41,7 @@ import AppsmithConsole from "../utils/AppsmithConsole";
|
|||
import type { SourceEntity } from "../entities/AppsmithConsole";
|
||||
import { getAppMode } from "ee/selectors/applicationSelectors";
|
||||
import { APP_MODE } from "../entities/App";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
const shouldShowToast = (action: string) => {
|
||||
return action in toastMessageErrorTypes;
|
||||
|
|
@ -298,7 +298,7 @@ export function* errorSaga(errorAction: ReduxAction<ErrorActionPayload>) {
|
|||
break;
|
||||
}
|
||||
case ErrorEffectTypes.LOG_TO_SENTRY: {
|
||||
yield call(Sentry.captureException, error);
|
||||
yield call(captureException, error, { errorName: "ErrorSagaError" });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import { get } from "lodash";
|
|||
import LOG_TYPE from "entities/AppsmithConsole/logtype";
|
||||
import { select } from "redux-saga/effects";
|
||||
import AppsmithConsole from "utils/AppsmithConsole";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
||||
import {
|
||||
createMessage,
|
||||
|
|
@ -232,7 +232,8 @@ export function* evalErrorHandler(
|
|||
|
||||
if (error.context.logToSentry) {
|
||||
// Send the generic error message to sentry for better grouping
|
||||
Sentry.captureException(new Error(error.message), {
|
||||
captureException(new Error(error.message), {
|
||||
errorName: "CyclicalDependencyError",
|
||||
tags: {
|
||||
node,
|
||||
entityType,
|
||||
|
|
@ -264,22 +265,23 @@ export function* evalErrorHandler(
|
|||
kind: "error",
|
||||
});
|
||||
log.error(error);
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "EvalTreeError" });
|
||||
break;
|
||||
}
|
||||
case EvalErrorTypes.BAD_UNEVAL_TREE_ERROR: {
|
||||
log.error(error);
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "BadUnevalTreeError" });
|
||||
break;
|
||||
}
|
||||
case EvalErrorTypes.EVAL_PROPERTY_ERROR: {
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "EvalPropertyError" });
|
||||
log.error(error);
|
||||
break;
|
||||
}
|
||||
case EvalErrorTypes.CLONE_ERROR: {
|
||||
log.debug(error);
|
||||
Sentry.captureException(new Error(error.message), {
|
||||
captureException(new Error(error.message), {
|
||||
errorName: "CloneError",
|
||||
extra: {
|
||||
request: error.context,
|
||||
},
|
||||
|
|
@ -294,18 +296,22 @@ export function* evalErrorHandler(
|
|||
text: `${error.message} at: ${error.context?.propertyPath}`,
|
||||
});
|
||||
log.error(error);
|
||||
Sentry.captureException(error);
|
||||
captureException(error, {
|
||||
errorName: "ParseJSError",
|
||||
entity: error.context,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case EvalErrorTypes.EXTRACT_DEPENDENCY_ERROR: {
|
||||
Sentry.captureException(new Error(error.message), {
|
||||
captureException(new Error(error.message), {
|
||||
errorName: "ExtractDependencyError",
|
||||
extra: error.context,
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
log.error(error);
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "UnknownEvalError" });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import { PropertyEvaluationErrorType } from "utils/DynamicBindingUtils";
|
|||
import { EVAL_WORKER_ACTIONS } from "ee/workers/Evaluation/evalWorkerActions";
|
||||
import log from "loglevel";
|
||||
import type { WidgetProps } from "widgets/BaseWidget";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { Action } from "redux";
|
||||
import {
|
||||
EVAL_AND_LINT_REDUX_ACTIONS,
|
||||
|
|
@ -123,6 +122,7 @@ import type {
|
|||
AffectedJSObjects,
|
||||
EvaluationReduxAction,
|
||||
} from "actions/EvaluationReduxActionTypes";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
const APPSMITH_CONFIGS = getAppsmithConfigs();
|
||||
|
||||
|
|
@ -932,7 +932,7 @@ export function* evaluateActionSelectorFieldSaga(action: any) {
|
|||
);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "EvaluationError" });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1003,7 +1003,7 @@ export default function* evaluationSagaListeners() {
|
|||
yield call(evaluationChangeListenerSaga);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "EvaluationError" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
import type { ReduxAction } from "actions/ReduxActionTypes";
|
||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
import log from "loglevel";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import { getFormEvaluationState } from "selectors/formSelectors";
|
||||
import { evalFormConfig } from "./EvaluationsSaga";
|
||||
import type {
|
||||
|
|
@ -372,7 +372,7 @@ export default function* formEvaluationChangeListener() {
|
|||
yield call(formEvaluationChangeListenerSaga);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "FormEvaluationError" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
|||
import { resetApplicationWidgets, resetPageList } from "actions/pageActions";
|
||||
import { resetCurrentApplication } from "ee/actions/applicationActions";
|
||||
import log from "loglevel";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { resetRecentEntities } from "actions/globalSearchActions";
|
||||
|
||||
import {
|
||||
|
|
@ -93,6 +92,7 @@ import type { ApplicationPayload } from "entities/Application";
|
|||
import type { Page } from "entities/Page";
|
||||
import type { PACKAGE_PULL_STATUS } from "ee/constants/ModuleConstants";
|
||||
import { validateSessionToken } from "utils/SessionUtils";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export const URL_CHANGE_ACTIONS = [
|
||||
ReduxActionTypes.CURRENT_APPLICATION_NAME_UPDATE,
|
||||
|
|
@ -278,10 +278,12 @@ export function* getInitResponses({
|
|||
ReduxActionTypes.END_CONSOLIDATED_PAGE_LOAD,
|
||||
shouldInitialiseUserDetails,
|
||||
);
|
||||
Sentry.captureMessage(
|
||||
`consolidated api failure for ${JSON.stringify(
|
||||
params,
|
||||
)} errored message response ${e}`,
|
||||
captureException(
|
||||
new Error(`consolidated api failure for ${JSON.stringify(params)}`),
|
||||
{
|
||||
errorName: "ConsolidatedApiError",
|
||||
extra: { error: e },
|
||||
},
|
||||
);
|
||||
throw new PageNotFoundError(`Cannot find page with base id: ${basePageId}`);
|
||||
}
|
||||
|
|
@ -372,7 +374,7 @@ export function* startAppEngine(action: ReduxAction<AppEnginePayload>) {
|
|||
|
||||
if (e instanceof AppEngineApiError) return;
|
||||
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "AppEngineError" });
|
||||
yield put(safeCrashAppRequest());
|
||||
} finally {
|
||||
endSpan(rootSpan);
|
||||
|
|
@ -469,7 +471,7 @@ function* eagerPageInitSaga() {
|
|||
} catch (error) {
|
||||
// Log error but don't block the rest of the initialization
|
||||
log.error("Error validating session token:", error);
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "SessionValidationError" });
|
||||
}
|
||||
|
||||
const url = window.location.pathname;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
takeLatest,
|
||||
} from "redux-saga/effects";
|
||||
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import log from "loglevel";
|
||||
|
||||
import {
|
||||
|
|
@ -132,7 +132,7 @@ export function* openPropertyPaneSaga(replay: any) {
|
|||
);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "OpenPropertyPaneError" });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ export function* postUndoRedoSaga(replay: any) {
|
|||
scrollWidgetIntoView(widgetIds[0]);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "PostUndoRedoError" });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +257,7 @@ export function* undoRedoSaga(action: ReduxAction<UndoRedoPayload>) {
|
|||
}
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "UndoRedoSagaError" });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import {
|
|||
ReduxActionTypes,
|
||||
} from "ee/constants/ReduxActionConstants";
|
||||
import log from "loglevel";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import { findLoadingEntities } from "utils/WidgetLoadingStateUtils";
|
||||
|
||||
const actionExecutionRequestActions = [
|
||||
|
|
@ -101,7 +101,7 @@ export default function* actionExecutionChangeListeners() {
|
|||
yield call(actionExecutionChangeListenerSaga);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "WidgetLoadingError" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import {
|
|||
createSnapshotSaga,
|
||||
deleteApplicationSnapshotSaga,
|
||||
} from "./SnapshotSagas";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import log from "loglevel";
|
||||
import { saveAllPagesSaga } from "ee/sagas/PageSagas";
|
||||
import { updateApplicationLayout } from "ee/actions/applicationActions";
|
||||
|
|
@ -27,6 +26,7 @@ import {
|
|||
import { updateApplicationLayoutType } from "./AutoLayoutUpdateSagas";
|
||||
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
||||
import { nestDSL } from "@shared/dsl";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
/**
|
||||
* This method is used to convert from auto-layout to fixed layout
|
||||
|
|
@ -214,7 +214,7 @@ function* logLayoutConversionErrorSaga() {
|
|||
(state: AppState) => state.ui.layoutConversion.conversionError,
|
||||
);
|
||||
|
||||
yield call(Sentry.captureException, error);
|
||||
yield call(captureException, error, { errorName: "LayoutConversionError" });
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,99 +1,24 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import { getAppsmithConfigs } from "ee/configs";
|
||||
import log from "loglevel";
|
||||
import { captureException } from "instrumentation/sendFaroErrors";
|
||||
import type { User } from "constants/userConstants";
|
||||
|
||||
class SentryUtil {
|
||||
class FaroUtil {
|
||||
static init() {
|
||||
const { sentry } = getAppsmithConfigs();
|
||||
|
||||
try {
|
||||
if (sentry.enabled && !window.Sentry) {
|
||||
window.Sentry = Sentry;
|
||||
Sentry.init({
|
||||
...sentry,
|
||||
beforeSend(event) {
|
||||
const exception = SentryUtil.extractSentryException(event);
|
||||
|
||||
if (exception?.type === "ChunkLoadError") {
|
||||
// Only log ChunkLoadErrors after the 2 retries
|
||||
if (!exception.value?.includes("failed after 2 retries")) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Non-Error rejections
|
||||
if (exception?.value?.startsWith("Non-Error")) {
|
||||
// TODO: Fix this the next time the file is edited
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const serializedData: any = event.extra?.__serialized__;
|
||||
|
||||
if (!serializedData) return null; // if no data is attached, ignore error
|
||||
|
||||
const actualErrorMessage = serializedData.error
|
||||
? serializedData.error.message
|
||||
: serializedData.message;
|
||||
|
||||
if (!actualErrorMessage) return null; // If no message is attached, ignore error
|
||||
|
||||
// Now modify the original error
|
||||
exception.value = actualErrorMessage;
|
||||
event.message = actualErrorMessage;
|
||||
}
|
||||
|
||||
return event;
|
||||
},
|
||||
beforeBreadcrumb(breadcrumb) {
|
||||
if (
|
||||
breadcrumb.category === "console" &&
|
||||
breadcrumb.level !== "error"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (breadcrumb.category === "sentry.transaction") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (breadcrumb.category === "redux.action") {
|
||||
if (
|
||||
breadcrumb.data &&
|
||||
breadcrumb.data.type === "SET_EVALUATED_TREE"
|
||||
) {
|
||||
breadcrumb.data = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return breadcrumb;
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
log.error("Failed to initialize Sentry:", error);
|
||||
}
|
||||
// No initialization needed
|
||||
}
|
||||
|
||||
public static identifyUser(userId: string, userData: User) {
|
||||
const { sentry } = getAppsmithConfigs();
|
||||
|
||||
if (sentry.enabled) {
|
||||
Sentry.configureScope(function (scope) {
|
||||
scope.setUser({
|
||||
id: userId,
|
||||
username: userData.username,
|
||||
email: userData.email,
|
||||
});
|
||||
});
|
||||
}
|
||||
// Set user context for error reporting
|
||||
window.faro?.api.setUser({
|
||||
id: userId,
|
||||
username: userData.username,
|
||||
email: userData.email,
|
||||
});
|
||||
}
|
||||
|
||||
private static extractSentryException(event: Sentry.Event) {
|
||||
if (!event.exception) return null;
|
||||
|
||||
const value = event.exception.values ? event.exception.values[0] : null;
|
||||
|
||||
return value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public static captureException(error: Error, context?: any) {
|
||||
captureException(error, context);
|
||||
}
|
||||
}
|
||||
|
||||
export default SentryUtil;
|
||||
export default FaroUtil;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
//Following function is the fix for the missing where key
|
||||
/**
|
||||
|
|
@ -47,10 +47,13 @@ export function getPathAndValueFromActionDiffObject(actionObjectDiff: any) {
|
|||
|
||||
return acc;
|
||||
} catch (error) {
|
||||
Sentry.captureException({
|
||||
message: `Adding key: where failed, cannot create path`,
|
||||
oldData: actionObjectDiff,
|
||||
});
|
||||
captureException(
|
||||
{
|
||||
message: `Adding key: where failed, cannot create path`,
|
||||
oldData: actionObjectDiff,
|
||||
},
|
||||
{ errorName: "ActionDiffPathError" },
|
||||
);
|
||||
}
|
||||
},
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ import {
|
|||
concatWithArray,
|
||||
} from "./helpers";
|
||||
import WidgetFactory from "../WidgetProvider/factory";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { Colors } from "constants/Colors";
|
||||
import * as FaroErrors from "instrumentation/sendFaroErrors";
|
||||
|
||||
jest.mock("instrumentation/sendFaroErrors");
|
||||
|
||||
describe("flattenObject test", () => {
|
||||
it("Check if non nested object is returned correctly", () => {
|
||||
|
|
@ -202,6 +204,10 @@ describe("#getLocale", () => {
|
|||
});
|
||||
|
||||
describe("#captureInvalidDynamicBindingPath", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("DSL should not be altered", () => {
|
||||
const baseDSL = {
|
||||
widgetName: "RadioGroup1",
|
||||
|
|
@ -278,7 +284,6 @@ describe("#captureInvalidDynamicBindingPath", () => {
|
|||
helpText: "Sets a default selected option",
|
||||
propertyName: "defaultOptionValue",
|
||||
label: "Default selected value",
|
||||
// placeholderText: "Y",
|
||||
controlType: "INPUT_TEXT",
|
||||
isBindProperty: true,
|
||||
isTriggerProperty: false,
|
||||
|
|
@ -340,7 +345,6 @@ describe("#captureInvalidDynamicBindingPath", () => {
|
|||
label: "Animate loading",
|
||||
controlType: "SWITCH",
|
||||
helpText: "Controls the loading of the widget",
|
||||
// defaultValue: true,
|
||||
isJSConvertible: true,
|
||||
isBindProperty: true,
|
||||
isTriggerProperty: false,
|
||||
|
|
@ -449,7 +453,6 @@ describe("#captureInvalidDynamicBindingPath", () => {
|
|||
helpText: "Sets a default selected option",
|
||||
propertyName: "defaultOptionValue",
|
||||
label: "Default selected value",
|
||||
// placeholderText: "Y",
|
||||
controlType: "INPUT_TEXT",
|
||||
isBindProperty: true,
|
||||
isTriggerProperty: false,
|
||||
|
|
@ -511,7 +514,6 @@ describe("#captureInvalidDynamicBindingPath", () => {
|
|||
label: "Animate loading",
|
||||
controlType: "SWITCH",
|
||||
helpText: "Controls the loading of the widget",
|
||||
// defaultValue: true,
|
||||
isJSConvertible: true,
|
||||
isBindProperty: true,
|
||||
isTriggerProperty: false,
|
||||
|
|
@ -541,13 +543,18 @@ describe("#captureInvalidDynamicBindingPath", () => {
|
|||
},
|
||||
]);
|
||||
|
||||
const sentrySpy = jest.spyOn(Sentry, "captureException");
|
||||
const mockCaptureException = jest.fn();
|
||||
|
||||
(FaroErrors.captureException as jest.Mock).mockImplementation(
|
||||
mockCaptureException,
|
||||
);
|
||||
|
||||
captureInvalidDynamicBindingPath(baseDSL);
|
||||
expect(sentrySpy).toHaveBeenCalledWith(
|
||||
expect(mockCaptureException).toHaveBeenCalledWith(
|
||||
new Error(
|
||||
`INVALID_DynamicPathBinding_CLIENT_ERROR: Invalid dynamic path binding list: RadioGroup1.options`,
|
||||
),
|
||||
{ errorName: "InvalidDynamicPathBinding" },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import moment from "moment";
|
|||
import { isDynamicValue } from "./DynamicBindingUtils";
|
||||
import type { ApiResponse } from "api/ApiResponses";
|
||||
import type { DSLWidget } from "WidgetProvider/constants";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { matchPath } from "react-router";
|
||||
import {
|
||||
BUILDER_CUSTOM_PATH,
|
||||
|
|
@ -45,6 +44,7 @@ import { klona as klonaJson } from "klona/json";
|
|||
|
||||
import { startAndEndSpanForFn } from "instrumentation/generateTraces";
|
||||
import type { Property } from "entities/Action";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export const snapToGrid = (
|
||||
columnWidth: number,
|
||||
|
|
@ -944,10 +944,11 @@ export const captureInvalidDynamicBindingPath = (
|
|||
* Checks if dynamicBindingPathList contains a property path that doesn't have a binding
|
||||
*/
|
||||
if (!isDynamicValue(pathValue)) {
|
||||
Sentry.captureException(
|
||||
captureException(
|
||||
new Error(
|
||||
`INVALID_DynamicPathBinding_CLIENT_ERROR: Invalid dynamic path binding list: ${currentDSL.widgetName}.${dBindingPath.key}`,
|
||||
),
|
||||
{ errorName: "InvalidDynamicPathBinding" },
|
||||
);
|
||||
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import _ from "lodash";
|
|||
import derivedProperties from "./parsedDerivedProperties";
|
||||
import BaseInputWidget from "widgets/BaseInputWidget";
|
||||
import type { BaseInputWidgetProps } from "widgets/BaseInputWidget/widget";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import log from "loglevel";
|
||||
import {
|
||||
formatCurrencyNumber,
|
||||
|
|
@ -44,6 +43,7 @@ import { getDefaultCurrency } from "../component/CurrencyCodeDropdown";
|
|||
import IconSVG from "../icon.svg";
|
||||
import ThumbnailSVG from "../thumbnail.svg";
|
||||
import { WIDGET_TAGS } from "constants/WidgetConstants";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export function defaultValueValidation(
|
||||
// TODO: Fix this the next time the file is edited
|
||||
|
|
@ -499,7 +499,7 @@ class CurrencyInputWidget extends BaseInputWidget<
|
|||
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "CurrencyInputWidget" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -517,7 +517,7 @@ class CurrencyInputWidget extends BaseInputWidget<
|
|||
} catch (e) {
|
||||
formattedValue = value;
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "CurrencyInputWidget" });
|
||||
}
|
||||
|
||||
// text is stored as what user has typed
|
||||
|
|
@ -575,7 +575,7 @@ class CurrencyInputWidget extends BaseInputWidget<
|
|||
}
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "CurrencyInputWidget" });
|
||||
this.props.updateWidgetMetaProperty("text", this.props.text);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import React, { useCallback, useContext, useMemo, useState } from "react";
|
||||
|
||||
import type { BaseInputComponentProps } from "./BaseInputField";
|
||||
|
|
@ -15,6 +14,7 @@ import derived from "widgets/CurrencyInputWidget/widget/derived";
|
|||
import { isEmpty } from "../helper";
|
||||
import { BASE_LABEL_TEXT_SIZE } from "../component/FieldLabel";
|
||||
import { getLocaleDecimalSeperator } from "widgets/WidgetUtils";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
type CurrencyInputComponentProps = BaseInputComponentProps & {
|
||||
currencyCountryCode: string;
|
||||
|
|
@ -132,7 +132,7 @@ function CurrencyInputField({
|
|||
}
|
||||
} catch (e) {
|
||||
text = inputValue;
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "JSONFormWidget_CurrencyInputField" });
|
||||
}
|
||||
|
||||
const value = derived.value({ text });
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import { set } from "lodash";
|
||||
import type { ControllerProps } from "react-hook-form";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
|
|
@ -8,6 +7,7 @@ import FormContext from "../FormContext";
|
|||
import type { FieldType } from "../constants";
|
||||
import { startAndEndSpanForFn } from "instrumentation/generateTraces";
|
||||
import { klonaRegularWithTelemetry } from "utils/helpers";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export interface UseRegisterFieldValidityProps {
|
||||
isValid: boolean;
|
||||
|
|
@ -53,7 +53,9 @@ function useRegisterFieldValidity({
|
|||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Sentry.captureException(e);
|
||||
captureException(e, {
|
||||
errorName: "JSONFormWidget_useRegisterFieldValidity",
|
||||
});
|
||||
}
|
||||
}, 0);
|
||||
}, [isValid, fieldName, fieldType, error, clearErrors, setError]);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import countryDetails from "./countryDetails";
|
|||
import { MapTypes } from "../constants";
|
||||
import { geoAlbers, geoAzimuthalEqualArea, geoMercator } from "d3-geo";
|
||||
import log from "loglevel";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
import { retryPromise } from "utils/AppsmithUtils";
|
||||
|
||||
interface GeoSpecialAreas {
|
||||
|
|
@ -75,7 +75,9 @@ export const loadMapGenerator = () => {
|
|||
|
||||
if (error.code !== 20) {
|
||||
log.error({ error });
|
||||
Sentry.captureException(error);
|
||||
captureException(error, {
|
||||
errorName: "MapChartWidget_utilities",
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import type { BaseInputWidgetProps } from "widgets/BaseInputWidget/widget";
|
|||
import { mergeWidgetConfig } from "utils/helpers";
|
||||
import type { CountryCode } from "libphonenumber-js";
|
||||
import { AsYouType, parseIncompletePhoneNumber } from "libphonenumber-js";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import log from "loglevel";
|
||||
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
|
||||
import {
|
||||
|
|
@ -39,6 +38,7 @@ import { getDefaultISDCode } from "../component/ISDCodeDropdown";
|
|||
import IconSVG from "../icon.svg";
|
||||
import ThumbnailSVG from "../thumbnail.svg";
|
||||
import { WIDGET_TAGS } from "constants/WidgetConstants";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
export function defaultValueValidation(
|
||||
// TODO: Fix this the next time the file is edited
|
||||
|
|
@ -348,7 +348,7 @@ class PhoneInputWidget extends BaseInputWidget<
|
|||
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "PhoneInputWidget" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import {
|
|||
getLocaleThousandSeparator,
|
||||
} from "widgets/WidgetUtils";
|
||||
import { limitDecimalValue } from "widgets/CurrencyInputWidget/component/utilities";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { getLocale } from "utils/helpers";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
const FOCUS_CLASS = "has-focus";
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ export function InlineCellEditor({
|
|||
|
||||
value = convertToNumber(inputValue);
|
||||
} catch (e) {
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "TableWidgetV2_InlineCellEditor" });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import CurrencyTypeDropdown, {
|
|||
CurrencyDropdownOptions,
|
||||
} from "widgets/CurrencyInputWidget/component/CurrencyCodeDropdown";
|
||||
import { getLocale } from "utils/helpers";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { getLocaleThousandSeparator } from "widgets/WidgetUtils";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
const Container = styled.div<{
|
||||
isCellEditMode?: boolean;
|
||||
|
|
@ -227,7 +227,7 @@ function PlainTextCell(
|
|||
return currency?.id + " " + formattedValue;
|
||||
}
|
||||
} catch (e) {
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "TableWidgetV2_PlainTextCell" });
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import { ValidationTypes } from "constants/WidgetValidation";
|
|||
import { generateReactKey } from "utils/generators";
|
||||
import { EVAL_VALUE_PATH } from "utils/DynamicBindingUtils";
|
||||
import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { DSLWidget } from "WidgetProvider/constants";
|
||||
import { DATA_BIND_REGEX_GLOBAL } from "constants/BindingsConstants";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
function migrateTabsDataUsingMigrator(currentDSL: DSLWidget) {
|
||||
if (currentDSL.type === "TABS_WIDGET" && currentDSL.version === 1) {
|
||||
|
|
@ -20,7 +20,8 @@ function migrateTabsDataUsingMigrator(currentDSL: DSLWidget) {
|
|||
currentDSL.type = "TABS_MIGRATOR_WIDGET";
|
||||
currentDSL.version = 1;
|
||||
} catch (error) {
|
||||
Sentry.captureException({
|
||||
captureException(error, {
|
||||
errorName: "TabsMigrator",
|
||||
message: "Tabs Migration Failed",
|
||||
oldData: currentDSL.tabs,
|
||||
});
|
||||
|
|
@ -116,7 +117,8 @@ const migrateTabsData = (currentDSL: DSLWidget) => {
|
|||
currentDSL.version = 2;
|
||||
delete currentDSL.tabs;
|
||||
} catch (error) {
|
||||
Sentry.captureException({
|
||||
captureException(error, {
|
||||
errorName: "TabsMigrator",
|
||||
message: "Tabs Migration Failed",
|
||||
oldData: currentDSL.tabs,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import _ from "lodash";
|
||||
import React from "react";
|
||||
import log from "loglevel";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import type { WidgetState } from "widgets/BaseWidget";
|
||||
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
||||
|
||||
|
|
@ -30,6 +29,7 @@ import type { CurrencyInputWidgetProps } from "./types";
|
|||
import { WDSBaseInputWidget } from "widgets/wds/WDSBaseInputWidget";
|
||||
import { getCountryCodeFromCurrencyCode, validateInput } from "./helpers";
|
||||
import type { KeyDownEvent } from "widgets/wds/WDSBaseInputWidget/component/types";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
||||
CurrencyInputWidgetProps,
|
||||
|
|
@ -189,7 +189,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
|||
} catch (e) {
|
||||
formattedValue = value;
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "WDSCurrencyInputWidget" });
|
||||
}
|
||||
|
||||
this.props.updateWidgetMetaProperty("text", String(formattedValue));
|
||||
|
|
@ -248,7 +248,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
|||
}
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "WDSCurrencyInputWidget" });
|
||||
this.props.updateWidgetMetaProperty("text", this.props.text);
|
||||
}
|
||||
|
||||
|
|
@ -311,7 +311,7 @@ class WDSCurrencyInputWidget extends WDSBaseInputWidget<
|
|||
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "WDSCurrencyInputWidget" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React from "react";
|
||||
import log from "loglevel";
|
||||
import merge from "lodash/merge";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { klonaRegularWithTelemetry, mergeWidgetConfig } from "utils/helpers";
|
||||
import type { CountryCode } from "libphonenumber-js";
|
||||
import type { WidgetState } from "widgets/BaseWidget";
|
||||
|
|
@ -21,6 +20,7 @@ import * as config from "../config";
|
|||
import { PhoneInputComponent } from "../component";
|
||||
import type { PhoneInputWidgetProps } from "./types";
|
||||
import { getCountryCode, validateInput } from "./helpers";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
||||
PhoneInputWidgetProps,
|
||||
|
|
@ -163,7 +163,7 @@ class WDSPhoneInputWidget extends WDSBaseInputWidget<
|
|||
this.props.updateWidgetMetaProperty("text", formattedValue);
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
Sentry.captureException(e);
|
||||
captureException(e, { errorName: "WDSPhoneInputWidget" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import { get, isEmpty, toPath } from "lodash";
|
|||
import { APP_MODE } from "entities/App";
|
||||
import { isAction } from "ee/workers/Evaluation/evaluationUtils";
|
||||
import log from "loglevel";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { getMemberExpressionObjectFromProperty } from "@shared/ast";
|
||||
import captureException from "instrumentation/sendFaroErrors";
|
||||
|
||||
interface ErrorMetaData {
|
||||
userScript: string;
|
||||
|
|
@ -224,7 +224,7 @@ export function convertAllDataTypesToString(e: any) {
|
|||
return JSON.stringify(e);
|
||||
} catch (error) {
|
||||
log.debug(error);
|
||||
Sentry.captureException(error);
|
||||
captureException(error, { errorName: "ErrorModifier_StringifyError" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user