From e2f350cf66dd350abffb350dc8897980a633577a Mon Sep 17 00:00:00 2001 From: Jan-Erik Rediger Date: Thu, 8 Aug 2024 12:39:02 +0200 Subject: [PATCH] Kotlin: Dispatch metric recording for event, object and timing distribution on the task queue This allows us to delay executing those until Glean gets initialized and thus the core library is loaded. This is important for Fenix startup where we use `libxul` from Gecko, but want it to be loaded by GeckoView code before Glean accesses it. The three metric types for which this is currently implemented are the three metric types that are currently recorded early during Fenix' startup (by Nimbus). For the timing distribution this task dispatching is ONLY used for the `accumulate` methods. We can't do that for start/stop, because the timings are handled within glean-core. --- .../telemetry/glean/private/EventMetricType.kt | 16 ++++++++-------- .../telemetry/glean/private/ObjectMetricType.kt | 15 +++++++-------- .../private/TimingDistributionMetricType.kt | 16 +++++++++++++--- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/EventMetricType.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/EventMetricType.kt index 6baad436a1..1ded394224 100644 --- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/EventMetricType.kt +++ b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/EventMetricType.kt @@ -7,6 +7,7 @@ package mozilla.telemetry.glean.private import androidx.annotation.VisibleForTesting import mozilla.telemetry.glean.internal.EventMetric import mozilla.telemetry.glean.testing.ErrorType +import mozilla.telemetry.glean.Dispatchers /** * A class that can be converted into key-value pairs of event extras. @@ -42,14 +43,11 @@ class NoExtras : EventExtras { * The Events API only exposes the [record] method, which takes care of validating the input * data and making sure that limits are enforced. */ -class EventMetricType internal constructor( - private var inner: EventMetric, +class EventMetricType constructor( + private var meta: CommonMetricData, + private var allowedExtraKeys: List ) where ExtraObject : EventExtras { - /** - * The public constructor used by automatically generated metrics. - */ - constructor(meta: CommonMetricData, allowedExtraKeys: List) : - this(inner = EventMetric(meta, allowedExtraKeys)) + val inner: EventMetric by lazy { EventMetric(meta, allowedExtraKeys) } /** * Record an event by using the information provided by the instance of this class. @@ -63,7 +61,9 @@ class EventMetricType internal constructor( * If no `extra` data is passed the above function will be invoked correctly. */ fun record(extra: ExtraObject? = null) { - inner.record(extra?.toExtraRecord() ?: emptyMap()) + Dispatchers.Queue.launch { + inner.record(extra?.toExtraRecord() ?: emptyMap()) + } } /** diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/ObjectMetricType.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/ObjectMetricType.kt index 32362d84c0..86cb3b1873 100644 --- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/ObjectMetricType.kt +++ b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/ObjectMetricType.kt @@ -8,6 +8,7 @@ import androidx.annotation.VisibleForTesting import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import mozilla.telemetry.glean.internal.ObjectMetric +import mozilla.telemetry.glean.Dispatchers import mozilla.telemetry.glean.testing.ErrorType /** @@ -28,14 +29,10 @@ interface ObjectSerialize { * The object API only exposes the [set] method. * Only the associated object structure can be recorded. */ -class ObjectMetricType internal constructor( - private var inner: ObjectMetric, +class ObjectMetricType constructor( + private var meta: CommonMetricData ) where K : ObjectSerialize { - /** - * The public constructor used by automatically generated metrics. - */ - constructor(meta: CommonMetricData) : - this(inner = ObjectMetric(meta)) + val inner: ObjectMetric by lazy { ObjectMetric(meta) } /** * Sets to the associated structure. @@ -43,7 +40,9 @@ class ObjectMetricType internal constructor( * @param obj The object to set. */ fun set(obj: K) { - inner.setString(obj.intoSerializedObject()) + Dispatchers.Queue.launch { + inner.setString(obj.intoSerializedObject()) + } } /** diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/TimingDistributionMetricType.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/TimingDistributionMetricType.kt index c57de0a713..ae4fd6a68f 100644 --- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/TimingDistributionMetricType.kt +++ b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/TimingDistributionMetricType.kt @@ -8,6 +8,7 @@ import androidx.annotation.VisibleForTesting import mozilla.telemetry.glean.GleanTimerId import mozilla.telemetry.glean.internal.TimingDistributionMetric import mozilla.telemetry.glean.testing.ErrorType +import mozilla.telemetry.glean.Dispatchers /** * This implements the developer facing API for recording timing distribution metrics. @@ -16,7 +17,7 @@ import mozilla.telemetry.glean.testing.ErrorType * allowing developers to record values that were previously registered in the metrics.yaml file. */ class TimingDistributionMetricType(meta: CommonMetricData, timeUnit: TimeUnit) : HistogramBase { - val inner = TimingDistributionMetric(meta, timeUnit) + val inner: TimingDistributionMetric by lazy { TimingDistributionMetric(meta, timeUnit) } /** * Delegate common methods to the underlying type directly. @@ -30,8 +31,17 @@ class TimingDistributionMetricType(meta: CommonMetricData, timeUnit: TimeUnit) : * Additional functionality */ - fun accumulateSingleSample(sample: Long) = inner.accumulateSingleSample(sample) - override fun accumulateSamples(samples: List) = inner.accumulateSamples(samples) + fun accumulateSingleSample(sample: Long) { + Dispatchers.Queue.launch { + inner.accumulateSingleSample(sample) + } + } + + override fun accumulateSamples(samples: List) { + Dispatchers.Queue.launch { + inner.accumulateSamples(samples) + } + } /** * Convenience method to simplify measuring a function or block of code.