Skip to content

feat: create Segment analytics implementation + use geo-localization proxy (Batch 2 of 4)#7520

Merged
NicolasMassart merged 23 commits into
feat/batch_1129_segmentfrom
feat/1274_segment_prepare_metrics_system
Dec 6, 2023
Merged

feat: create Segment analytics implementation + use geo-localization proxy (Batch 2 of 4)#7520
NicolasMassart merged 23 commits into
feat/batch_1129_segmentfrom
feat/1274_segment_prepare_metrics_system

Conversation

@NicolasMassart

@NicolasMassart NicolasMassart commented Oct 17, 2023

Copy link
Copy Markdown
Contributor

Description

  1. What is the reason for the change?
  • Implement a new metrics system for the Segment SDK.
  • Make it work alongside the old one so that we can remove the old one progressively.
  1. What is the improvement/solution?
  • Create a new class to handle metrics with segment
  • abstract all segment SDK calls
  • provide our own user and anonymous Ids for improved privacy
  • Reuse the Mixpanel user id it available, otherwise generates a new one with the same format
  • patch Segment SDK to allow the privacy aware user and anonymous Ids
  • No event sent at all if user haven't accepted to send metrics info
  • Total reset of the infos in case user asks to reset (in settings)
  • Ability to disable all metrics
  • Ability to ask for deletion of all data

IMPORTANT

This PR contains a placeholder for the user metrics deletion request. This is to be implemented in a next PR in this batch but made fake here on purpose to prevent blocking this PR progress. See the following placeholder code and comment in this PR.

NOTE: We discussed splitting this PR to extract the SDK patch in its own PR. But I would like to first try in only one PR, first because it's not so big, just 11 files, we've seen worse, but mostly because looking at the patch without the context of the MetaMetrics class seems strange and more complicated to me and could lead to mistakes or questions that are answered by the Metametrics code itself.
However, if you believe I should absolutely make it in a separate PR, I will do it. Thanks.

Related issues

Fixes MetaMask/mobile-planning#1222

Manual testing steps

Only unit tests, manual testing will be available for next step in this batch of work.

Screenshots/Recordings

Bellow it no screenshot but the data received by Segment that we can see on the monitoring dev website.

image

Before

NA

After

Two event criteria:

  • events being anonymous because user is not yet identified
  • events being anonymous because even if user is identified we don't want to know
    Example of anonymous event because user is not identified:
{
  "context": {
    "library": {
      "name": "source-functions",
      "version": "1.0.0"
    },
    "location": {
      "api_processing_time_ms": 580,
      "country_code": "FR",
      "region": "NOR",
      "timezone": "Europe/Paris"
    }
  },
  "event": "183637normal anonymous event",
  "integrations": {},
  "messageId": "8f0e9b2e-a6ab-4b3f-922d-731932cce1a4",
  "originalTimestamp": "2023-11-16T17:36:45.43083525Z",
  "properties": {
    "applicationVersion": "7.10.0",
    "currentBuildNumber": "1187",
    "deviceBrand": "Apple",
    "operatingSystemVersion": "17.0.1",
    "platform": "ios"
  },
  "receivedAt": "2023-11-16T17:36:45.431Z",
  "sentAt": "2023-11-16T17:36:45.430Z",
  "timestamp": "2023-11-16T17:36:45.430Z",
  "type": "track",
  "userId": "0x0000000000000000",
  "writeKey": "REDACTED"
}

Example of anonymous event because user is not identified AND we don't want to know the details:

{
  "context": {
    "library": {
      "name": "source-functions",
      "version": "1.0.0"
    },
    "location": {
      "api_processing_time_ms": 580,
      "country_code": "FR",
      "region": "NOR",
      "timezone": "Europe/Paris"
    }
  },
  "event": "183637anonymous anonymous event",
  "integrations": {},
  "messageId": "daa2a578-4778-49fb-91d2-389c864fb5e5",
  "originalTimestamp": "2023-11-16T17:36:45.430876388Z",
  "properties": {},
  "receivedAt": "2023-11-16T17:36:45.431Z",
  "sentAt": "2023-11-16T17:36:45.430Z",
  "timestamp": "2023-11-16T17:36:45.430Z",
  "type": "track",
  "userId": "0x0000000000000000",
  "writeKey": "REDACTED"
}

Then the user can identify:

{
  "context": {
    "library": {
      "name": "source-functions",
      "version": "1.0.0"
    },
    "location": {
      "api_processing_time_ms": 0,
      "country_code": "FR",
      "region": "NOR",
      "timezone": "Europe/Paris"
    }
  },
  "integrations": {},
  "messageId": "72361f1f-3d8a-4b9a-97e1-7b01b457c4df",
  "originalTimestamp": "2023-11-16T17:37:13.309513172Z",
  "receivedAt": "2023-11-16T17:37:13.310Z",
  "sentAt": "2023-11-16T17:37:13.309Z",
  "timestamp": "2023-11-16T17:37:13.310Z",
  "traits": {
    "testtime": "183637"
  },
  "type": "identify",
  "userId": "0x7fb47bfe4e25c4e70097365f61838cfff275191e61f85262a51dc59fe52123de",
  "writeKey": "REDACTED"
}

and once identified, the events can still be sent anonymously or not depending if we have to know the details or not:

We know what but not who:

{
  "context": {
    "library": {
      "name": "source-functions",
      "version": "1.0.0"
    },
    "location": {
      "api_processing_time_ms": 0,
      "country_code": "FR",
      "region": "NOR",
      "timezone": "Europe/Paris"
    }
  },
  "event": "183637delayed identified anonymous event",
  "integrations": {},
  "messageId": "4031820c-e2b0-4bfa-ae47-ccdf77a54d64",
  "originalTimestamp": "2023-11-16T17:37:13.30954482Z",
  "properties": {
    "applicationVersion": "7.10.0",
    "currentBuildNumber": "1187",
    "deviceBrand": "Apple",
    "operatingSystemVersion": "17.0.1",
    "platform": "ios"
  },
  "receivedAt": "2023-11-16T17:37:13.310Z",
  "sentAt": "2023-11-16T17:37:13.309Z",
  "timestamp": "2023-11-16T17:37:13.310Z",
  "type": "track",
  "userId": "0x0000000000000000",
  "writeKey": "REDACTED"
}

or we know who but not what:

{
  "context": {
    "library": {
      "name": "source-functions",
      "version": "1.0.0"
    },
    "location": {
      "api_processing_time_ms": 0,
      "country_code": "FR",
      "region": "NOR",
      "timezone": "Europe/Paris"
    }
  },
  "event": "183637delayed identified anonymous event",
  "integrations": {},
  "messageId": "5076ef49-a852-4d23-8331-99ca81ee0e92",
  "originalTimestamp": "2023-11-16T17:37:13.309556282Z",
  "properties": {},
  "receivedAt": "2023-11-16T17:37:13.310Z",
  "sentAt": "2023-11-16T17:37:13.309Z",
  "timestamp": "2023-11-16T17:37:13.310Z",
  "type": "track",
  "userId": "0x7fb47bfe4e25c4e70097365f61838cfff275191e61f85262a51dc59fe52123de",
  "writeKey": "REDACTED"
}

Pre-merge author checklist

  • I’ve followed MetaMask Coding Standards.
  • I've clearly explained what problem this PR is solving and how it is solved.
  • I've linked related issues
  • I've included manual testing steps
  • I've included screenshots/recordings if applicable
  • I’ve included tests if applicable
  • I’ve documented my code using JSDoc format if applicable
  • I’ve applied the right labels on the PR (see labeling guidelines). Not required for external contributors.
  • I’ve properly set the pull request status:
    • In case it's not yet "ready for review", I've set it to "draft".
    • In case it's "ready for review", I've changed it from "draft" to "non-draft".

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

- update metrics class
- extract utils
- add tests
- patch Segment SDK to handle proxy required content type
and updated unit tests
@NicolasMassart NicolasMassart force-pushed the feat/1274_segment_prepare_metrics_system branch from 8209e95 to 6dd56d4 Compare November 10, 2023 16:19
@MetaMask MetaMask deleted a comment from socket-security Bot Nov 10, 2023
@MetaMask MetaMask deleted a comment from socket-security Bot Nov 10, 2023
@socket-security

socket-security Bot commented Nov 10, 2023

Copy link
Copy Markdown

Updated dependencies detected. Learn more about Socket for GitHub ↗︎

Packages Version New capabilities Transitives Size Publisher
react-native-get-random-values 1.8.0...1.9.0 None +0/-0 19.6 kB linusu
@segment/analytics-react-native 2.13.0...2.17.0 None +104/-2 5.15 MB oscb
@segment/sovran-react-native 0.4.5...1.0.4 None +0/-0 104 kB oscb

@socket-security

socket-security Bot commented Nov 10, 2023

Copy link
Copy Markdown

👍 Dependency issues cleared. Learn more about Socket for GitHub ↗︎

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

Ignoring: @segment/tsub@2.0.0, @stdlib/assert-has-tostringtag-support@0.0.9, @stdlib/assert-is-object-like@0.0.8, @stdlib/assert-is-regexp-string@0.0.9, @stdlib/assert-is-string@0.0.8, @stdlib/buffer-from-string@0.0.8, @stdlib/constants-float64-exponent-bias@0.0.8, @stdlib/constants-float64-high-word-exponent-mask@0.0.8, @stdlib/constants-float64-max-base2-exponent@0.0.8, @stdlib/constants-float64-max-base2-exponent-subnormal@0.0.8, @stdlib/constants-float64-min-base2-exponent-subnormal@0.0.8, @stdlib/constants-float64-ninf@0.0.8, @stdlib/constants-float64-pinf@0.0.8, @stdlib/constants-float64-smallest-normal@0.0.8, @stdlib/math-base-napi-unary@0.0.9, @stdlib/math-base-special-copysign@0.0.7, @stdlib/number-float64-base-to-float32@0.0.7, @stdlib/number-float64-base-to-words@0.0.7, @stdlib/regexp-regexp@0.0.8, @stdlib/string-lowercase@0.0.9, @stdlib/string-replace@0.0.11, @stdlib/utils-escape-regexp-string@0.0.9, @stdlib/utils-regexp-from-string@0.0.9

Next steps

Take a deeper look at the dependency

Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support [AT] socket [DOT] dev.

Remove the package

If you happen to install a dependency that Socket reports as Known Malware you should immediately remove it and select a different dependency. For other alert types, you may may wish to investigate alternative packages or consider if there are other ways to mitigate the specific risk posed by the dependency.

Mark a package as acceptable risk

To ignore an alert, reply with a comment starting with @SocketSecurity ignore followed by a space separated list of package-name@version specifiers. e.g. @SocketSecurity ignore foo@1.0.0 bar@* or ignore all packages with @SocketSecurity ignore-all

@NicolasMassart

Copy link
Copy Markdown
Contributor Author

@SocketSecurity ignore @segment/tsub@2.0.0

I verified the said commit and it's just a package version fix

@NicolasMassart NicolasMassart force-pushed the feat/1274_segment_prepare_metrics_system branch from fac08ff to 6b7f537 Compare November 15, 2023 22:20
@NicolasMassart NicolasMassart force-pushed the feat/1274_segment_prepare_metrics_system branch from 6b7f537 to ad17b38 Compare November 15, 2023 22:23
@NicolasMassart

Copy link
Copy Markdown
Contributor Author

@SocketSecurity ignore-all
only stdlib version bump

@codecov-commenter

codecov-commenter commented Nov 16, 2023

Copy link
Copy Markdown

Codecov Report

Attention: 4 lines in your changes are missing coverage. Please review.

Comparison is base (7b76904) 37.46% compared to head (78736ff) 36.80%.
Report is 10 commits behind head on feat/batch_1129_segment.

Files Patch % Lines
app/core/Analytics/MetaMetrics.ts 94.11% 1 Missing and 3 partials ⚠️
Additional details and impacted files
@@                     Coverage Diff                     @@
##           feat/batch_1129_segment    #7520      +/-   ##
===========================================================
- Coverage                    37.46%   36.80%   -0.67%     
===========================================================
  Files                         1052     1091      +39     
  Lines                        28202    29192     +990     
  Branches                      2517     2680     +163     
===========================================================
+ Hits                         10566    10743     +177     
- Misses                       17037    17839     +802     
- Partials                       599      610      +11     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@metamaskbot metamaskbot added the INVALID-PR-TEMPLATE PR's body doesn't match template label Nov 17, 2023
@NicolasMassart NicolasMassart force-pushed the feat/1274_segment_prepare_metrics_system branch from 91aeb75 to 1002dd5 Compare November 17, 2023 15:49
@NicolasMassart NicolasMassart force-pushed the feat/1274_segment_prepare_metrics_system branch from 1002dd5 to 854b506 Compare November 17, 2023 16:16
@NicolasMassart NicolasMassart marked this pull request as ready for review November 17, 2023 16:25
@NicolasMassart NicolasMassart added needs-dev-review PR needs reviews from other engineers (in order to receive required approvals) and removed Run Smoke E2E labels Nov 21, 2023
add tests
add delete date getter
@NicolasMassart NicolasMassart force-pushed the feat/1274_segment_prepare_metrics_system branch from 81db34f to 62ed6fa Compare November 21, 2023 15:29
Comment thread app/core/Analytics/MetaMetrics.ts
Comment thread ios/Podfile.lock
Comment thread ios/Podfile.lock Outdated
Comment thread ios/Podfile.lock
Comment thread patches/@segment+analytics-react-native+2.17.0.patch
Comment on lines +223 to +272
* TODO: this is a temporary placeholder implementation.
* This #createSegmentDeleteRegulation method is currently not testable
* because Segment delete endpoint proxy is not ready to use.
* The implementation is mock tested.
* Real work on this delete feature will be done in a next PR in this batch.
*/

/**
* generate a new delete regulation for the user.
* This is necessary to respect the GDPR and CCPA regulations.
* Check Segment documentation for more information.
* https://segment.com/docs/privacy/user-deletion-and-suppression/
*/
#createSegmentDeleteRegulation = async (): Promise<{
#createDeleteRegulation = async (): Promise<{
status: string;
error?: string;
}> => {
const segmentToken = process.env.SEGMENT_DELETION_API_KEY;
const regulationType = 'DELETE_ONLY';
try {
const response = await axios({
url: SEGMENT_REGULATIONS_ENDPOINT,
method: 'POST',
headers: {
'Content-Type': 'application/vnd.segment.v1alpha+json',
Authorization: `Bearer ${segmentToken}`,
},
data: JSON.stringify({
regulationType,
subjectType: 'USER_ID',
subjectIds: [this.#metametricsId],
}),
});
const { result, status } = response as any;

if (status === '200') {
const { regulateId } = result.data;
await this.#storeDeleteRegulationId(regulateId);
await this.#storeDeleteRegulationCreationDate();
return { status: DataDeleteResponseStatus.ok };
}

return { status: DataDeleteResponseStatus.error };
} catch (error: any) {
Logger.error(error, 'Analytics Deletion Task Error');
return { status: DataDeleteResponseStatus.error, error };
}
};

// PUBLIC METHODS
}> => ({
status: DataDeleteResponseStatus.error,
error: 'Analytics Deletion Task Error',
});
// => {
// const segmentToken = process.env.SEGMENT_DELETION_API_KEY;
// const regulationType = 'DELETE_ONLY';
// try {
// const response = await axios({
// url: SEGMENT_REGULATIONS_ENDPOINT,
// method: 'POST',
// headers: {
// 'Content-Type': 'application/vnd.segment.v1alpha+json',
// Authorization: `Bearer ${segmentToken}`,
// },
// data: JSON.stringify({
// regulationType,
// subjectType: 'USER_ID',
// subjectIds: [this.metametricsId],
// }),
// });
// const { data } = response as any;
// const { regulateId } = data;
// await this.#storeDeleteRegulationId(regulateId);
// await this.#storeDeleteRegulationCreationDate();
// return { status: DataDeleteResponseStatus.ok };
// } catch (error: any) {
// Logger.error(error, 'Analytics Deletion Task Error');
// return {
// status: DataDeleteResponseStatus.error,
// error: 'Analytics Deletion Task Error',
// };
// }
// };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In order to unblock this PR, this is to be implemented in another PR in the batch as we don't have the proxy yet.

Comment thread app/core/Analytics/MetaMetrics.ts
…_metrics_system

# Conflicts:
#	ios/Podfile.lock
@sonarqubecloud

sonarqubecloud Bot commented Dec 1, 2023

Copy link
Copy Markdown

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 2 Code Smells

90.1% 90.1% Coverage
0.0% 0.0% Duplication

@NicolasMassart NicolasMassart changed the title Feat: create Segment analytics implementation + use geo-localization proxy (Batch 2 of 3) Feat: create Segment analytics implementation + use geo-localization proxy (Batch 2 of 4) Dec 1, 2023
@NicolasMassart NicolasMassart changed the title Feat: create Segment analytics implementation + use geo-localization proxy (Batch 2 of 4) feat: create Segment analytics implementation + use geo-localization proxy (Batch 2 of 4) Dec 1, 2023
@MarioAslau MarioAslau self-requested a review December 3, 2023 22:18

@sethkfman sethkfman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@NicolasMassart NicolasMassart merged commit c047917 into feat/batch_1129_segment Dec 6, 2023
@NicolasMassart NicolasMassart deleted the feat/1274_segment_prepare_metrics_system branch December 6, 2023 10:14
@github-actions github-actions Bot locked and limited conversation to collaborators Dec 6, 2023
@github-actions github-actions Bot removed the needs-dev-review PR needs reviews from other engineers (in order to receive required approvals) label Dec 6, 2023
@metamaskbot metamaskbot added the needs-dev-review PR needs reviews from other engineers (in order to receive required approvals) label Dec 8, 2023
@gauthierpetetin gauthierpetetin added the team-mobile-platform Mobile Platform team label Feb 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

needs-dev-review PR needs reviews from other engineers (in order to receive required approvals) team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants