@@ -399,10 +596,63 @@ in Rust where it's required. `None` or no argument will default to the first val
{{#include ../../../shared/tab_header.md}}
-
+
+```Kotlin
+import org.mozilla.yourApplication.GleanMetrics.Devtools
+
+// Usually you don't know the exact timing values,
+// but you do know how many samples there are:
+assertEquals(2, Devtools.ColdToolboxOpenDelay[toolboxId].testGetValue().count)
+
+// ...and the lower bound of how long they all took:
+assertTrue(400 <= Devtools.ColdToolboxOpenDelay[toolboxId].testGetValue().sum)
+```
+
+
+
+```Java
+import org.mozilla.yourApplication.GleanMetrics.Devtools;
+
+// Usually you don't know the exact timing values,
+// but you do know how many samples there are:
+assertEquals(2, Devtools.INSTANCE.ColdToolboxOpenDelay()[toolboxId].testGetValue().count);
+
+// ...and the lower bound of how long they all took:
+assertTrue(400 <= Devtools.INSTANCE.ColdToolboxOpenDelay()[toolboxId].testGetValue().sum);
+```
+
+
+
+```Swift
+import Glean
+
+// Usually you don't know the exact timing values,
+// but you do know how many samples there are:
+XCTAssertEqual(2, Devtools.ColdToolboxOpenDelay[toolboxId]).testGetValue().count)
+
+// ...and the lower bound of how long they all took:
+XCTAssertLessThanOrEqual(400, Devtools.ColdToolboxOpenDelay[toolboxId]).testGetValue().sum)
+```
+
+
+
+```Python
+from glean import load_metrics
+metrics = load_metrics("metrics.yaml")
+
+# Usually you don't know the exact timing values,
+# but you do know how many samples there are:
+assert 2 == metrics.devtools.cold_toolbox_open_delay[toolbox_id].test_get_value().count
+
+# ...and the lower bound of how long they all took:
+assert 400 <= metrics.devtools.cold_toolbox_open_delay[toolbox_id].test_get_value().sum
+```
+
+
```Rust
@@ -449,10 +699,47 @@ Gets the number of errors recorded for a given labeled timing distribution metri
{{#include ../../../shared/tab_header.md}}
-
-
-
-
+
+
+```Kotlin
+import org.mozilla.yourApplication.GleanMetrics.Devtools
+
+// Assert there were no negative values instrumented.
+assertEquals(0, Devtools.ColdToolboxOpenDelay.testGetNumRecordedErrors(ErrorType.INVALID_VALUE))
+```
+
+
+
+
+```Java
+import org.mozilla.yourApplication.GleanMetrics.Devtools;
+
+// Assert there were no negative values instrumented.
+assertEquals(0, Devtools.INSTANCE.ColdToolboxOpenDelay().testGetNumRecordedErrors(ErrorType.INVALID_VALUE));
+```
+
+
+
+
+```Swift
+import Glean
+
+// Assert there were no negative values instrumented.
+XCTAssertEqual(0, Devtools.ColdToolboxOpenDelay.testGetNumRecordedErrors(.invalidValue))
+```
+
+
+
+
+```Python
+from glean import load_metrics
+metrics = load_metrics("metrics.yaml")
+
+# Assert there were no negative values instrumented.
+assert 0 == metrics.devtools.cold_toolbox_open_delay.test_get_num_recorded_errors(ErrorType.INVALID_VALUE)
+```
+
+
```Rust
diff --git a/glean-core/Cargo.toml b/glean-core/Cargo.toml
index e973da9ecd..cccb711861 100644
--- a/glean-core/Cargo.toml
+++ b/glean-core/Cargo.toml
@@ -21,7 +21,7 @@ include = [
rust-version = "1.90"
[package.metadata.glean]
-glean-parser = "20.1.0"
+glean-parser = "21.0.1"
[badges]
circle-ci = { repository = "mozilla/glean", branch = "main" }
diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/Aliases.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/Aliases.kt
index e9314f8675..ad31eb3d41 100644
--- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/Aliases.kt
+++ b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/Aliases.kt
@@ -63,3 +63,18 @@ typealias LabeledMetricData = mozilla.telemetry.glean.internal.LabeledMetricData
* The set of data specifically needed to construct simple labeled metric types.
*/
typealias CommonLabeledMetricData = mozilla.telemetry.glean.internal.LabeledMetricData.Common
+
+/**
+ * The set of data specifically needed to construct labeled memory distribution metric types.
+ */
+typealias MemoryDistributionLabeledMetricData = mozilla.telemetry.glean.internal.LabeledMetricData.MemoryDistribution
+
+/**
+ * The set of data specifically needed to construct labeled timing distribution metric types.
+ */
+typealias TimingDistributionLabeledMetricData = mozilla.telemetry.glean.internal.LabeledMetricData.TimingDistribution
+
+/**
+ * The set of data specifically needed to construct labeled custom distribution metric types.
+ */
+typealias CustomDistributionLabeledMetricData = mozilla.telemetry.glean.internal.LabeledMetricData.CustomDistribution
diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/CustomDistributionMetricType.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/CustomDistributionMetricType.kt
index d5fa91648f..ae950181fc 100644
--- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/CustomDistributionMetricType.kt
+++ b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/CustomDistributionMetricType.kt
@@ -26,15 +26,23 @@ import mozilla.telemetry.glean.testing.ErrorType
* Instances of this class type are automatically generated by the parsers at build time,
* allowing developers to record values that were previously registered in the metrics.yaml file.
*/
-class CustomDistributionMetricType(
- meta: CommonMetricData,
- rangeMin: Long,
- rangeMax: Long,
- bucketCount: Long,
- histogramType: HistogramType,
-) : HistogramBase {
- val inner: CustomDistributionMetric by lazy {
- CustomDistributionMetric(meta, rangeMin, rangeMax, bucketCount, histogramType)
+class CustomDistributionMetricType : HistogramBase {
+ lateinit var inner: CustomDistributionMetric
+
+ constructor(
+ meta: CommonMetricData,
+ rangeMin: Long,
+ rangeMax: Long,
+ bucketCount: Long,
+ histogramType: HistogramType,
+ ) {
+ Dispatchers.Delayed.launch {
+ inner = CustomDistributionMetric(meta, rangeMin, rangeMax, bucketCount, histogramType)
+ }
+ }
+
+ constructor(metric: CustomDistributionMetric) {
+ inner = metric
}
/**
diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/LabeledMetricType.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/LabeledMetricType.kt
index 6538ff74aa..7714f5347a 100644
--- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/LabeledMetricType.kt
+++ b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/LabeledMetricType.kt
@@ -8,11 +8,14 @@ import androidx.annotation.VisibleForTesting
import mozilla.telemetry.glean.testing.ErrorType
import mozilla.telemetry.glean.internal.LabeledBoolean as InternalLabeledBoolean
import mozilla.telemetry.glean.internal.LabeledCounter as InternalLabeledCounter
+import mozilla.telemetry.glean.internal.LabeledCustomDistribution as InternalLabeledCustomDistribution
+import mozilla.telemetry.glean.internal.LabeledMemoryDistribution as InternalLabeledMemoryDistribution
import mozilla.telemetry.glean.internal.LabeledQuantity as InternalLabeledQuantity
import mozilla.telemetry.glean.internal.LabeledString as InternalLabeledString
+import mozilla.telemetry.glean.internal.LabeledTimingDistribution as InternalLabeledTimingDistribution
class LabeledBoolean constructor(
- meta: CommonLabeledMetricData,
+ meta: LabeledMetricData,
labels: List?,
) {
val metric = InternalLabeledBoolean(meta, labels)
@@ -21,7 +24,7 @@ class LabeledBoolean constructor(
}
class LabeledCounter constructor(
- meta: CommonLabeledMetricData,
+ meta: LabeledMetricData,
labels: List?,
) {
val metric = InternalLabeledCounter(meta, labels)
@@ -30,7 +33,7 @@ class LabeledCounter constructor(
}
class LabeledQuantity constructor(
- meta: CommonLabeledMetricData,
+ meta: LabeledMetricData,
labels: List?,
) {
val metric = InternalLabeledQuantity(meta, labels)
@@ -39,7 +42,7 @@ class LabeledQuantity constructor(
}
class LabeledString constructor(
- meta: CommonLabeledMetricData,
+ meta: LabeledMetricData,
labels: List?,
) {
val metric = InternalLabeledString(meta, labels)
@@ -47,6 +50,33 @@ class LabeledString constructor(
fun get(label: String): StringMetricType = StringMetricType(metric.get(label))
}
+class LabeledMemoryDistribution constructor(
+ meta: LabeledMetricData,
+ labels: List?,
+) {
+ val metric = InternalLabeledMemoryDistribution(meta, labels)
+
+ fun get(label: String): MemoryDistributionMetricType = MemoryDistributionMetricType(metric.get(label))
+}
+
+class LabeledTimingDistribution constructor(
+ meta: LabeledMetricData,
+ labels: List?,
+) {
+ val metric = InternalLabeledTimingDistribution(meta, labels)
+
+ fun get(label: String): TimingDistributionMetricType = TimingDistributionMetricType(metric.get(label))
+}
+
+class LabeledCustomDistribution constructor(
+ meta: LabeledMetricData,
+ labels: List?,
+) {
+ val metric = InternalLabeledCustomDistribution(meta, labels)
+
+ fun get(label: String): CustomDistributionMetricType = CustomDistributionMetricType(metric.get(label))
+}
+
/**
* This implements the developer facing API for labeled metrics.
*
@@ -61,33 +91,22 @@ class LabeledString constructor(
*/
@Suppress("LongParameterList")
class LabeledMetricType(
- private val disabled: Boolean,
- category: String,
- lifetime: Lifetime,
- name: String,
- private val labels: Set? = null,
- private val sendInPings: List,
+ private val meta: LabeledMetricData,
private val subMetric: T,
+ private val labels: Set? = null,
) {
// The inner labeled metric, from which actual metrics are constructed.
private val inner: Any
init {
- val meta = CommonLabeledMetricData(
- cmd = CommonMetricData(
- category = category,
- name = name,
- sendInPings = sendInPings,
- disabled = disabled,
- lifetime = lifetime,
- ),
- )
-
this.inner = when (subMetric) {
is CounterMetricType -> LabeledCounter(meta, labels?.toList())
is BooleanMetricType -> LabeledBoolean(meta, labels?.toList())
is StringMetricType -> LabeledString(meta, labels?.toList())
is QuantityMetricType -> LabeledQuantity(meta, labels?.toList())
+ is CustomDistributionMetricType -> LabeledCustomDistribution(meta, labels?.toList())
+ is MemoryDistributionMetricType -> LabeledMemoryDistribution(meta, labels?.toList())
+ is TimingDistributionMetricType -> LabeledTimingDistribution(meta, labels?.toList())
else -> error("Can not create a labeled version of this metric type")
}
}
@@ -116,6 +135,9 @@ class LabeledMetricType(
is LabeledBoolean -> this.inner.get(label) as T
is LabeledString -> this.inner.get(label) as T
is LabeledQuantity -> this.inner.get(label) as T
+ is LabeledCustomDistribution -> this.inner.get(label) as T
+ is LabeledMemoryDistribution -> this.inner.get(label) as T
+ is LabeledTimingDistribution -> this.inner.get(label) as T
else -> error("Can not create a labeled version of this metric type")
}
@@ -153,6 +175,9 @@ class LabeledMetricType(
is LabeledBoolean -> this.inner.metric.testGetNumRecordedErrors(errorType)
is LabeledString -> this.inner.metric.testGetNumRecordedErrors(errorType)
is LabeledQuantity -> this.inner.metric.testGetNumRecordedErrors(errorType)
+ is LabeledCustomDistribution -> this.inner.metric.testGetNumRecordedErrors(errorType)
+ is LabeledMemoryDistribution -> this.inner.metric.testGetNumRecordedErrors(errorType)
+ is LabeledTimingDistribution -> this.inner.metric.testGetNumRecordedErrors(errorType)
else -> error("Can not create a labeled version of this metric type")
}
@@ -173,6 +198,9 @@ class LabeledMetricType(
is LabeledCounter -> this.inner.metric.testGetValue(pingName)
is LabeledString -> this.inner.metric.testGetValue(pingName)
is LabeledQuantity -> this.inner.metric.testGetValue(pingName)
+ is LabeledCustomDistribution -> this.inner.metric.testGetValue(pingName)
+ is LabeledMemoryDistribution -> this.inner.metric.testGetValue(pingName)
+ is LabeledTimingDistribution -> this.inner.metric.testGetValue(pingName)
else -> error("Can not create a labeled version of this metric type")
}!!
}
diff --git a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/MemoryDistributionMetricType.kt b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/MemoryDistributionMetricType.kt
index f4ce088087..5894a33fb7 100644
--- a/glean-core/android/src/main/java/mozilla/telemetry/glean/private/MemoryDistributionMetricType.kt
+++ b/glean-core/android/src/main/java/mozilla/telemetry/glean/private/MemoryDistributionMetricType.kt
@@ -15,11 +15,18 @@ import mozilla.telemetry.glean.testing.ErrorType
* Instances of this class type are automatically generated by the parsers at build time,
* allowing developers to record values that were previously registered in the metrics.yaml file.
*/
-class MemoryDistributionMetricType(
- meta: CommonMetricData,
- memoryUnit: MemoryUnit,
-) : HistogramBase {
- val inner: MemoryDistributionMetric by lazy { MemoryDistributionMetric(meta, memoryUnit) }
+class MemoryDistributionMetricType : HistogramBase {
+ lateinit var inner: MemoryDistributionMetric
+
+ constructor(meta: CommonMetricData, memoryUnit: MemoryUnit) {
+ Dispatchers.Delayed.launch {
+ inner = MemoryDistributionMetric(meta, memoryUnit)
+ }
+ }
+
+ constructor(metric: MemoryDistributionMetric) {
+ inner = metric
+ }
/**
* Accumulates the provided sample in the metric.
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 29cb09eca4..559bae952a 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
@@ -16,11 +16,18 @@ import mozilla.telemetry.glean.testing.ErrorType
* Instances of this class type are automatically generated by the parsers at build time,
* allowing developers to record values that were previously registered in the metrics.yaml file.
*/
-class TimingDistributionMetricType(
- meta: CommonMetricData,
- timeUnit: TimeUnit,
-) : HistogramBase {
- val inner: TimingDistributionMetric by lazy { TimingDistributionMetric(meta, timeUnit) }
+class TimingDistributionMetricType : HistogramBase {
+ lateinit var inner: TimingDistributionMetric
+
+ constructor(meta: CommonMetricData, timeUnit: TimeUnit) {
+ Dispatchers.Delayed.launch {
+ inner = TimingDistributionMetric(meta, timeUnit)
+ }
+ }
+
+ constructor(metric: TimingDistributionMetric) {
+ inner = metric
+ }
/**
* Starts tracking time for the provided metric.
diff --git a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/AccumulationsBeforeGleanInitTest.kt b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/AccumulationsBeforeGleanInitTest.kt
index 8d838c4bbe..0918f06e23 100644
--- a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/AccumulationsBeforeGleanInitTest.kt
+++ b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/AccumulationsBeforeGleanInitTest.kt
@@ -60,11 +60,15 @@ class AccumulationsBeforeGleanInitTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "test.telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "pre_init_counter",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "test.telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "pre_init_counter",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
)
diff --git a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/LabeledMetricTypeTest.kt b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/LabeledMetricTypeTest.kt
index d94e1cedd0..f7e4840df2 100644
--- a/glean-core/android/src/test/java/mozilla/telemetry/glean/private/LabeledMetricTypeTest.kt
+++ b/glean-core/android/src/test/java/mozilla/telemetry/glean/private/LabeledMetricTypeTest.kt
@@ -36,11 +36,15 @@ class LabeledMetricTypeTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_counter_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_counter_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
)
@@ -70,11 +74,15 @@ class LabeledMetricTypeTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_counter_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_counter_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
labels = setOf("foo", "bar", "baz"),
)
@@ -106,11 +114,15 @@ class LabeledMetricTypeTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_counter_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_counter_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
)
@@ -140,11 +152,15 @@ class LabeledMetricTypeTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_counter_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_counter_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
)
@@ -180,11 +196,15 @@ class LabeledMetricTypeTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_counter_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_counter_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
)
@@ -233,11 +253,15 @@ class LabeledMetricTypeTest {
)
val labeledBooleanMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_boolean_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_boolean_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = booleanMetric,
)
@@ -286,11 +310,15 @@ class LabeledMetricTypeTest {
)
val labeledStringMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_string_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_string_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = stringMetric,
)
@@ -339,11 +367,15 @@ class LabeledMetricTypeTest {
)
val labeledStringMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_string_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_string_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = stringMetric,
)
@@ -367,11 +399,15 @@ class LabeledMetricTypeTest {
)
val labeledBooleanMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_boolean_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_boolean_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = booleanMetric,
)
@@ -395,11 +431,15 @@ class LabeledMetricTypeTest {
)
val labeledQuantityMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_quantity_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_quantity_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = quantityMetric,
)
@@ -424,11 +464,15 @@ class LabeledMetricTypeTest {
)
val labeledEventMetric = LabeledMetricType>(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_event_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_event_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = eventMetric,
)
@@ -451,11 +495,15 @@ class LabeledMetricTypeTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_counter_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_counter_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
labels = setOf("foo", "bar", "baz"),
)
@@ -493,11 +541,15 @@ class LabeledMetricTypeTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_nocrash",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_nocrash",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
labels = setOf("foo"),
)
@@ -525,11 +577,15 @@ class LabeledMetricTypeTest {
)
val labeledCounterMetric = LabeledMetricType(
- disabled = false,
- category = "telemetry",
- lifetime = Lifetime.APPLICATION,
- name = "labeled_counter_metric",
- sendInPings = listOf("metrics"),
+ CommonLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_counter_metric",
+ sendInPings = listOf("metrics"),
+ ),
+ ),
subMetric = counterMetric,
)
@@ -541,4 +597,39 @@ class LabeledMetricTypeTest {
assertEquals(1, values["label1"])
assertEquals(2, values["label2"])
}
+
+ @Test
+ fun `test labeled memory distribution`() {
+ val metric = MemoryDistributionMetricType(
+ CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.PING,
+ name = "memory_distribution",
+ sendInPings = listOf("store1"),
+ ),
+ memoryUnit = MemoryUnit.KILOBYTE,
+ )
+
+ val labeledMetric = LabeledMetricType(
+ MemoryDistributionLabeledMetricData(
+ cmd = CommonMetricData(
+ disabled = false,
+ category = "telemetry",
+ lifetime = Lifetime.APPLICATION,
+ name = "labeled_memory_distribution",
+ sendInPings = listOf("store1"),
+ ),
+ unit = MemoryUnit.KILOBYTE,
+ ),
+ subMetric = metric,
+ )
+
+ labeledMetric["label1"].accumulate(1)
+ labeledMetric["label2"].accumulate(2)
+
+ val kb = 1024
+ assertEquals(1L * kb, labeledMetric["label1"].testGetValue()!!.sum)
+ assertEquals(2L * kb, labeledMetric["label2"].testGetValue()!!.sum)
+ }
}
diff --git a/glean-core/build/Cargo.toml b/glean-core/build/Cargo.toml
index 23cb9e6018..dc913de982 100644
--- a/glean-core/build/Cargo.toml
+++ b/glean-core/build/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "glean-build"
-version = "20.1.0"
+version = "21.0.1"
edition = "2021"
description = "Glean SDK Rust build helper"
repository = "https://github.com/mozilla/glean"
diff --git a/glean-core/build/src/lib.rs b/glean-core/build/src/lib.rs
index 1be411d8c0..59bd8b7d22 100644
--- a/glean-core/build/src/lib.rs
+++ b/glean-core/build/src/lib.rs
@@ -39,7 +39,7 @@ use std::{env, path::PathBuf};
use xshell_venv::{Result, Shell, VirtualEnv};
-const GLEAN_PARSER_VERSION: &str = "20.1.0";
+const GLEAN_PARSER_VERSION: &str = "21.0.1";
/// A Glean Rust bindings generator.
pub struct Builder {
diff --git a/glean-core/ios/Glean/Metrics/LabeledMetric.swift b/glean-core/ios/Glean/Metrics/LabeledMetric.swift
index cfc9984b77..2a6f6dbca7 100644
--- a/glean-core/ios/Glean/Metrics/LabeledMetric.swift
+++ b/glean-core/ios/Glean/Metrics/LabeledMetric.swift
@@ -13,8 +13,6 @@
/// but records metrics for the underlying metric type `T` in the storage engine for that type.
/// The only difference is that labeled metrics are stored with the special key `$category.$name/$label`.
public final class LabeledMetricType: @unchecked Sendable {
- let disabled: Bool
- let sendInPings: [String]
let subMetric: T
let inner: AnyObject
@@ -24,38 +22,30 @@ public final class LabeledMetricType: @unchecked Sendable {
/// * `BooleanMetricType`
/// * `CounterMetricType`
/// * `StringMetricType`
- /// * `QuantityMetric`
+ /// * `QuantityMetricType`
+ /// * `LabeledCustomDistribution`
+ /// * `LabeledMemoryDistribution`
+ /// * `LabeledTimingDistribution`
///
/// Throws an exception when used with unsupported sub-metrics.
- public init(
- category: String,
- name: String,
- sendInPings: [String],
- lifetime: Lifetime,
- disabled: Bool,
- subMetric: T,
- labels: [String]? = nil
- ) throws {
- let meta = CommonMetricData(
- category: category,
- name: name,
- sendInPings: sendInPings,
- lifetime: lifetime,
- disabled: disabled
- )
- self.disabled = disabled
- self.sendInPings = sendInPings
+ public init(_ meta: LabeledMetricData, subMetric: T, labels: [String]? = nil) throws {
self.subMetric = subMetric
switch subMetric {
case is CounterMetricType:
- self.inner = LabeledCounter(.common(cmd: meta), labels)
+ self.inner = LabeledCounter(meta, labels)
case is BooleanMetricType:
- self.inner = LabeledBoolean(.common(cmd: meta), labels)
+ self.inner = LabeledBoolean(meta, labels)
case is StringMetricType:
- self.inner = LabeledString(.common(cmd: meta), labels)
- case is QuantityMetric:
- self.inner = LabeledQuantity(.common(cmd: meta), labels)
+ self.inner = LabeledString(meta, labels)
+ case is QuantityMetricType:
+ self.inner = LabeledQuantity(meta, labels)
+ case is MemoryDistributionMetricType:
+ self.inner = LabeledMemoryDistribution(meta, labels)
+ case is TimingDistributionMetricType:
+ self.inner = LabeledTimingDistribution(meta, labels)
+ case is CustomDistributionMetricType:
+ self.inner = LabeledCustomDistribution(meta, labels)
default:
throw "Can not create a labeled version of this metric type"
}
@@ -78,7 +68,6 @@ public final class LabeledMetricType: @unchecked Sendable {
/// * label: The label
/// - returns: The specific metric for that label
public subscript(label: String) -> T {
-
switch self.inner {
case is LabeledCounter:
return (self.inner as! LabeledCounter).get(label) as! T
@@ -88,6 +77,12 @@ public final class LabeledMetricType: @unchecked Sendable {
return (self.inner as! LabeledString).get(label) as! T
case is LabeledQuantity:
return (self.inner as! LabeledQuantity).get(label) as! T
+ case is LabeledMemoryDistribution:
+ return (self.inner as! LabeledMemoryDistribution).get(label) as! T
+ case is LabeledTimingDistribution:
+ return (self.inner as! LabeledTimingDistribution).get(label) as! T
+ case is LabeledCustomDistribution:
+ return (self.inner as! LabeledCustomDistribution).get(label) as! T
default:
// The constructor will already throw an exception on an unhandled sub-metric type
assertUnreachable()
@@ -109,6 +104,12 @@ public final class LabeledMetricType: @unchecked Sendable {
return (self.inner as! LabeledString).testGetNumRecordedErrors(errorType)
case is LabeledQuantity:
return (self.inner as! LabeledQuantity).testGetNumRecordedErrors(errorType)
+ case is LabeledMemoryDistribution:
+ return (self.inner as! LabeledMemoryDistribution).testGetNumRecordedErrors(errorType)
+ case is LabeledTimingDistribution:
+ return (self.inner as! LabeledTimingDistribution).testGetNumRecordedErrors(errorType)
+ case is LabeledCustomDistribution:
+ return (self.inner as! LabeledCustomDistribution).testGetNumRecordedErrors(errorType)
default:
// The constructor will already throw an exception on an unhandled sub-metric type
assertUnreachable()
@@ -133,6 +134,12 @@ public final class LabeledMetricType: @unchecked Sendable {
return labeled.testGetValue(pingName)!
case let labeled as LabeledQuantity:
return labeled.testGetValue(pingName)!
+ case let labeled as LabeledMemoryDistribution:
+ return labeled.testGetValue(pingName)!
+ case let labeled as LabeledTimingDistribution:
+ return labeled.testGetValue(pingName)!
+ case let labeled as LabeledCustomDistribution:
+ return labeled.testGetValue(pingName)!
default:
// The constructor will already throw an exception on an unhandled sub-metric type
assertUnreachable()
diff --git a/glean-core/ios/GleanTests/Metrics/LabeledMetricTests.swift b/glean-core/ios/GleanTests/Metrics/LabeledMetricTests.swift
index cbab212efe..2060672287 100644
--- a/glean-core/ios/GleanTests/Metrics/LabeledMetricTests.swift
+++ b/glean-core/ios/GleanTests/Metrics/LabeledMetricTests.swift
@@ -5,6 +5,7 @@
@testable import Glean
import XCTest
+// swiftlint:disable type_body_length
class LabeledMetricTypeTests: XCTestCase {
override func setUp() {
resetGleanDiscardingInitialPings(testCase: self, tag: "LabeledMetricTypeTests")
@@ -24,11 +25,15 @@ class LabeledMetricTypeTests: XCTestCase {
))
let labeledCounterMetric = try! LabeledMetricType(
- category: "telemetry",
- name: "labeled_counter_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_counter_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: counterMetric
)
@@ -55,11 +60,15 @@ class LabeledMetricTypeTests: XCTestCase {
))
let labeledCounterMetric = try! LabeledMetricType(
- category: "telemetry",
- name: "labeled_counter_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_counter_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: counterMetric,
labels: ["foo", "bar", "baz"]
)
@@ -88,11 +97,15 @@ class LabeledMetricTypeTests: XCTestCase {
))
let labeledCounterMetric = try! LabeledMetricType(
- category: "telemetry",
- name: "labeled_counter_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_counter_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: counterMetric
)
@@ -120,11 +133,15 @@ class LabeledMetricTypeTests: XCTestCase {
))
let labeledCounterMetric = try! LabeledMetricType(
- category: "telemetry",
- name: "labeled_counter_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_counter_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: counterMetric
)
@@ -162,11 +179,15 @@ class LabeledMetricTypeTests: XCTestCase {
))
let labeledStringMetric = try! LabeledMetricType(
- category: "telemetry",
- name: "labeled_counter_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_counter_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: counterMetric
)
@@ -187,11 +208,15 @@ class LabeledMetricTypeTests: XCTestCase {
))
let labeledBooleanMetric = try! LabeledMetricType(
- category: "telemetry",
- name: "labeled_boolean_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_boolean_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: booleanMetric
)
@@ -212,11 +237,15 @@ class LabeledMetricTypeTests: XCTestCase {
))
let labeledQuantityMetric = try! LabeledMetricType(
- category: "telemetry",
- name: "labeled_quantity_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_quantity_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: quantityMetric
)
@@ -237,11 +266,15 @@ class LabeledMetricTypeTests: XCTestCase {
), nil)
XCTAssertThrowsError(try LabeledMetricType>(
- category: "telemetry",
- name: "labeled_event_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_event_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: eventMetric
)) { error in
XCTAssertEqual(error as! String, "Can not create a labeled version of this metric type")
@@ -258,11 +291,15 @@ class LabeledMetricTypeTests: XCTestCase {
))
let labeledCounterMetric = try! LabeledMetricType(
- category: "telemetry",
- name: "labeled_counter_metric",
- sendInPings: ["metrics"],
- lifetime: .application,
- disabled: false,
+ .common(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_counter_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ )
+ ),
subMetric: counterMetric
)
@@ -274,4 +311,119 @@ class LabeledMetricTypeTests: XCTestCase {
XCTAssertEqual(1, labeledValues["label1"] as! Int32)
XCTAssertEqual(2, labeledValues["label2"] as! Int32)
}
+
+ func testLabeledMemoryDistribution() {
+ let metric = MemoryDistributionMetricType(
+ CommonMetricData(
+ category: "telemetry",
+ name: "labeled_memory_distribution_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false
+ ),
+ .kilobyte
+ )
+
+ let labeledMetric = try! LabeledMetricType(
+ .memoryDistribution(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_memory_distribution_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ ),
+ unit: .kilobyte
+ ),
+ subMetric: metric
+ )
+
+ labeledMetric["label1"].accumulate(1)
+ labeledMetric["label2"].accumulate(2)
+
+ let kb = Int64(1024)
+
+ XCTAssertEqual(1 * kb, labeledMetric["label1"].testGetValue()!.sum)
+ XCTAssertEqual(2 * kb, labeledMetric["label2"].testGetValue()!.sum)
+ }
+
+ func testLabeledTimingDistribution() {
+ let metric = TimingDistributionMetricType(
+ CommonMetricData(
+ category: "telemetry",
+ name: "labeled_timing_distribution_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false
+ ),
+ .nanosecond
+ )
+
+ let labeledMetric = try! LabeledMetricType(
+ .timingDistribution(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_timing_distribution_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ ),
+ unit: .nanosecond
+ ),
+ subMetric: metric
+ )
+
+ var id = labeledMetric["label1"].start()
+ labeledMetric["label1"].stopAndAccumulate(id)
+
+ id = labeledMetric["label2"].start()
+ labeledMetric["label2"].stopAndAccumulate(id)
+
+ id = labeledMetric["label2"].start()
+ labeledMetric["label2"].stopAndAccumulate(id)
+
+ XCTAssertEqual(1, labeledMetric["label1"].testGetValue()!.count)
+ XCTAssertEqual(2, labeledMetric["label2"].testGetValue()!.count)
+ }
+
+ func testLabeledCustomDistribution() {
+ let metric = CustomDistributionMetricType(
+ CommonMetricData(
+ category: "telemetry",
+ name: "labeled_custom_distribution_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false
+ ),
+ 0,
+ 60000,
+ 100,
+ .exponential,
+ )
+
+ let labeledMetric = try! LabeledMetricType(
+ .customDistribution(
+ cmd: CommonMetricData(
+ category: "telemetry",
+ name: "labeled_custom_distribution_metric",
+ sendInPings: ["metrics"],
+ lifetime: .application,
+ disabled: false,
+ ),
+ rangeMin: 0,
+ rangeMax: 60000,
+ bucketCount: 100,
+ histogramType: .exponential,
+ ),
+ subMetric: metric
+ )
+
+ labeledMetric["label1"].accumulateSamples([1])
+ labeledMetric["label2"].accumulateSamples([2])
+ labeledMetric["label2"].accumulateSamples([3])
+
+ XCTAssertEqual(1, labeledMetric["label1"].testGetValue()!.count)
+ XCTAssertEqual(2, labeledMetric["label2"].testGetValue()!.count)
+ }
}
+// swiftlint:enable type_body_length
diff --git a/glean-core/ios/sdk_generator.sh b/glean-core/ios/sdk_generator.sh
index bedfd79a2c..bc204a25f9 100755
--- a/glean-core/ios/sdk_generator.sh
+++ b/glean-core/ios/sdk_generator.sh
@@ -25,7 +25,7 @@
set -e
-GLEAN_PARSER_VERSION=20.1
+GLEAN_PARSER_VERSION=21.0
# CMDNAME is used in the usage text below.
# shellcheck disable=SC2034
diff --git a/glean-core/python/glean/__init__.py b/glean-core/python/glean/__init__.py
index bb95ab3ca8..61ce393c2a 100644
--- a/glean-core/python/glean/__init__.py
+++ b/glean-core/python/glean/__init__.py
@@ -31,7 +31,7 @@
__email__ = "glean-team@mozilla.com"
-GLEAN_PARSER_VERSION = "20.1.0"
+GLEAN_PARSER_VERSION = "21.0.1"
parser_version = VersionInfo.parse(GLEAN_PARSER_VERSION)
parser_version_next_major = parser_version.bump_major()
diff --git a/glean-core/python/glean/_loader.py b/glean-core/python/glean/_loader.py
index 146c80d8f9..ed3058261e 100644
--- a/glean-core/python/glean/_loader.py
+++ b/glean-core/python/glean/_loader.py
@@ -32,7 +32,11 @@
"event": metrics.EventMetricType,
"labeled_boolean": metrics.LabeledBooleanMetricType,
"labeled_counter": metrics.LabeledCounterMetricType,
+ "labeled_custom_distribution": metrics.LabeledCustomDistributionMetricType,
+ "labeled_memory_distribution": metrics.LabeledMemoryDistributionMetricType,
+ "labeled_quantity": metrics.LabeledQuantityMetricType,
"labeled_string": metrics.LabeledStringMetricType,
+ "labeled_timing_distribution": metrics.LabeledTimingDistributionMetricType,
"memory_distribution": metrics.MemoryDistributionMetricType,
"object": metrics.ObjectMetricType,
"ping": metrics.PingType,
@@ -92,6 +96,10 @@
gp_metrics.MemoryUnit.megabyte: metrics.MemoryUnit.MEGABYTE,
gp_metrics.MemoryUnit.gigabyte: metrics.MemoryUnit.GIGABYTE,
},
+ "histogram_type": {
+ gp_metrics.HistogramType.linear: metrics.HistogramType.LINEAR,
+ gp_metrics.HistogramType.exponential: metrics.HistogramType.EXPONENTIAL,
+ },
}
@@ -289,9 +297,32 @@ def _get_metric_objects(
args["label"] = None
meta_args, rest = _split_ctor_args(args)
if getattr(metric, "labeled", False):
- glean_metric = metric_type(
- metrics.LabeledMetricData.COMMON(metrics.CommonMetricData(**meta_args)), **rest
- )
+ if metric.type == "labeled_custom_distribution":
+ glean_metric = metric_type(
+ metrics.LabeledMetricData.CUSTOM_DISTRIBUTION(
+ metrics.CommonMetricData(**meta_args), **rest
+ )
+ )
+ elif metric.type == "labeled_timing_distribution":
+ rest["unit"] = rest["time_unit"]
+ del rest["time_unit"]
+ glean_metric = metric_type(
+ metrics.LabeledMetricData.TIMING_DISTRIBUTION(
+ metrics.CommonMetricData(**meta_args), **rest
+ )
+ )
+ elif metric.type == "labeled_memory_distribution":
+ rest["unit"] = rest["memory_unit"]
+ del rest["memory_unit"]
+ glean_metric = metric_type(
+ metrics.LabeledMetricData.MEMORY_DISTRIBUTION(
+ metrics.CommonMetricData(**meta_args), **rest
+ )
+ )
+ else:
+ glean_metric = metric_type(
+ metrics.LabeledMetricData.COMMON(metrics.CommonMetricData(**meta_args)), **rest
+ )
else:
glean_metric = metric_type(metrics.CommonMetricData(**meta_args), **rest)
diff --git a/glean-core/python/glean/metrics/__init__.py b/glean-core/python/glean/metrics/__init__.py
index e3fab36301..0b7b00a788 100644
--- a/glean-core/python/glean/metrics/__init__.py
+++ b/glean-core/python/glean/metrics/__init__.py
@@ -38,8 +38,11 @@
from .labeled import (
LabeledBooleanMetricType,
LabeledCounterMetricType,
+ LabeledCustomDistributionMetricType,
+ LabeledMemoryDistributionMetricType,
LabeledQuantityMetricType,
LabeledStringMetricType,
+ LabeledTimingDistributionMetricType,
)
from .ping import PingType
from .string import StringMetricType
@@ -62,9 +65,12 @@
"EventMetricType",
"LabeledBooleanMetricType",
"LabeledCounterMetricType",
+ "LabeledCustomDistributionMetricType",
+ "LabeledMemoryDistributionMetricType",
"LabeledMetricData",
"LabeledQuantityMetricType",
"LabeledStringMetricType",
+ "LabeledTimingDistributionMetricType",
"Lifetime",
"MemoryDistributionMetricType",
"MemoryUnit",
diff --git a/glean-core/python/glean/metrics/labeled.py b/glean-core/python/glean/metrics/labeled.py
index a27073aec7..cb1dddecef 100644
--- a/glean-core/python/glean/metrics/labeled.py
+++ b/glean-core/python/glean/metrics/labeled.py
@@ -8,9 +8,12 @@
from .._uniffi import LabeledBoolean
from .._uniffi import LabeledCounter
+from .._uniffi import LabeledCustomDistribution
+from .._uniffi import LabeledMemoryDistribution
from .._uniffi import LabeledMetricData
-from .._uniffi import LabeledString
from .._uniffi import LabeledQuantity
+from .._uniffi import LabeledString
+from .._uniffi import LabeledTimingDistribution
from ..testing import ErrorType
@@ -107,9 +110,24 @@ class LabeledQuantityMetricType(LabeledMetricBase):
_ctor = LabeledQuantity
+class LabeledCustomDistributionMetricType(LabeledMetricBase):
+ _ctor = LabeledCustomDistribution
+
+
+class LabeledMemoryDistributionMetricType(LabeledMetricBase):
+ _ctor = LabeledMemoryDistribution
+
+
+class LabeledTimingDistributionMetricType(LabeledMetricBase):
+ _ctor = LabeledTimingDistribution
+
+
__all__ = [
"LabeledBooleanMetricType",
"LabeledCounterMetricType",
+ "LabeledCustomDistributionMetricType",
+ "LabeledMemoryDistributionMetricType",
"LabeledQuantityMetricType",
"LabeledStringMetricType",
+ "LabeledTimingDistributionMetricType",
]
diff --git a/glean-core/python/tests/metrics/test_labeled.py b/glean-core/python/tests/metrics/test_labeled.py
index 3ba30baec3..bf4c76ee42 100644
--- a/glean-core/python/tests/metrics/test_labeled.py
+++ b/glean-core/python/tests/metrics/test_labeled.py
@@ -264,3 +264,28 @@ def test_rapidly_recreating_labeled_metrics_does_not_crash():
labeled_counter_metric["foo"].add(1)
assert max_attempts == labeled_counter_metric["foo"].test_get_value()
+
+
+def test_labeled_custom_distribution():
+ labeled_counter_metric = metrics.LabeledCustomDistributionMetricType(
+ LabeledMetricData.CUSTOM_DISTRIBUTION(
+ CommonMetricData(
+ disabled=False,
+ category="telemetry",
+ lifetime=Lifetime.APPLICATION,
+ name="labeled_counter_metric",
+ send_in_pings=["metrics"],
+ label=None,
+ ),
+ range_min=0,
+ range_max=100,
+ bucket_count=100,
+ histogram_type=metrics.HistogramType.LINEAR,
+ )
+ )
+
+ labeled_counter_metric["label1"].accumulate_samples([1, 2])
+ labeled_counter_metric["label2"].accumulate_single_sample(3)
+
+ assert 2 == labeled_counter_metric["label1"].test_get_value().count
+ assert 1 == labeled_counter_metric["label2"].test_get_value().count
diff --git a/glean-core/src/glean.udl b/glean-core/src/glean.udl
index 128393d09e..afb6159cf8 100644
--- a/glean-core/src/glean.udl
+++ b/glean-core/src/glean.udl
@@ -528,6 +528,36 @@ interface LabeledQuantity {
record? test_get_value(optional string? ping_name = null);
};
+interface LabeledMemoryDistribution {
+ constructor(LabeledMetricData meta, sequence? labels);
+
+ MemoryDistributionMetric get(string label);
+
+ i32 test_get_num_recorded_errors(ErrorType error);
+
+ record? test_get_value(optional string? ping_name = null);
+};
+
+interface LabeledTimingDistribution {
+ constructor(LabeledMetricData meta, sequence? labels);
+
+ TimingDistributionMetric get(string label);
+
+ i32 test_get_num_recorded_errors(ErrorType error);
+
+ record? test_get_value(optional string? ping_name = null);
+};
+
+interface LabeledCustomDistribution {
+ constructor(LabeledMetricData meta, sequence? labels);
+
+ CustomDistributionMetric get(string label);
+
+ i32 test_get_num_recorded_errors(ErrorType error);
+
+ record? test_get_value(optional string? ping_name = null);
+};
+
interface StringListMetric {
constructor(CommonMetricData meta);
diff --git a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy
index 7d46b7e6f7..f8eb9a4d94 100644
--- a/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy
+++ b/gradle-plugin/src/main/groovy/mozilla/telemetry/glean-gradle-plugin/GleanGradlePlugin.groovy
@@ -59,7 +59,7 @@ abstract class GleanMetricsYamlTransform implements TransformAction {
// The version of glean_parser to install from PyPI.
- private String GLEAN_PARSER_VERSION = "20.1"
+ private String GLEAN_PARSER_VERSION = "21.0"
// The version of Miniconda is explicitly specified.
// Miniconda3-4.5.12 is known to not work on Windows.
private String MINICONDA_VERSION = "24.3.0-0"
diff --git a/pyproject.toml b/pyproject.toml
index 845ac3bb27..1fd3f46e7d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,7 +22,7 @@ maintainers = [
dependencies = [
"semver>=2.13.0",
- "glean_parser~=20.1",
+ "glean_parser~=21.0",
]
[project.urls]
diff --git a/samples/glean-sym-test/Cargo.lock b/samples/glean-sym-test/Cargo.lock
index 7a2c532ed0..596f193451 100644
--- a/samples/glean-sym-test/Cargo.lock
+++ b/samples/glean-sym-test/Cargo.lock
@@ -458,7 +458,7 @@ dependencies = [
[[package]]
name = "glean-build"
-version = "20.1.0"
+version = "21.0.1"
dependencies = [
"xshell-venv",
]
diff --git a/samples/ios/app/metrics.yaml b/samples/ios/app/metrics.yaml
index fea4eea065..bb30ad290c 100644
--- a/samples/ios/app/metrics.yaml
+++ b/samples/ios/app/metrics.yaml
@@ -301,3 +301,21 @@ codegen_test:
range_max: 100
bucket_count: 100
histogram_type: linear
+
+ labeled_timing_distribution:
+ <<: *defaults
+ type: labeled_timing_distribution
+ time_unit: millisecond
+
+ labeled_memory_distribution:
+ <<: *defaults
+ type: labeled_memory_distribution
+ memory_unit: byte
+
+ labeled_custom_distribution:
+ <<: *defaults
+ type: labeled_custom_distribution
+ range_min: 0
+ range_max: 100
+ bucket_count: 100
+ histogram_type: exponential
diff --git a/samples/python/glean-sample/__main__.py b/samples/python/glean-sample/__main__.py
index 4880c704d1..f13fd3cecb 100644
--- a/samples/python/glean-sample/__main__.py
+++ b/samples/python/glean-sample/__main__.py
@@ -44,6 +44,17 @@
ch.append(f)
metrics.party.chooser.set(ch)
+metrics.codegen_test.quantity.set(1)
+metrics.codegen_test.custom_distribution.accumulate_samples([1, 2])
+metrics.codegen_test.memory_distribution.accumulate_samples([1, 2])
+metrics.codegen_test.timing_distribution.accumulate_samples([1, 2])
+
+
+metrics.codegen_test.labeled_quantity["label"].set(1)
+metrics.codegen_test.labeled_custom_distribution["label"].accumulate_samples([1, 2])
+metrics.codegen_test.labeled_memory_distribution["label"].accumulate_samples([1, 2])
+metrics.codegen_test.labeled_timing_distribution["label"].accumulate_samples([1, 2])
+
pings.prototype.submit()
Glean.shutdown()
diff --git a/samples/python/metrics.yaml b/samples/python/metrics.yaml
index 8f5c476d04..6ce4be7204 100644
--- a/samples/python/metrics.yaml
+++ b/samples/python/metrics.yaml
@@ -74,3 +74,64 @@ party:
- type: string
- type: number
- type: boolean
+
+codegen_test:
+ counter: &defaults
+ type: counter
+ description: |
+ A metric for codegen testing --
+ no extra data, just setting the defaults
+ bugs:
+ - https://bugzilla.mozilla.org/TODO
+ data_reviews:
+ - http://example.com/reviews
+ notification_emails:
+ - CHANGE-ME@example.com
+ expires: never
+ send_in_pings:
+ - sample
+
+ quantity:
+ <<: *defaults
+ type: quantity
+ unit: apples
+
+ timing_distribution:
+ <<: *defaults
+ type: timing_distribution
+ time_unit: millisecond
+
+ memory_distribution:
+ <<: *defaults
+ type: memory_distribution
+ memory_unit: byte
+
+ custom_distribution:
+ <<: *defaults
+ type: custom_distribution
+ range_min: 0
+ range_max: 100
+ bucket_count: 100
+ histogram_type: linear
+
+ labeled_quantity:
+ <<: *defaults
+ type: labeled_quantity
+
+ labeled_timing_distribution:
+ <<: *defaults
+ type: labeled_timing_distribution
+ time_unit: millisecond
+
+ labeled_memory_distribution:
+ <<: *defaults
+ type: labeled_memory_distribution
+ memory_unit: byte
+
+ labeled_custom_distribution:
+ <<: *defaults
+ type: labeled_custom_distribution
+ range_min: 0
+ range_max: 100
+ bucket_count: 100
+ histogram_type: exponential