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

RUM-6129 Introduce the API usage telemetry event and API #2258

Merged

Conversation

mariusc83
Copy link
Member

@mariusc83 mariusc83 commented Sep 11, 2024

What does this PR do?

In this PR we are introducing the new InternalLogger#logApisUsage method which will be used to report usage of different APIs as Telemetry from our sdk. In order to achieve this we had to refactor and simplify the whole Telemetry related logic in the SDK to make it more scalable. For this we introduced the new InternalTelemetryEvent which will be shared through out all the module from the dd-sdk-android-internal module.

Motivation

What inspired you to submit this pull request?

Additional Notes

Anything else we should know when reviewing?

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

@mariusc83 mariusc83 self-assigned this Sep 11, 2024
@mariusc83 mariusc83 force-pushed the mconstantin/rum-6129/introduce-the-usagetelemetry-event branch 7 times, most recently from 9b196a9 to cefb3c2 Compare September 13, 2024 08:49
@mariusc83 mariusc83 marked this pull request as ready for review September 13, 2024 08:51
@mariusc83 mariusc83 requested review from a team as code owners September 13, 2024 08:51
@mariusc83 mariusc83 force-pushed the mconstantin/rum-6129/introduce-the-usagetelemetry-event branch from cefb3c2 to 94d452d Compare September 13, 2024 09:13
@codecov-commenter
Copy link

codecov-commenter commented Sep 13, 2024

Codecov Report

Attention: Patch coverage is 58.08824% with 57 lines in your changes missing coverage. Please review.

Project coverage is 69.90%. Comparing base (febadea) to head (531b346).
Report is 5 commits behind head on develop.

Files with missing lines Patch % Lines
...ndroid/telemetry/internal/TelemetryEventHandler.kt 40.32% 34 Missing and 3 partials ⚠️
...og/android/telemetry/internal/TelemetryEventExt.kt 0.00% 9 Missing ⚠️
.../main/kotlin/com/datadog/android/_InternalProxy.kt 76.92% 0 Missing and 3 partials ⚠️
...dog/android/telemetry/internal/TelemetryEventId.kt 72.73% 1 Missing and 2 partials ⚠️
...n/com/datadog/android/core/internal/DatadogCore.kt 75.00% 0 Missing and 2 partials ⚠️
.../android/core/internal/logger/SdkInternalLogger.kt 92.86% 0 Missing and 1 partial ⚠️
...lin/com/datadog/android/rum/internal/RumFeature.kt 90.00% 0 Missing and 1 partial ⚠️
.../android/rum/internal/monitor/DatadogRumMonitor.kt 66.67% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2258      +/-   ##
===========================================
- Coverage    70.06%   69.90%   -0.16%     
===========================================
  Files          730      727       -3     
  Lines        27181    27112      -69     
  Branches      4593     4572      -21     
===========================================
- Hits         19043    18950      -93     
- Misses        6845     6878      +33     
+ Partials      1293     1284       -9     
Files with missing lines Coverage Δ
...n/kotlin/com/datadog/android/api/InternalLogger.kt 100.00% <ø> (ø)
...ndroid/rum/internal/domain/event/RumEventMapper.kt 100.00% <100.00%> (ø)
...g/android/rum/internal/domain/scope/RumRawEvent.kt 100.00% <100.00%> (ø)
...atadog/android/telemetry/internal/TelemetryType.kt 100.00% <100.00%> (ø)
.../android/core/internal/logger/SdkInternalLogger.kt 88.17% <92.86%> (-4.76%) ⬇️
...lin/com/datadog/android/rum/internal/RumFeature.kt 93.52% <90.00%> (-0.08%) ⬇️
.../android/rum/internal/monitor/DatadogRumMonitor.kt 85.28% <66.67%> (-1.75%) ⬇️
...n/com/datadog/android/core/internal/DatadogCore.kt 82.19% <75.00%> (+0.29%) ⬆️
.../main/kotlin/com/datadog/android/_InternalProxy.kt 65.22% <76.92%> (+1.58%) ⬆️
...dog/android/telemetry/internal/TelemetryEventId.kt 80.00% <72.73%> (-20.00%) ⬇️
... and 2 more

... and 24 files with indirect coverage changes

@mariusc83 mariusc83 force-pushed the mconstantin/rum-6129/introduce-the-usagetelemetry-event branch from 94d452d to e2bd3f2 Compare September 13, 2024 09:37
message = message,
additionalProperties = null
)
rumFeature?.sendEvent(bundleEventIntoTelemetry(telemetryEvent))
Copy link
Member

Choose a reason for hiding this comment

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

Note

Since the event itself can be of type Any, you could avoid the Map<…> altogether and send the InternalTelemetryEvent directly. Same for all the methods in this class.

Copy link
Member Author

Choose a reason for hiding this comment

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

yes but then I will need an extra case in the onReceive of the RumFeature only for this so I would rather bundle it here.

batchUploadFrequency = configuration.coreConfig.uploadFrequency.baseStepMs,
batchProcessingLevel = configuration.coreConfig.batchProcessingLevel.maxBatchesPerUploadJob
)
rumFeature.sendEvent(
Copy link
Member

Choose a reason for hiding this comment

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

Warning

This is another argument to send the event InternalTelemetryEvent directly. Here you're not reusing the bundleEventIntoTelemetry() function you made, meaning that any further change around the telemetry would need to happen in two places, which is error prone.

Copy link
Member Author

Choose a reason for hiding this comment

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

hmmm actually I see your point also regarding the first comment. I don't know why I kept using the Map...we could just send the InternalTelemetryEvent everywhere

apiUsageEvent: InternalTelemetryEvent.ApiUsage,
samplingRate: Float
) {
println("AU [T]: ${apiUsageEvent::class.simpleName} | $samplingRate%")
Copy link
Member

@0xnm 0xnm Sep 16, 2024

Choose a reason for hiding this comment

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

Is it useful to log apiUsageEvent::class.simpleName if AU already stands for ApiUsage?

*/
@InternalApi
fun logApiUsage(
apiUsageEvent: InternalTelemetryEvent.ApiUsage,
Copy link
Member

Choose a reason for hiding this comment

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

won't it cause any issues if we are adding the class from implementation dependency to the class which is visible on the customer side via api dependency type? any compilation/IDE issues?

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't see any but will try to test it from the sample app

overwrite = forge.aBool(),
noView = forge.aBool(),
noActiveView = forge.aBool(),
additionalProperties = forge.aMap { forge.aString() to forge.aString() }.toMutableMap()
Copy link
Member

Choose a reason for hiding this comment

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

minor: calls like forge.aMap, etc. have a Forge as lambda receiver, so it can be written as forge.aMap { aString() to aString() }

public static final field Companion Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Companion;
public fun <init> (Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Dd;JLjava/lang/String;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Source;Ljava/lang/String;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Application;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Session;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$View;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Action;Ljava/util/List;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Telemetry;)V
public synthetic fun <init> (Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Dd;JLjava/lang/String;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Source;Ljava/lang/String;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Application;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Session;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$View;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Action;Ljava/util/List;Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Telemetry;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lcom/datadog/android/telemetry/model/CommonTelemetryProperties$Dd;
Copy link
Member

Choose a reason for hiding this comment

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

What bothers me is that by adding new data classes in our schema which have many params, we add so many useless destructuring methods which just grow binary footprint for nothing. Maybe there is a way to prevent them from being generated using some 3rd party plugins.

Copy link
Member Author

Choose a reason for hiding this comment

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

I am going to have a look for something but not going to spend too much on this

Copy link
Member

Choose a reason for hiding this comment

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

yes, it is a side thought, for sure shouldn't be a part of this PR.

@@ -15,10 +15,6 @@ tasks.register(
) {
inputDirPath = "src/main/json/telemetry"
targetPackageName = "com.datadog.android.telemetry.model"
ignoredFiles = arrayOf(
"_common-schema.json",
"usage-schema.json"
Copy link
Member

Choose a reason for hiding this comment

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

blocking: you need to remove only usage-schema.json from here. _common-schema is already referenced and being used by individual event schema files.

Copy link
Member Author

Choose a reason for hiding this comment

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

oh ok...thought it will need also the _common-schema as usage-schema is referencing it

@@ -298,6 +292,20 @@ internal class RumFeature(

// region Internal

private fun handleTelemetryEvent(event: Map<*, *>) {
Copy link
Member

Choose a reason for hiding this comment

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

probably with that change we can send class directly instead of using Map? It will require a change of the check right at the beginning of onReceive, but it is a minor thing.

Copy link
Member Author

Choose a reason for hiding this comment

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

yup exactly what @xgouchet was pointing out also, I am going to apply the changes now.

val onlyOnce: Boolean = false,
override val eventTime: Time = Time(),
val isMetric: Boolean = false
internal data class TelemetryEventWrapper(
Copy link
Member

Choose a reason for hiding this comment

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

we probably can keep the same name for the class - SendTelemetry. but not a big deal


else -> null
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we log here?

Copy link
Member Author

Choose a reason for hiding this comment

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

actually that's a sealed class so we don't really need the else here anyway. In case we do not treat a case we will be warned by the editor.

)
)
}
else -> null
Copy link
Member

@0xnm 0xnm Sep 16, 2024

Choose a reason for hiding this comment

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

we don't need else here I think, because we are using sealed class. So if we remove else here and add one more sub-type to InternalTelemetryEvent.ApiUsage, without adding additional branch in when, we will get a compilation error, which is for good.

Copy link
Member Author

Choose a reason for hiding this comment

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

yup it is exactly the case in line 117 also so you are right

@mariusc83 mariusc83 force-pushed the mconstantin/rum-6129/introduce-the-usagetelemetry-event branch from b76ea8a to 9475ffd Compare September 16, 2024 09:48
@mariusc83 mariusc83 requested review from 0xnm and xgouchet September 16, 2024 09:48
Copy link
Member

@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.

I added few comments/suggestions, but nothing blocking.

Comment on lines 262 to 271
!is Map<*, *> -> {
sdkCore.internalLogger.log(
InternalLogger.Level.WARN,
InternalLogger.Target.USER,
{ UNKNOWN_EVENT_TYPE_PROPERTY_VALUE.format(Locale.US, event["type"]) }
{ UNSUPPORTED_EVENT_TYPE.format(Locale.US, event::class.java.canonicalName) }
)
return
}

else -> when (event["type"]) {
Copy link
Member

Choose a reason for hiding this comment

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

I think it is better to swap these branches, and just do:

is Map<*, *> ->
else ->

reason: !is is harder to read and then in else it it takes some time to understand that type of the object there is Map.

@@ -656,8 +596,8 @@ internal class RumFeature(
internal const val LOG_ERROR_WITH_STACKTRACE_EVENT_MISSING_MANDATORY_FIELDS =
"RUM feature received a log event with stacktrace" +
" where mandatory message field is either missing or has a wrong type."
internal const val TELEMETRY_MISSING_MESSAGE_FIELD = "RUM feature received a telemetry" +
" event, but mandatory message field is either missing or has a wrong type."
internal const val TELEMETRY_MISSING_EVENT_FIELD_WARNING_MESSAGE = "RUM feature received a telemetry" +
Copy link
Member

Choose a reason for hiding this comment

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

is it still needed?

val telemetryEvent: Any? = when (event.type) {
TelemetryType.DEBUG -> {
val timestamp = wrappedEvent.eventTime.timestamp + datadogContext.time.serverTimeOffsetMs
val telemetryEvent: Any? = when (event) {
Copy link
Member

Choose a reason for hiding this comment

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

does it become exhaustive when? The reason why I'm asking it because there are 2 sealed classes involved here, not only one. Will it be a compilation error if we add say InternalTelemetry.Log.XXX into classes definition?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the way it behaves is that whenever you add a new type of the sealed class it will warn you that is not handled but will double check it.

Copy link
Member

Choose a reason for hiding this comment

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

yes, but you now have 2 sealed base classes in this hierarchy, not one, that is why I'm curious.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I confirm whenever you add a new type to that sealed class it is only to crash at compile time saying that you need to be exhaustive.

@mariusc83 mariusc83 force-pushed the mconstantin/rum-6129/introduce-the-usagetelemetry-event branch from 9475ffd to db9a4f1 Compare September 16, 2024 12:52
@mariusc83 mariusc83 requested a review from 0xnm September 16, 2024 12:53
@mariusc83 mariusc83 force-pushed the mconstantin/rum-6129/introduce-the-usagetelemetry-event branch from db9a4f1 to 531b346 Compare September 17, 2024 07:41
@mariusc83 mariusc83 merged commit 531effd into develop Sep 17, 2024
23 checks passed
@mariusc83 mariusc83 deleted the mconstantin/rum-6129/introduce-the-usagetelemetry-event branch September 17, 2024 09:37
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.

4 participants