Repository: parse-community/Parse-SDK-JS
Pull request #1594 (2022-11-03 04:15:10)

feat: Add option `Parse.nodeLogging` to fully log `Parse.Object` in Node.js environments
### New Pull Request Checklist
<!--
    Check every following box [x] before submitting your PR.
    Click the "Preview" tab for better readability.
    Thanks for contributing to Parse Platform!
-->

- [x] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [x] I am creating this PR in reference to an [issue](https://github.com/parse-community/Parse-SDK-JS/issues?q=is%3Aissue).

### Issue Description
<!-- Add a brief description of the issue this PR solves. -->

Currently, when logging a Parse.Object in NodeJS, the only thing that is logged is `ParseObject { _objCount: 376, className: 'Person' }`, which more often than not isn't overly helpful.

Related issue: `n/a`

### Approach
<!-- Add a description of the approach in this PR. -->

Adds `Parse.nodeLogging` which logs the object out to:

```
ParseObject: className: Person, id: undefined
Attributes: {
  "foo": "bar"
}
```

### TODOs before merging
<!--
    Add TODOs that need to be completed before merging this PR.
    Delete TODOs that do not apply to this PR.
-->

- [x] Add tests

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced a static property to enable or disable enhanced logging for objects in Node.js environments.
  - When logging is enabled, objects provide detailed, formatted output showing class name, object ID, and attributes for easier debugging.
- **Tests**
  - Added tests to verify the new logging property and the enhanced object output in Node.js.
- **Documentation**
  - Updated type declarations to include the new logging property with usage warnings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

parse-github-assistant[bot]: 
### Thanks for opening this pull request!

- ❌ Please link an issue that describes the reason for this pull request, otherwise your pull request will be closed. Make sure to write it as `Related issue: #123` in the PR description, so I can recognize it.

<!-- parse-issue-bot-meta-tag-id {"requireLinkedIssue":true} -->


mtrezza: Does this influence existing built-in log messages? If so, maybe this should be optional, because logging object attributes may expose sensitive data in the logs.
dblythy: Yes it does, that's why it defaults to `false` at the moment
mtrezza: Alright, maybe we can add a short warning note about that to the option docs.
dplewis: I normally use `query.find({ json: true })` or use log `object.toJSON()`
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/parse-community/Parse-SDK-JS/pull/1594?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`dcaccc2`)](https://app.codecov.io/gh/parse-community/Parse-SDK-JS/commit/dcaccc2a952f25b90d083e35065f9deebbe61ca2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) to head [(`cd7cf2e`)](https://app.codecov.io/gh/parse-community/Parse-SDK-JS/commit/cd7cf2efff490dc3c198a81095237a09a9233ebb?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##             alpha     #1594   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           64        64           
  Lines         6238      6245    +7     
  Branches      1466      1467    +1     
=========================================
+ Hits          6238      6245    +7     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/parse-community/Parse-SDK-JS/pull/1594?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
dplewis: > Does this influence existing built-in log messages?

The symbols are scoped locally per object and doesn't influence existing built in logs

@mtrezza This is ready for review
mtrezza: I believe I was referring to when using the Parse SDK in Cloud Code, whether that will output additional logs to the requester, which may expose information about the object, for example in case of an error.
mtrezza: Well, that's my question. @dblythy's answer above seems different from yours, hence I'm asking again.
coderabbitai[bot]: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->

> [!NOTE]
> Currently processing new changes in this PR. This may take a few minutes, please wait...
> 
> <details>
> <summary>📥 Commits</summary>
> 
> Reviewing files that changed from the base of the PR and between 38a2e8a11d6d1a6ca5f145c87948d34fb285cd55 and 48cc795e47a8a2b7c6172cc9f5f7211dd77a84b2.
> 
> </details>
> 
> <details>
> <summary>📒 Files selected for processing (6)</summary>
> 
> * `src/CoreManager.ts` (1 hunks)
> * `src/Parse.ts` (1 hunks)
> * `src/ParseObject.ts` (1 hunks)
> * `src/__tests__/Parse-test.js` (1 hunks)
> * `src/__tests__/ParseObject-test.js` (1 hunks)
> * `types/Parse.d.ts` (1 hunks)
> 
> </details>
> 
> ```ascii
>  __________________________________
> < Software is hard. - Donald Knuth >
>  ----------------------------------
>   \
>    \   \
>         \ /\
>         ( )
>       .( o ).
> ```

<!-- end of auto-generated comment: review in progress by coderabbit.ai -->
<!-- usage_tips_start -->

> [!TIP]
> <details>
> <summary>CodeRabbit can suggest fixes for GitHub Check annotations.</summary>
> 
> Configure `reviews.tools.github-checks` in your project's settings in CodeRabbit to adjust the time to wait for GitHub Checks to complete.
> 
> </details>

<!-- usage_tips_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=parse-community/Parse-SDK-JS&utm_content=1594):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `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 gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@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.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

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 using 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 generate sequence diagram` to generate a sequence diagram of the changes in this 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.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration 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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
mtrezza: I've added a note to the JSDoc of `set nodeLogging`, if that's fine, I'll go ahead and merge.
dplewis: LGTM!

Patch:
diff --git a/src/CoreManager.ts b/src/CoreManager.ts
index 03e2b60..cdf1f15 100644
--- a/src/CoreManager.ts
+++ b/src/CoreManager.ts
@@ -355,6 +355,7 @@ const config: Config & Record<string, any> = {
   IDEMPOTENCY: false,
   ALLOW_CUSTOM_OBJECT_ID: false,
   PARSE_ERRORS: [],
+  NODE_LOGGING: false,
 };
 
 function requireMethods(name: string, methods: string[], controller: any) {
diff --git a/src/Parse.ts b/src/Parse.ts
index 67e55b0..71f3f83 100644
--- a/src/Parse.ts
+++ b/src/Parse.ts
@@ -314,6 +314,28 @@ const Parse = {
     return CoreManager.get('ALLOW_CUSTOM_OBJECT_ID');
   },
 
+  /**
+   * Setting this property to `true` enables enhanced logging for `Parse.Object`
+   * in Node.js environments. Specifically, it will log:
+   *
+   * ```
+   * ParseObject: className: <CLASS_NAME>, id: <OBJECT_ID>
+   * Attributes: <OBJECT_ATTRIBUTES>
+   * ```
+   *
+   * @warning This should not be enabled in production environments as this may
+   * expose sensitive information in server logs.
+   *
+   * @property {boolean} Parse.nodeLogging
+   * @static
+   */
+  set nodeLogging(value) {
+    CoreManager.set('NODE_LOGGING', value);
+  },
+  get nodeLogging() {
+    return CoreManager.get('NODE_LOGGING');
+  },
+
   _request(...args) {
     return CoreManager.getRESTController().request.apply(null, args);
   },
diff --git a/src/ParseObject.ts b/src/ParseObject.ts
index 7979f7d..9ecb329 100644
--- a/src/ParseObject.ts
+++ b/src/ParseObject.ts
@@ -186,6 +186,13 @@ class ParseObject<T extends Attributes = Attributes> {
         throw new Error("Can't create an invalid Parse Object");
       }
     }
+    if (CoreManager.get('NODE_LOGGING')) {
+      this[Symbol.for('nodejs.util.inspect.custom')] = function () {
+        return `ParseObject: className: ${this.className}, id: ${
+          this.id
+        }\nAttributes: ${JSON.stringify(this.attributes, null, 2)}`;
+      };
+    }
   }
 
   /**
diff --git a/types/Parse.d.ts b/types/Parse.d.ts
index 8eb2830..b53d19e 100644
--- a/types/Parse.d.ts
+++ b/types/Parse.d.ts
@@ -322,6 +322,22 @@ declare const Parse: {
      * @static
      */
     allowCustomObjectId: any;
+    /**
+     * Setting this property to `true` enables enhanced logging for `Parse.Object`
+     * in Node.js environments. Specifically, it will log:
+     *
+     * ```
+     * ParseObject: className: <CLASS_NAME>, id: <OBJECT_ID>
+     * Attributes: <OBJECT_ATTRIBUTES>
+     * ```
+     *
+     * @warning This should not be enabled in production environments as this may
+     * expose sensitive information in server logs.
+     *
+     * @property {boolean} Parse.nodeLogging
+     * @static
+     */
+    nodeLogging: any;
     _request(...args: any[]): any;
     _ajax(...args: any[]): any;
     _decode(_: any, value: any): any;


Test patch:
diff --git a/src/__tests__/Parse-test.js b/src/__tests__/Parse-test.js
index 2709ff1..2476e1c 100644
--- a/src/__tests__/Parse-test.js
+++ b/src/__tests__/Parse-test.js
@@ -206,6 +206,13 @@ describe('Parse module', () => {
     Parse.allowCustomObjectId = false;
   });
 
+  it('can set nodeLogging', () => {
+    expect(Parse.nodeLogging).toBe(false);
+    Parse.nodeLogging = true;
+    expect(CoreManager.get('NODE_LOGGING')).toBe(true);
+    Parse.nodeLogging = false;
+  });
+
   it('getServerHealth', () => {
     const controller = {
       request: jest.fn(),
diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js
index 973878b..60f7cec 100644
--- a/src/__tests__/ParseObject-test.js
+++ b/src/__tests__/ParseObject-test.js
@@ -3532,4 +3532,14 @@ describe('ParseObject pin', () => {
     });
     CoreManager.set('ALLOW_CUSTOM_OBJECT_ID', false);
   });
+
+  it('can log an object', () => {
+    CoreManager.set('NODE_LOGGING', true);
+    const o = new ParseObject('Person', { foo: 'bar' });
+    const symbol = Symbol.for('nodejs.util.inspect.custom');
+    expect(o[symbol]()).toBe(
+      `ParseObject: className: Person, id: undefined\nAttributes: {\n  \"foo\": \"bar\"\n}`
+    );
+    CoreManager.set('NODE_LOGGING', false);
+  });
 });