Skip to content

chore: Add deviceType and appMode to new relic telemetry data#33735

Merged
rajatagrawal merged 7 commits intoreleasefrom
chore/add-attributes-telemetry
May 31, 2024
Merged

chore: Add deviceType and appMode to new relic telemetry data#33735
rajatagrawal merged 7 commits intoreleasefrom
chore/add-attributes-telemetry

Conversation

@dvj1988
Copy link

@dvj1988 dvj1988 commented May 27, 2024

Description

Add deviceType and appMode attributes to new relic spans related to evaluation

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.Sanity"

🔍 Cypress test results

Tip

🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/9297145435
Commit: 309d8ae
Cypress dashboard url: Click here!

Communication

Should the DevRel and Marketing teams inform users about this change?

  • Yes
  • No

@dvj1988 dvj1988 requested review from rajatagrawal and vsvamsi1 May 27, 2024 04:40
@github-actions github-actions bot added the skip-changelog Adding this label to a PR prevents it from being listed in the changelog label May 27, 2024
@dvj1988 dvj1988 self-assigned this May 27, 2024
@dvj1988 dvj1988 added ok-to-test Required label for CI and removed ok-to-test Required label for CI labels May 27, 2024
@dvj1988 dvj1988 marked this pull request as ready for review May 27, 2024 04:50
@dvj1988 dvj1988 requested a review from ApekshaBhosale as a code owner May 27, 2024 04:50
@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 27, 2024

Walkthrough

The updates primarily enhance telemetry functionality across various modules. These changes introduce common telemetry attributes, utilize SpanOptions for span creation, and add parameters like appMode and telemetryAttributes to functions and methods. The goal is to improve telemetry handling and data collection, ensuring more consistent and detailed tracing information.

Changes

Files Change Summary
app/client/src/UITelemetry/generateTraces.ts Added import for SpanOptions, introduced deviceType, defined getCommonTelemetryAttributes, updated startRootSpan and startNestedSpan to include common telemetry attributes, and used SpanOptions in startNestedSpan.
app/client/src/sagas/EvaluationsSaga.ts Added { appMode } parameter to the evaluateTreeSaga function call.
app/client/src/utils/WorkerUtil.ts Introduced Attributes for telemetry attributes in method signatures within GracefulWorkerService class, added telemetryAttributes parameter, and utilized it in method implementations.
app/client/src/workers/Evaluation/handlers/evalTree.ts Added appMode parameter to function calls within evalTree to distinguish between initialization and non-initialization phases.
app/client/src/workers/common/DataTreeEvaluator/index.ts Added telemetryAttributes parameter to various method calls for telemetry purposes, replaced undefined with telemetryAttributes in method calls.

Sequence Diagram(s) (Beta)

sequenceDiagram
    participant User
    participant UI
    participant Telemetry
    participant Worker
    participant Evaluator

    User->>UI: Interacts with UI
    UI->>Telemetry: startRootSpan(spanName, spanAttributes)
    Telemetry->>UI: Returns span
    UI->>Worker: Calls method with telemetryAttributes
    Worker->>Evaluator: Calls evaluateTree with appMode and telemetryAttributes
    Evaluator->>Telemetry: Logs telemetry data
    Evaluator->>Worker: Returns evaluation result
    Worker->>UI: Returns result
    UI->>User: Displays result
Loading

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Outside diff range and nitpick comments (16)
app/client/src/UITelemetry/generateTraces.ts (3)

10-10: Add a comment explaining why deviceType is imported from react-device-detect.

Adding a brief comment here about the purpose of importing deviceType can help maintain clarity, especially for new developers or those unfamiliar with the react-device-detect library.


Line range hint 46-67: Similar to the previous comment, add error handling for undefined tracer in startNestedSpan.

  const generatorTrace = trace.getTracer(GENERATOR_TRACE);
+ if (!generatorTrace) {
+   throw new Error("Generator Trace not found for GENERATOR_TRACE");
+ }
  if (!spanName || !parentSpan) {
    // do not generate nested span without parentSpan..we cannot generate context out of it
    return;
  }

Line range hint 81-81: Specify a type other than any for the function return type in wrapFnWithParentTraceContext.

- export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => any) {
+ export function wrapFnWithParentTraceContext<T>(parentSpan: Span, fn: () => T): T {
  const parentContext = trace.setSpan(context.active(), parentSpan);
  return context.with(parentContext, fn);
};

This change improves type safety by allowing the function to handle different return types explicitly.

app/client/src/utils/WorkerUtil.ts (3)

15-15: Add a comment explaining the purpose of importing Attributes from @opentelemetry/api.

A brief comment here about the purpose of importing Attributes can help maintain clarity, especially for new developers or those unfamiliar with the @opentelemetry/api library.


Line range hint 158-194: Refactor addChildSpansToRootSpan to handle potential undefined rootSpan more gracefully.

  if (!rootSpan) {
    return;
  }
  const webworkerTelemetryResponse = webworkerTelemetry as Record<
    string,
    WebworkerSpanData
  >;

This change ensures that the function exits early if rootSpan is undefined, preventing further execution and potential errors.


Line range hint 209-258: Ensure proper error handling and type safety in the request generator function.

  *request(
    method: string,
    data: Record<string, unknown> = {},
    telemetryAttributes: Attributes = {},
  ): Generator<any, any, any> {
    yield this.ready(true);
    if (!this._Worker) {
+     throw new Error("Worker is not initialized");
      return;
    }

Adding explicit error handling for an uninitialized worker enhances robustness and prevents silent failures.

app/client/src/workers/Evaluation/handlers/evalTree.ts (3)

Line range hint 146-197: Refactor to simplify the handling of appMode in various profile functions.

  const setupFirstTreeResponse = profileFn(
    "setupFirstTree",
    { description: "non-initialisation", appMode },
    webworkerTelemetry,
    () => dataTreeEvaluator?.setupFirstTree(unevalTree, configTree),
  );

This change ensures that appMode is consistently passed and handled, reducing the risk of errors due to missing or incorrect parameters.


Line range hint 256-311: Optimize the handling of appMode in diffAndGenerateSerializeUpdates to ensure consistency and correctness.

  const updates = profileFn(
    "diffAndGenerateSerializeUpdates",
    { appMode },
    webworkerTelemetry,
    () => {
      let updates;
      if (isNewTree) {
        try {
          updates = serialiseToBigInt([{ kind: "newTree", rhs: dataTree }]);
          dataTreeEvaluator?.setPrevState(dataTree);
        } catch (e) {
          updates = "[]";
        }
        isNewTree = false;
      } else {
        const allUnevalUpdates = unEvalUpdates.map(
          (update) => update.payload.propertyPath,
        );

This change ensures that appMode is consistently passed and handled, reducing the risk of errors due to missing or incorrect parameters.


[!TIP]
Codebase Verification

The search results show multiple instances of profileFn usage across different files. In the evalTree.ts file, appMode is consistently passed as an argument to profileFn. However, in the index.ts file within the DataTreeEvaluator directory, appMode is not explicitly passed in several instances.

  • Files and lines to review:
    • app/client/src/workers/common/DataTreeEvaluator/index.ts
      • Lines where profileFn is called without appMode:
        • Line 96: const parsedCollections = profileFn("SetupFirstTree.parseJSActions", undefined, webworkerTelemetry);
        • Line 102: const { dependencies, inverseDependencies } = profileFn("createDependencyMap", undefined, webworkerTelemetry);
        • Line 108: >[] = profileFn("SetupUpdateTree.Diff1", telemetryAttributes, webworkerTelemetry);
        • Line 114: const parsedCollections = profileFn("SetupUpdateTree.parseJSActions", telemetryAttributes, webworkerTelemetry);
        • Line 120: } = profileFn("updateDependencyMap", telemetryAttributes, webworkerTelemetry);
        • Line 126: const setupUpdateTreeOutput = profileFn("setupTree", telemetryAttributes, webworkerTelemetry);

Please ensure that appMode is passed correctly in these instances to maintain consistency and safety.

Analysis chain

Line range hint 99-114: Ensure that appMode is always passed correctly and handled safely in profileFn.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that `appMode` is always provided and valid.

# Test: Search for all usages of `profileFn` to ensure `appMode` is always passed.
rg --type typescript $'profileFn'

Length of output: 67



Script:

#!/bin/bash
# Description: Verify that `appMode` is always provided and valid.

# Test: Search for all usages of `profileFn` to ensure `appMode` is always passed.
rg --type ts 'profileFn'

Length of output: 1496



Script:

#!/bin/bash
# Description: Extract lines around each `profileFn` usage to inspect arguments.

# Extract lines around each `profileFn` usage in the relevant files.
rg --type ts 'profileFn' -A 3 -B 3

Length of output: 9913

app/client/src/workers/common/DataTreeEvaluator/index.ts (7)

136-136: Consider using a more specific import for Attributes to avoid potential conflicts with other libraries.


488-488: Ensure that telemetryAttributes are properly documented to clarify their usage within the method.


Line range hint 463-476: Consider replacing forEach with for...of for better performance and readability.

- Object.keys(unEvalJSCollection).forEach((update) => {
-   const updates = unEvalJSCollection[update];
-   if (!!unevalTree[update]) {
-     Object.keys(updates).forEach((key) => {
-       const data = get(unevalTree, `${update}.${key}.data`, undefined);
-       if (isJSObjectFunction(unevalTree, update, key, configTree)) {
-         set(unevalTree, `${update}.${key}`, new String(updates[key]));
-         set(unevalTree, `${update}.${key}.data`, data);
-       } else {
-         set(unevalTree, `${update}.${key}`, updates[key]);
-       }
-     });
-   }
- });
+ for (const update of Object.keys(unEvalJSCollection)) {
+   const updates = unEvalJSCollection[update];
+   if (unevalTree[update]) {
+     for (const key of Object.keys(updates)) {
+       const data = get(unevalTree, `${update}.${key}.data`, undefined);
+       if (isJSObjectFunction(unevalTree, update, key, configTree)) {
+         set(unevalTree, `${update}.${key}`, new String(updates[key]));
+         set(unevalTree, `${update}.${key}.data`, data);
+       } else {
+         set(unevalTree, `${update}.${key}`, updates[key]);
+       }
+     }
+   }
+ }

Line range hint 3-3: Avoid shadowing the global EvalError property. Consider renaming the local EvalError type to prevent potential conflicts.

- import type { EvalError } from "utils/DynamicBindingUtils";
+ import type { EvaluationError as EvalError } from "utils/DynamicBindingUtils";

Line range hint 175-175: Avoid using any type for better type safety. Specify a more explicit type or use generics if applicable.

Also applies to: 229-229, 485-485, 725-725, 1039-1039, 1343-1343


Line range hint 992-1000: This default parameter should follow the last required parameter or should be a required parameter to maintain consistency and avoid potential bugs.

- setupUpdateTree(unEvalTree: any, configTree: ConfigTree, webworkerTelemetry: Record<string, WebworkerSpanData> = {}, telemetryAttributes: Attributes = {})
+ setupUpdateTree(unEvalTree: any, configTree: ConfigTree, telemetryAttributes: Attributes = {}, webworkerTelemetry: Record<string, WebworkerSpanData> = {})

Line range hint 1298-1334: This else clause can be omitted because previous branches break early, simplifying the control flow.

- if (condition1) {
-   // code
- } else if (condition2) {
-   // code
- } else {
-   // code
- }
+ if (condition1) {
-   // code
- } else if (condition2) {
-   // code
- }

@dvj1988 dvj1988 removed the ok-to-test Required label for CI label May 27, 2024

const getCommonTelemetryAttributes = () => {
return {
deviceType,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please add appMode also as common telemetry attribute ?

Copy link
Author

@dvj1988 dvj1988 May 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved.

Copy link
Author

@dvj1988 dvj1988 May 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rajatagrawal The test cases were failing because the worker was trying to access the window.location object which is not available in the worker's scope.
This is happening because we are creating the root span inside the request method of the worker service and this makes it impossible to access the common attributes unless they are passed as an additional argument to the request method. I am reverting the code to the previous state for now.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Outside diff range and nitpick comments (1)
app/client/src/UITelemetry/generateTraces.ts (1)

Line range hint 94-94: Specify a more precise type than any.

Using any can lead to potential type safety issues. Specify a more precise type for better type checking.

- export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => any) {
+ export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => void) {

@dvj1988 dvj1988 requested review from rajatagrawal and vsvamsi1 May 27, 2024 11:24
@dvj1988 dvj1988 added ok-to-test Required label for CI and removed ok-to-test Required label for CI labels May 27, 2024
rajatagrawal
rajatagrawal previously approved these changes May 28, 2024
@dvj1988 dvj1988 added ok-to-test Required label for CI and removed ok-to-test Required label for CI labels May 28, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Outside diff range and nitpick comments (2)
app/client/src/UITelemetry/generateTraces.ts (2)

Line range hint 58-79: Optimize startNestedSpan by ensuring parentSpan is checked early.

The function startNestedSpan checks for parentSpan inside the function body. It's more efficient to check this at the beginning to avoid unnecessary operations:

export function startNestedSpan(
  spanName: string,
  parentSpan?: Span,
  spanAttributes: Attributes = {},
  startTime?: TimeTimeInput,
) {
+ if (!spanName || !parentSpan) {
+   return;
+ }
  ...
}

Line range hint 93-93: Specify a type instead of using any.

The function wrapFnWithParentTraceContext uses any for the return type of fn. Using any can lead to potential type safety issues. Specify a more appropriate type if possible:

- export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => any) {
+ export function wrapFnWithParentTraceContext<T>(parentSpan: Span, fn: () => T): T {
  ...
}

Comment on lines 17 to 18
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor getCommonTelemetryAttributes for better error handling.

The function getCommonTelemetryAttributes currently assumes that window.location will always be available, which might not be the case in all environments (e.g., server-side rendering or tests). Consider adding a guard clause to handle such scenarios:

const getCommonTelemetryAttributes = () => {
+ if (typeof window === 'undefined' || !window.location) {
+   return { deviceType: 'unknown', appMode: 'unknown' };
+ }
  const { pathname } = window.location;
  ...
};

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
const getCommonTelemetryAttributes = () => {
const { pathname } = window.location;
const appMode = isEditorPath(pathname)
? APP_MODE.EDIT
: isViewerPath(pathname)
? APP_MODE.PUBLISHED
: "";
return {
deviceType,
appMode,
};
};
const getCommonTelemetryAttributes = () => {
if (typeof window === 'undefined' || !window.location) {
return { deviceType: 'unknown', appMode: 'unknown' };
}
const { pathname } = window.location;
const appMode = isEditorPath(pathname)
? APP_MODE.EDIT
: isViewerPath(pathname)
? APP_MODE.PUBLISHED
: "";
return {
deviceType,
appMode,
};
};

Comment on lines 34 to 37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper error handling in startRootSpan.

The function startRootSpan uses optional chaining (tracer?.startSpan) which could lead to silent failures if tracer is undefined. It's better to handle this explicitly:

  const tracer = trace.getTracer(GENERATOR_TRACE);
+ if (!tracer) {
+   throw new Error('Tracer not found for GENERATOR_TRACE');
+ }
  if (!spanName) {
    return;
  }
  ...

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
spanAttributes: Attributes = {},
startTime?: TimeInput,
) {
const tracer = trace.getTracer(GENERATOR_TRACE);
if (!spanName) {
return;
}
const attributes = spanAttributes ?? { attributes: spanAttributes };
const startTimeAttr = startTime ? { startTime } : {};
const commonAttributes = getCommonTelemetryAttributes();
return tracer?.startSpan(spanName, {
kind: SpanKind.CLIENT,
...attributes,
...startTimeAttr,
attributes: {
...commonAttributes,
...spanAttributes,
},
startTime,
spanAttributes: Attributes = {},
startTime?: TimeInput,
) {
const tracer = trace.getTracer(GENERATOR_TRACE);
if (!tracer) {
throw new Error('Tracer not found for GENERATOR_TRACE');
}
if (!spanName) {
return;
}
const commonAttributes = getCommonTelemetryAttributes();
return tracer.startSpan(spanName, {
kind: SpanKind.CLIENT,
attributes: {
...commonAttributes,
...spanAttributes,
},
startTime,

@dvj1988
Copy link
Author

dvj1988 commented May 28, 2024

/build-deploy-preview skip-tests=true

1 similar comment
@dvj1988
Copy link
Author

dvj1988 commented May 28, 2024

/build-deploy-preview skip-tests=true

@github-actions
Copy link

Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/9268469276.
Workflow: On demand build Docker image and deploy preview.
skip-tests: true.
env: ``.
PR: 33735.
recreate: .

@github-actions
Copy link

Deploy-Preview-URL: https://ce-33735.dp.appsmith.com

@dvj1988
Copy link
Author

dvj1988 commented May 29, 2024

/build-deploy-preview skip-tests=true

@dvj1988 dvj1988 added ok-to-test Required label for CI and removed ok-to-test Required label for CI labels May 29, 2024
@github-actions
Copy link

Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/9289034182.
Workflow: On demand build Docker image and deploy preview.
skip-tests: true.
env: ``.
PR: 33735.
recreate: .

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Outside diff range and nitpick comments (1)
app/client/src/UITelemetry/generateTraces.ts (1)

Line range hint 95-95: Specify a more explicit type than any.

- export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => any) {
+ export function wrapFnWithParentTraceContext<T>(parentSpan: Span, fn: () => T): T {
  const parentContext = trace.setSpan(context.active(), parentSpan);
  return context.with(parentContext, fn);
}

@github-actions
Copy link

Deploy-Preview-URL: https://ce-33735.dp.appsmith.com

@dvj1988
Copy link
Author

dvj1988 commented May 29, 2024

/build-deploy-preview skip-tests=true

@github-actions
Copy link

Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/9289345647.
Workflow: On demand build Docker image and deploy preview.
skip-tests: true.
env: ``.
PR: 33735.
recreate: .

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Outside diff range and nitpick comments (1)
app/client/src/UITelemetry/generateTraces.ts (1)

Line range hint 95-95: Specify a more appropriate type instead of any.

- export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => any) {
+ export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => void) {

@github-actions
Copy link

Deploy-Preview-URL: https://ce-33735.dp.appsmith.com

@dvj1988 dvj1988 added ok-to-test Required label for CI and removed ok-to-test Required label for CI labels May 29, 2024
@dvj1988 dvj1988 added ok-to-test Required label for CI and removed ok-to-test Required label for CI labels May 30, 2024
@rajatagrawal rajatagrawal merged commit d880168 into release May 31, 2024
@rajatagrawal rajatagrawal deleted the chore/add-attributes-telemetry branch May 31, 2024 03:55
@coderabbitai coderabbitai bot mentioned this pull request Dec 24, 2024
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ok-to-test Required label for CI skip-changelog Adding this label to a PR prevents it from being listed in the changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants