Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUMM-2172 Single Storage #932

Merged
merged 5 commits into from
May 17, 2022
Merged

Conversation

xgouchet
Copy link
Collaborator

What does this PR do?

Provide an implementation of the single storage mechanism for SDK v2

Additional Notes

Unit tests are globally not passing but all tests on the new classes are green ✅

@xgouchet xgouchet requested a review from a team as a code owner May 16, 2022 13:05
Copy link
Contributor

@0xnm 0xnm left a comment

Choose a reason for hiding this comment

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

Nicely done! I've added some thoughts/comments, but none of them are blocking for me.

fun currentMetadata(): ByteArray?

/**
* @param event the event to write
Copy link
Contributor

Choose a reason for hiding this comment

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

minor: missing descriptions of the method and newMetadata arguments

/**
* Holds information about the current local and server time.
* @property deviceTimeNs the current time as known by the System on the device (nanoseconds)
* @property serverTimeNs the current time synchronized with our NTP server(s) (nanoseconds)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @property serverTimeNs the current time synchronized with our NTP server(s) (nanoseconds)
* @property serverTimeNs the current time synchronized with Datadog NTP server(s) (nanoseconds)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

👍

),
ProcessInfo(forge.aBool(), forge.anInt()),
NetworkInfo(forge.aValueFrom(NetworkInfo.Connectivity::class.java), null),
UserInfo(null, null, null, emptyMap()),
Copy link
Contributor

Choose a reason for hiding this comment

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

should have nullable values forged

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes I know, I'll deal with those in a future PR (when those are actually needed)

assertThat(RumFeature.initialized.get()).isEqualTo(rumEnabled)
assertThat(WebViewLogsFeature.initialized.get()).isEqualTo(logsEnabled)
assertThat(WebViewRumFeature.initialized.get()).isEqualTo(rumEnabled)
// assertThat(CoreFeature.initialized.get()).isTrue()
Copy link
Contributor

Choose a reason for hiding this comment

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

I would propose to add a TODO at the beginning of this file and DatadogCoreTest as well saying we should handle those commented lines (unlikely we will forget, but still)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes good point

return
}

val file = orchestrator.getWritableFile(event.size)
Copy link
Contributor

Choose a reason for hiding this comment

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

thought: in this particular case callback is invoked synchronously, but in general API definition says it may be invoked in async manner, meaning that by the time it is invoked we may have other consent -> different orchestrator, not the one we captured for invocation. We need to be aware about that.

Copy link
Contributor

Choose a reason for hiding this comment

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

(...) by the time it is invoked we may have other consent -> different orchestrator, not the one we captured for invocation

Not sure if I understand this @0xnm 🤔💭. We get the orchestrator based on the immutable datadogContext passed as an parameter to writeCurrentBatch(). Then, any time later we receive a callback which provides us API (BatchWriter) to writing data. The write strategy will respect the consent value from datadogContext.

From the caller's POV, IMO everything should be consistent with this implementation: the caller orders write for given consent value and it knows that BatchWriter will respect it. No?

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean that generally the API contract is that this callback may be invoked in async manner (if I got it right). My point is that what if user changed a consent in the timeframe between the moment we received an orchestrator and the moment we use it in the BatchWriter. Then event may be written to the location which belongs to the old consent.

This is quite hypothetical case (and may be quite an edge case), but this gist of it is that imo we need to keep in mind the possible SDK state changes with async invocations.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is an edge case that is not something we want to dig into. The time frame for such a concurrency issue will on most case something smaller than 500ms, which is totally acceptable.

Copy link
Contributor

Choose a reason for hiding this comment

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

I get the point now @0xnm 👌. Agree, it's kind of edge case, but it can be clearly visible in such user situation:

// all synchronous, on a single thread:
Datadog.set(trackingConsent: .granted)
logger.info("granted log")
Datadog.set(trackingConsent: .pending)

In such case, the "granted log" should be sent by the SDK. This is however a question on how we will further synchronise things in higher implementation (even higher than Storage level). The RFC recommends processing all user calls through context thread first (see Threading in DDCore) to support exactly these edge cases.

Copy link
Contributor

@ncreated ncreated left a comment

Choose a reason for hiding this comment

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

Looks very good from the architecture POV 👍. I can see slight differences when comparing to RFC interfaces, but I believe these are Android / Kotlin specifics.

@xgouchet xgouchet force-pushed the xgouchet/RUMM-2172/single_storage branch from ddf1ba3 to 771eb8a Compare May 17, 2022 11:40
@xgouchet xgouchet merged commit 2304a33 into feature/sdkv2 May 17, 2022
@xgouchet xgouchet deleted the xgouchet/RUMM-2172/single_storage branch May 17, 2022 12:03
@xgouchet xgouchet added this to the 1.16.0 milestone Dec 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants