tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 7767650662d5872688c062303a14533e106e657e
parent 07b9fc6e1865108d5f01cf1707fc5ec9125550fa
Author: Charlie Humphreys <chumphreys@mozilla.com>
Date:   Mon, 17 Nov 2025 01:46:20 +0000

Bug 1998248: Add JS API for TestGetValue on Labeled metrics r=chutten,webidl,toolkit-telemetry-reviewers,smaug,fluent-reviewers,bolsson

Differential Revision: https://phabricator.services.mozilla.com/D271591

Diffstat:
Mdom/bindings/Codegen.py | 2+-
Mdom/webidl/Glean.webidl | 5+++++
Mtoolkit/components/glean/bindings/private/Labeled.cpp | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtoolkit/components/glean/bindings/private/Labeled.h | 10++++++++++
Mtoolkit/components/glean/build_scripts/glean_parser_ext/js.py | 45+++++++++++++++++++++++++++++++++++++++++----
Mtoolkit/components/glean/build_scripts/glean_parser_ext/templates/js.jinja2 | 4++--
Mtoolkit/components/glean/build_scripts/glean_parser_ext/templates/js_h.jinja2 | 6++++++
Mtoolkit/components/glean/build_scripts/glean_parser_ext/util.py | 15++++++++++++---
Mtoolkit/components/glean/tests/pytest/jogfactory_output | 34+++++++++++++++++-----------------
Mtoolkit/components/glean/tests/pytest/metrics_test_output_js_cpp | 158++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mtoolkit/components/glean/tests/pytest/metrics_test_output_js_h | 24++++++++++++++++++++++++
Mtoolkit/components/glean/tests/xpcshell/test_Glean.js | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtoolkit/content/aboutGlean.js | 10+++++-----
Mtoolkit/locales/en-US/toolkit/about/aboutGlean.ftl | 2+-
14 files changed, 456 insertions(+), 112 deletions(-)

diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py @@ -8646,7 +8646,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider, isMember=False): if not isMember and typeNeedsRooting(returnType): rooter = CGGeneric( "RecordRooter<%s> resultRooter(cx, &result);\n" - % ("nsString, " + result.define()) + % (recordKeyType(returnType) + ", " + result.define()) ) else: rooter = None diff --git a/dom/webidl/Glean.webidl b/dom/webidl/Glean.webidl @@ -25,6 +25,8 @@ interface GleanImpl { getter GleanCategory (DOMString identifier); }; +typedef (boolean or unsigned long long or UTF8String or GleanDistributionData) GleanLabeledTestValue; + [Func="GleanWebidlEnabled", Exposed=Window] interface GleanLabeled { /** @@ -40,4 +42,7 @@ interface GleanLabeled { * `OTHER_LABEL` label. */ getter GleanMetric (DOMString identifier); + + [Throws, ChromeOnly] + record<UTF8String, GleanLabeledTestValue>? testGetValue(optional UTF8String aPingName = ""); }; diff --git a/toolkit/components/glean/bindings/private/Labeled.cpp b/toolkit/components/glean/bindings/private/Labeled.cpp @@ -7,6 +7,8 @@ #include "mozilla/glean/bindings/Labeled.h" #include "mozilla/dom/GleanBinding.h" +#include "mozilla/dom/GleanMetricsBinding.h" +#include "mozilla/dom/Record.h" #include "mozilla/glean/fog_ffi_generated.h" #include "mozilla/glean/bindings/GleanJSMetricsLookup.h" #include "mozilla/glean/bindings/MetricTypes.h" @@ -55,6 +57,125 @@ void GleanLabeled::GetSupportedNames(nsTArray<nsString>& aNames) { // We really don't know, so don't do anything. } +using GleanLabeledTestValue = + dom::OwningBooleanOrUnsignedLongLongOrUTF8StringOrGleanDistributionData; + +void GleanLabeled::TestGetValue( + const nsACString& aPingName, + dom::Nullable<dom::Record<nsCString, GleanLabeledTestValue>>& aResult, + ErrorResult& aRv) { + auto type = static_cast<MetricTypeId>(mTypeId); + Maybe<nsCString> err; + + switch (type) { + case MetricTypeId::LABELED_BOOLEAN: + err = impl::fog_labeled_test_get_error<impl::BooleanMetric>(mId); + break; + case MetricTypeId::LABELED_COUNTER: + err = impl::fog_labeled_test_get_error< + impl::CounterMetric<impl::CounterType::eBaseOrLabeled>>(mId); + break; + case MetricTypeId::LABELED_STRING: + err = impl::fog_labeled_test_get_error<impl::StringMetric>(mId); + break; + case MetricTypeId::LABELED_QUANTITY: + err = impl::fog_labeled_test_get_error<impl::QuantityMetric>(mId); + break; + case MetricTypeId::LABELED_CUSTOM_DISTRIBUTION: + err = + impl::fog_labeled_test_get_error<impl::CustomDistributionMetric>(mId); + break; + case MetricTypeId::LABELED_MEMORY_DISTRIBUTION: + err = + impl::fog_labeled_test_get_error<impl::MemoryDistributionMetric>(mId); + break; + case MetricTypeId::LABELED_TIMING_DISTRIBUTION: + err = + impl::fog_labeled_test_get_error<impl::TimingDistributionMetric>(mId); + break; + default: + err = Some(nsCString("type ID supplied is not a Labeled metric type")); + } + if (err.isSome()) { + aResult.SetNull(); + aRv.ThrowDataError(err.value()); + return; + } + + dom::Record<nsCString, GleanLabeledTestValue> retVal; + uint64_t count = 0; + nsTArray<nsCString> keys; + if (type == MetricTypeId::LABELED_BOOLEAN) { + nsTArray<bool> values; + impl::fog_labeled_boolean_test_get_value(mId, &aPingName, &count, &keys, + &values); + for (uint64_t i = 0; i < count; i++) { + auto el = retVal.Entries().AppendElement(); + el->mKey = keys[i]; + el->mValue.SetAsBoolean() = values[i]; + } + } else if (type == MetricTypeId::LABELED_COUNTER) { + nsTArray<int32_t> values; + impl::fog_labeled_counter_test_get_value(mId, &aPingName, &count, &keys, + &values); + for (uint64_t i = 0; i < count; i++) { + auto el = retVal.Entries().AppendElement(); + el->mKey = keys[i]; + el->mValue.SetAsUnsignedLongLong() = values[i]; + } + } else if (type == MetricTypeId::LABELED_STRING) { + nsTArray<nsCString> values; + impl::fog_labeled_string_test_get_value(mId, &aPingName, &count, &keys, + &values); + for (uint64_t i = 0; i < count; i++) { + auto el = retVal.Entries().AppendElement(); + el->mKey = keys[i]; + el->mValue.SetAsUTF8String() = values[i]; + } + } else if (type == MetricTypeId::LABELED_QUANTITY) { + nsTArray<int64_t> values; + impl::fog_labeled_quantity_test_get_value(mId, &aPingName, &count, &keys, + &values); + for (uint64_t i = 0; i < count; i++) { + auto el = retVal.Entries().AppendElement(); + el->mKey = keys[i]; + el->mValue.SetAsUnsignedLongLong() = values[i]; + } + } else if (type == MetricTypeId::LABELED_CUSTOM_DISTRIBUTION || + type == MetricTypeId::LABELED_MEMORY_DISTRIBUTION || + type == MetricTypeId::LABELED_TIMING_DISTRIBUTION) { + nsTArray<impl::FfiDistributionData> values; + if (type == MetricTypeId::LABELED_CUSTOM_DISTRIBUTION) { + impl::fog_labeled_custom_distribution_test_get_value( + mId, &aPingName, &count, &keys, &values); + } else if (type == MetricTypeId::LABELED_MEMORY_DISTRIBUTION) { + impl::fog_labeled_memory_distribution_test_get_value( + mId, &aPingName, &count, &keys, &values); + } else if (type == MetricTypeId::LABELED_TIMING_DISTRIBUTION) { + impl::fog_labeled_timing_distribution_test_get_value( + mId, &aPingName, &count, &keys, &values); + } + for (size_t i = 0; i < keys.Length(); i++) { + auto el = retVal.Entries().AppendElement(); + el->mKey = keys[i]; + auto& distributionData = el->mValue.SetAsGleanDistributionData(); + distributionData.mCount = values[i].count; + distributionData.mSum = values[i].sum; + + for (size_t j = 0; j < values[i].keys.Length(); j++) { + auto elem = distributionData.mValues.Entries().AppendElement(); + elem->mKey.AppendInt(values[i].keys[j]); + elem->mValue = values[i].values[j]; + } + } + } else { + MOZ_ASSERT_UNREACHABLE( + "The function should have returned instead of hitting this."); + } + + aResult.SetValue(std::move(retVal)); +} + namespace impl { // Helper function to get the current process type string for telemetry labeling diff --git a/toolkit/components/glean/bindings/private/Labeled.h b/toolkit/components/glean/bindings/private/Labeled.h @@ -11,6 +11,8 @@ #include "nsWrapperCache.h" #include "mozilla/ResultVariant.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/GleanBinding.h" +#include "mozilla/dom/Record.h" #include "mozilla/glean/bindings/Boolean.h" #include "mozilla/glean/bindings/Counter.h" #include "mozilla/glean/bindings/CustomDistribution.h" @@ -312,6 +314,9 @@ class Labeled { } // namespace impl +using GleanLabeledTestValue = + dom::OwningBooleanOrUnsignedLongLongOrUTF8StringOrGleanDistributionData; + class GleanLabeled final : public GleanMetric { public: explicit GleanLabeled(uint32_t aId, uint32_t aTypeId, nsISupports* aParent) @@ -325,6 +330,11 @@ class GleanLabeled final : public GleanMetric { bool NameIsEnumerable(const nsAString& aName); void GetSupportedNames(nsTArray<nsString>& aNames); + void TestGetValue( + const nsACString& aPingName, + dom::Nullable<dom::Record<nsCString, GleanLabeledTestValue>>& aResult, + ErrorResult& aRv); + private: virtual ~GleanLabeled() = default; diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/js.py b/toolkit/components/glean/build_scripts/glean_parser_ext/js.py @@ -15,7 +15,12 @@ import jinja2 from glean_parser import util from perfecthash import PerfectHash from string_table import StringTable -from util import generate_metric_ids, generate_ping_ids, get_metrics +from util import ( + generate_metric_ids, + generate_ping_ids, + get_metrics, + type_ids_and_categories, +) """ We need to store several bits of information in the Perfect Hash Map Entry: @@ -124,6 +129,7 @@ def output_js(objs, output_fd_h, output_fd_cpp, options={}): lstrip_blocks=True, ) env.filters["Camelize"] = util.Camelize + env.filters["SCREAMING_CASE"] = util.screaming_case for filter_name, filter_func in filters: env.filters[filter_name] = filter_func return env.get_template(template_name) @@ -173,20 +179,36 @@ def write_metrics( category_string_table = StringTable() metric_string_table = StringTable() # Mapping from a type name to its ID + metric_types = set() metric_type_ids = {} - for category_name, objs in get_metrics(objs).items(): + for category_name, objects in get_metrics(objs).items(): + for metric in objects.values(): + metric_type_tuple = (type_name(metric), subtype_name(metric), metric.type) + metric_types.add(metric_type_tuple) + metric_types = sorted( + metric_types, key=lambda metric_type_tuple: metric_type_tuple[2] + ) + + for category_name, objects in get_metrics(objs).items(): category_camel = util.camelize(category_name) id = category_string_table.stringIndex(category_camel) categories.append((category_camel, id)) - for metric in objs.values(): + for metric in objects.values(): identifier = metric_identifier(category_camel, metric.name) metric_type_tuple = (type_name(metric), subtype_name(metric)) if metric_type_tuple in metric_type_ids: type_id, _ = metric_type_ids[metric_type_tuple] else: - type_id = len(metric_type_ids) + 1 + type_id = ( + next( + i + for i, v in enumerate(metric_types) + if v[0] == metric_type_tuple[0] and v[1] == metric_type_tuple[1] + ) + + 1 + ) metric_type_ids[metric_type_tuple] = (type_id, metric.type) idx = metric_string_table.stringIndex(identifier) @@ -194,6 +216,20 @@ def write_metrics( entry = create_entry(metric_id, type_id, idx) metric_id_mapping[identifier] = entry + metric_type_ids = sorted(metric_type_ids.items(), key=lambda types: types[1][1]) + + # This validates that the type ids generated by the type_ids_and_categories function in `util.py` + # generates the same IDs as this method. This will cause failures at build time if something is wrong. + # TODO: Merge the method here that creates the metric_type_ids dict with `type_ids_and_categories` in `util.py` - https://bugzilla.mozilla.org/show_bug.cgi?id=1999421 + other_type_ids = list(type_ids_and_categories(objs)[0].items()) + for i, v in enumerate(metric_type_ids): + assert ( + v[1][1] == other_type_ids[i][0] + ), f"Metric {v[1][1]} is at index {i} in `glean_parser_ext/js.py`, but {other_type_ids[i][0]} is at that index in `glean_parser_ext/util.py`" + assert ( + v[1][0] == other_type_ids[i][1]["id"] + ), f"Metric {v[1][1]} has type_id {v[1][0]} in `glean_parser_ext/js.py`, but its type_id in `glean_parser_ext/util.py` is {other_type_ids[i][1]['id']}" + # Create a lookup table for the metric categories only category_string_table = category_string_table.writeToString("gCategoryStringTable") category_map = [(bytearray(category, "ascii"), id) for (category, id) in categories] @@ -253,6 +289,7 @@ def write_metrics( id_signal_bits=ID_SIGNAL_BITS, num_categories=len(categories), num_metrics=len(metric_id_mapping.items()), + metric_type_ids=metric_type_ids, ) ) output_fd_h.write("\n") diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/js.jinja2 b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/js.jinja2 @@ -49,7 +49,7 @@ already_AddRefed<GleanMetric> NewMetricFromId(uint32_t id, nsISupports* aParent) uint32_t metricId = GLEAN_METRIC_ID(id); switch (typeId) { - {% for (type_name, subtype_name), (type_id, original_type) in metric_type_ids.items() %} + {% for (type_name, subtype_name), (type_id, original_type) in metric_type_ids %} case {{ type_id }}: /* {{ original_type }} */ { return MakeAndAddRef<{{type_name}}>(metricId{% if subtype_name|length > 0 %}, {{ type_id }}{% endif %}, aParent); @@ -78,7 +78,7 @@ already_AddRefed<GleanMetric> NewSubMetricFromIds(uint32_t aParentTypeId, uint32_t* aSubmetricId, nsISupports* aParent) { switch (aParentTypeId) { - {% for (type_name, subtype_name), (type_id, original_type) in metric_type_ids.items() %} + {% for (type_name, subtype_name), (type_id, original_type) in metric_type_ids %} {% if subtype_name|length > 0 %} case {{ type_id }}: { /* {{ original_type }} */ auto id = impl::fog_{{original_type}}_get(aParentMetricId, &aLabel); diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/templates/js_h.jinja2 b/toolkit/components/glean/build_scripts/glean_parser_ext/templates/js_h.jinja2 @@ -22,6 +22,12 @@ class nsISupports; namespace mozilla::glean { +enum MetricTypeId { + {% for (type_name, subtype_name), (type_id, original_type) in metric_type_ids %} + {{original_type|SCREAMING_CASE}} = {{type_id}}, + {% endfor %} +}; + // The category lookup table's entry type using category_entry_t = uint32_t; // The metric lookup table's entry type diff --git a/toolkit/components/glean/build_scripts/glean_parser_ext/util.py b/toolkit/components/glean/build_scripts/glean_parser_ext/util.py @@ -101,15 +101,24 @@ def type_ids_and_categories(objs) -> tuple[dict[str, tuple[int, list[str]]], lis (If it didn't, it would supply args in the wrong order to metric type constructors with multiple extra args (e.g. custom_distribution)). """ + metric_types = set() metric_type_ids = {} categories = [] - for category_name, objs in get_metrics(objs).items(): + for category_name, objects in get_metrics(objs).items(): + for metric in objects.values(): + if metric.type not in metric_type_ids: + metric_types.add(metric.type) + metric_types = sorted(metric_types) + + for category_name, objects in get_metrics(objs).items(): categories.append(category_name) - for metric in objs.values(): + for metric in objects.values(): if metric.type not in metric_type_ids: - type_id = len(metric_type_ids) + 1 + type_id = ( + next(i for i, v in enumerate(metric_types) if v == metric.type) + 1 + ) args = util.common_metric_args.copy() for arg_name in util.extra_metric_args: if hasattr(metric, arg_name): diff --git a/toolkit/components/glean/tests/pytest/jogfactory_output b/toolkit/components/glean/tests/pytest/jogfactory_output @@ -282,7 +282,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = DatetimeMetric::new(BaseMetricId(metric_id), meta, time_unit.unwrap()); - let metric32: u32 = (15 << 27) | metric_id; + let metric32: u32 = (4 << 27) | metric_id; assert!( __jog_metric_maps::DATETIME_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -299,7 +299,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = DenominatorMetric::new(BaseMetricId(metric_id), meta, numerators.unwrap()); - let metric32: u32 = (17 << 27) | metric_id; + let metric32: u32 = (5 << 27) | metric_id; assert!( __jog_metric_maps::DENOMINATOR_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -316,7 +316,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = DualLabeledCounterMetric::new(BaseMetricId(metric_id), meta, keys, categories); - let metric32: u32 = (13 << 27) | metric_id; + let metric32: u32 = (6 << 27) | metric_id; assert!( __jog_metric_maps::DUAL_LABELED_COUNTER_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -333,7 +333,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = EventMetric::with_runtime_extra_keys(BaseMetricId(metric_id), meta, allowed_extra_keys.unwrap()); - let metric32: u32 = (16 << 27) | metric_id; + let metric32: u32 = (7 << 27) | metric_id; assert!( __jog_metric_maps::EVENT_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -355,7 +355,7 @@ pub fn create_and_register_metric( } else { LabeledMetric::new(BaseMetricId(metric_id), meta, labels) }; - let metric32: u32 = (4 << 27) | metric_id; + let metric32: u32 = (8 << 27) | metric_id; assert!( __jog_metric_maps::LABELED_BOOLEAN_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -373,7 +373,7 @@ pub fn create_and_register_metric( ..Default::default() } }; let metric = LabeledMetric::new(BaseMetricId(metric_id), meta, labels); - let metric32: u32 = (5 << 27) | metric_id; + let metric32: u32 = (9 << 27) | metric_id; assert!( __jog_metric_maps::LABELED_COUNTER_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -391,7 +391,7 @@ pub fn create_and_register_metric( ..Default::default() } }; let metric = LabeledMetric::new(BaseMetricId(metric_id), meta, labels); - let metric32: u32 = (6 << 27) | metric_id; + let metric32: u32 = (10 << 27) | metric_id; assert!( __jog_metric_maps::LABELED_STRING_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -408,7 +408,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = MemoryDistributionMetric::new(BaseMetricId(metric_id), meta, memory_unit.unwrap()); - let metric32: u32 = (7 << 27) | metric_id; + let metric32: u32 = (11 << 27) | metric_id; assert!( __jog_metric_maps::MEMORY_DISTRIBUTION_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -425,7 +425,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = NumeratorMetric::new(BaseMetricId(metric_id), meta); - let metric32: u32 = (20 << 27) | metric_id; + let metric32: u32 = (12 << 27) | metric_id; assert!( __jog_metric_maps::NUMERATOR_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -442,7 +442,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = ObjectMetric::new(BaseMetricId(metric_id), meta); - let metric32: u32 = (14 << 27) | metric_id; + let metric32: u32 = (13 << 27) | metric_id; assert!( __jog_metric_maps::OBJECT_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -459,7 +459,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = QuantityMetric::new(BaseMetricId(metric_id), meta); - let metric32: u32 = (18 << 27) | metric_id; + let metric32: u32 = (14 << 27) | metric_id; assert!( __jog_metric_maps::QUANTITY_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -476,7 +476,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = RateMetric::new(BaseMetricId(metric_id), meta); - let metric32: u32 = (19 << 27) | metric_id; + let metric32: u32 = (15 << 27) | metric_id; assert!( __jog_metric_maps::RATE_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -493,7 +493,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = StringMetric::new(BaseMetricId(metric_id), meta); - let metric32: u32 = (9 << 27) | metric_id; + let metric32: u32 = (16 << 27) | metric_id; assert!( __jog_metric_maps::STRING_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -510,7 +510,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = StringListMetric::new(BaseMetricId(metric_id), meta); - let metric32: u32 = (8 << 27) | metric_id; + let metric32: u32 = (17 << 27) | metric_id; assert!( __jog_metric_maps::STRING_LIST_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -527,7 +527,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = TextMetric::new(BaseMetricId(metric_id), meta); - let metric32: u32 = (10 << 27) | metric_id; + let metric32: u32 = (18 << 27) | metric_id; assert!( __jog_metric_maps::TEXT_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -544,7 +544,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = TimespanMetric::new(BaseMetricId(metric_id), meta, time_unit.unwrap()); - let metric32: u32 = (11 << 27) | metric_id; + let metric32: u32 = (19 << 27) | metric_id; assert!( __jog_metric_maps::TIMESPAN_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." @@ -561,7 +561,7 @@ pub fn create_and_register_metric( ..Default::default() }; let metric = TimingDistributionMetric::new(BaseMetricId(metric_id), meta, time_unit.unwrap()); - let metric32: u32 = (12 << 27) | metric_id; + let metric32: u32 = (20 << 27) | metric_id; assert!( __jog_metric_maps::TIMING_DISTRIBUTION_MAP.write()?.insert(BaseMetricId(metric_id), metric).is_none(), "We should never insert a runtime metric with an already-used id." diff --git a/toolkit/components/glean/tests/pytest/metrics_test_output_js_cpp b/toolkit/components/glean/tests/pytest/metrics_test_output_js_cpp @@ -59,73 +59,73 @@ already_AddRefed<GleanMetric> NewMetricFromId(uint32_t id, nsISupports* aParent) { return MakeAndAddRef<GleanCustomDistribution>(metricId, aParent); } - case 4: /* labeled_boolean */ + case 4: /* datetime */ { - return MakeAndAddRef<GleanLabeled>(metricId, 4, aParent); + return MakeAndAddRef<GleanDatetime>(metricId, aParent); } - case 5: /* labeled_counter */ + case 5: /* denominator */ { - return MakeAndAddRef<GleanLabeled>(metricId, 5, aParent); + return MakeAndAddRef<GleanDenominator>(metricId, aParent); } - case 6: /* labeled_string */ + case 6: /* dual_labeled_counter */ { - return MakeAndAddRef<GleanLabeled>(metricId, 6, aParent); + return MakeAndAddRef<GleanDualLabeledCounter>(metricId, aParent); } - case 7: /* memory_distribution */ + case 7: /* event */ { - return MakeAndAddRef<GleanMemoryDistribution>(metricId, aParent); + return MakeAndAddRef<GleanEvent>(metricId, aParent); } - case 8: /* string_list */ + case 8: /* labeled_boolean */ { - return MakeAndAddRef<GleanStringList>(metricId, aParent); + return MakeAndAddRef<GleanLabeled>(metricId, 8, aParent); } - case 9: /* string */ + case 9: /* labeled_counter */ { - return MakeAndAddRef<GleanString>(metricId, aParent); + return MakeAndAddRef<GleanLabeled>(metricId, 9, aParent); } - case 10: /* text */ + case 10: /* labeled_string */ { - return MakeAndAddRef<GleanText>(metricId, aParent); + return MakeAndAddRef<GleanLabeled>(metricId, 10, aParent); } - case 11: /* timespan */ + case 11: /* memory_distribution */ { - return MakeAndAddRef<GleanTimespan>(metricId, aParent); + return MakeAndAddRef<GleanMemoryDistribution>(metricId, aParent); } - case 12: /* timing_distribution */ + case 12: /* numerator */ { - return MakeAndAddRef<GleanTimingDistribution>(metricId, aParent); + return MakeAndAddRef<GleanNumerator>(metricId, aParent); } - case 13: /* dual_labeled_counter */ + case 13: /* object */ { - return MakeAndAddRef<GleanDualLabeledCounter>(metricId, aParent); + return MakeAndAddRef<GleanObject>(metricId, aParent); } - case 14: /* object */ + case 14: /* quantity */ { - return MakeAndAddRef<GleanObject>(metricId, aParent); + return MakeAndAddRef<GleanQuantity>(metricId, aParent); } - case 15: /* datetime */ + case 15: /* rate */ { - return MakeAndAddRef<GleanDatetime>(metricId, aParent); + return MakeAndAddRef<GleanRate>(metricId, aParent); } - case 16: /* event */ + case 16: /* string */ { - return MakeAndAddRef<GleanEvent>(metricId, aParent); + return MakeAndAddRef<GleanString>(metricId, aParent); } - case 17: /* denominator */ + case 17: /* string_list */ { - return MakeAndAddRef<GleanDenominator>(metricId, aParent); + return MakeAndAddRef<GleanStringList>(metricId, aParent); } - case 18: /* quantity */ + case 18: /* text */ { - return MakeAndAddRef<GleanQuantity>(metricId, aParent); + return MakeAndAddRef<GleanText>(metricId, aParent); } - case 19: /* rate */ + case 19: /* timespan */ { - return MakeAndAddRef<GleanRate>(metricId, aParent); + return MakeAndAddRef<GleanTimespan>(metricId, aParent); } - case 20: /* numerator */ + case 20: /* timing_distribution */ { - return MakeAndAddRef<GleanNumerator>(metricId, aParent); + return MakeAndAddRef<GleanTimingDistribution>(metricId, aParent); } case 21: /* uuid */ { @@ -154,17 +154,17 @@ already_AddRefed<GleanMetric> NewSubMetricFromIds(uint32_t aParentTypeId, uint32_t* aSubmetricId, nsISupports* aParent) { switch (aParentTypeId) { - case 4: { /* labeled_boolean */ + case 8: { /* labeled_boolean */ auto id = impl::fog_labeled_boolean_get(aParentMetricId, &aLabel); *aSubmetricId = id; return MakeAndAddRef<GleanBoolean>(id, aParent); } - case 5: { /* labeled_counter */ + case 9: { /* labeled_counter */ auto id = impl::fog_labeled_counter_get(aParentMetricId, &aLabel); *aSubmetricId = id; return MakeAndAddRef<GleanCounter>(id, aParent); } - case 6: { /* labeled_string */ + case 10: { /* labeled_string */ auto id = impl::fog_labeled_string_get(aParentMetricId, &aLabel); *aSubmetricId = id; return MakeAndAddRef<GleanString>(id, aParent); @@ -414,62 +414,62 @@ static_assert(sizeof(gMetricStringTable) < 4294967296, "Metric string table is t const metric_entry_t sMetricByNameLookupEntries[] = { 1152921611981030014ull, - 3458764672734331862ull, - 8646911490709783796ull, - 5764607578868810038ull, - 10376293653130773162ull, - 2305843030688530526ull, - 11529215166327554778ull, - 2882303911840973722ull, - 8646911370450698730ull, + 5764607681948025814ull, + 2305843215372125428ull, + 10376293597296197942ull, + 8070450643917079210ull, + 4611686039902224478ull, + 6917529147900166874ull, + 5188146921054667674ull, + 2305843095113040362ull, 576460756598390784ull, 12105676043185030676ull, 1729382269795172390ull, - 3458764677029299184ull, - 5764607703422862425ull, - 5188146946824471622ull, - 8070450734111392991ull, - 2305843150947615582ull, + 5764607686242993136ull, + 10376293721850250329ull, + 9223372212948436038ull, + 7493989981807969503ull, + 4611686160161309534ull, 576460881152443159ull, - 2305843026393563204ull, + 4611686035607257156ull, 1152921732240115085ull, - 8070450613852307926ull, - 9223372247308174607ull, + 7493989861548884438ull, + 4035225476577363215ull, 1729382394349224767ull, - 4611686190226080815ull, - 10376293773389858234ull, - 5188146822270419236ull, - 2305843082228138388ull, - 10952754529988249045ull, - 10952754409729163972ull, + 9799832960956892207ull, + 8070450764176164282ull, + 9223372088394383652ull, + 4611686091441832340ull, + 8646911520774555093ull, + 8646911400515470020ull, 12105675922925945601ull, - 2882303787286921342ull, - 4035225309073637616ull, + 5188146796500615294ull, + 6341068318287331568ull, 576460945576952990ull, - 11529215286586639852ull, - 2305843155242582905ull, - 2882303916135941045ull, - 6341068335467200838ull, + 6917529268159251948ull, + 4611686164456276857ull, + 5188146925349634997ull, + 10952754353894588742ull, 1152921723650180424ull, 576460821022900600ull, - 6341068460021253226ull, - 9223372251603141927ull, - 4611686065672028430ull, - 3458764552475246801ull, - 9799832887942447675ull, + 10952754478448641130ull, + 4035225480872330535ull, + 9799832836402839822ull, + 5764607561688940753ull, + 2882303860301365819ull, 1152921513196781587ull, - 6917529216619644031ull, + 11529215235047031935ull, 1152921607686062682ull, - 4035225433627690000ull, - 2305843206782190779ull, - 6917529092065591642ull, + 6341068442841383952ull, + 4611686215995884731ull, + 11529215110492979546ull, 1152921727945147752ull, - 9223372131344056859ull, - 3458764548180279480ull, - 9223372127049089540ull, + 4035225360613245467ull, + 5764607557393973432ull, + 4035225356318278148ull, 1152921637750833963ull, - 7493989857253917111ull, - 2882303791581888664ull + 3458764591129952695ull, + 5188146800795582616ull }; diff --git a/toolkit/components/glean/tests/pytest/metrics_test_output_js_h b/toolkit/components/glean/tests/pytest/metrics_test_output_js_h @@ -20,6 +20,30 @@ class nsISupports; namespace mozilla::glean { +enum MetricTypeId { + BOOLEAN = 1, + COUNTER = 2, + CUSTOM_DISTRIBUTION = 3, + DATETIME = 4, + DENOMINATOR = 5, + DUAL_LABELED_COUNTER = 6, + EVENT = 7, + LABELED_BOOLEAN = 8, + LABELED_COUNTER = 9, + LABELED_STRING = 10, + MEMORY_DISTRIBUTION = 11, + NUMERATOR = 12, + OBJECT = 13, + QUANTITY = 14, + RATE = 15, + STRING = 16, + STRING_LIST = 17, + TEXT = 18, + TIMESPAN = 19, + TIMING_DISTRIBUTION = 20, + UUID = 21, +}; + // The category lookup table's entry type using category_entry_t = uint32_t; // The metric lookup table's entry type diff --git a/toolkit/components/glean/tests/xpcshell/test_Glean.js b/toolkit/components/glean/tests/xpcshell/test_Glean.js @@ -982,3 +982,135 @@ add_task(function test_dual_labeled_counter_works() { .testGetValue() ); }); + +add_task(async function test_labeled_metrics_test_get_value_works() { + Services.fog.testResetFOG(); + + // LabeledBoolean + Glean.testOnly.mabelsLikeBalloons.test1.set(true); + Glean.testOnly.mabelsLikeBalloons.test2.set(false); + + const booleanValue = Glean.testOnly.mabelsLikeBalloons.testGetValue(); + Assert.deepEqual( + { + test1: true, + test2: false, + }, + booleanValue + ); + + // LabeledCounter + Glean.testOnly.mabelsLabeledCounters.clean.add(1); + + const counterValue = Glean.testOnly.mabelsLabeledCounters.testGetValue(); + Assert.deepEqual( + { + clean: 1, + }, + counterValue + ); + + // LabeledString + Glean.testOnly.mabelsBalloonStrings.test.set("string!"); + + const stringValue = Glean.testOnly.mabelsBalloonStrings.testGetValue(); + Assert.deepEqual( + { + test: "string!", + }, + stringValue + ); + + // LabeledQuantity + Glean.testOnly.buttonJars.up.set(1); + Glean.testOnly.buttonJars.curling.set(10); + + const quantityValue = Glean.testOnly.buttonJars.testGetValue(); + Assert.deepEqual( + { + up: 1, + curling: 10, + }, + quantityValue + ); + + // LabeledCustomDistribution + Glean.testOnly.mabelsCustomLabelLengths.monospace.accumulateSamples([1, 42]); + Glean.testOnly.mabelsCustomLabelLengths.sanserif.accumulateSingleSample(13); + + const customDistributionValue = + Glean.testOnly.mabelsCustomLabelLengths.testGetValue(); + Assert.deepEqual( + { + monospace: { + count: 2, + sum: 43, + values: { + 1: 2, + }, + }, + sanserif: { + count: 1, + sum: 13, + values: { + 1: 1, + }, + }, + }, + customDistributionValue + ); + + // LabeledMemoryDistribution + Glean.testOnly.whatDoYouRemember.twenty_years_ago.accumulate(7); + Glean.testOnly.whatDoYouRemember.twenty_years_ago.accumulate(17); + + const memoryDistributionValue = + Glean.testOnly.whatDoYouRemember.testGetValue(); + const [first, second] = Object.keys( + memoryDistributionValue.twenty_years_ago.values + ); + Assert.deepEqual( + { + twenty_years_ago: { + count: 2, + sum: 24 * 1024 * 1024, + values: { + [first]: 1, + [second]: 1, + }, + }, + }, + memoryDistributionValue + ); + + // LabeledTimingDistribution + let t1 = Glean.testOnly.whereHasTheTimeGone.west.start(); + let t2 = Glean.testOnly.whereHasTheTimeGone.west.start(); + await sleep(5); + let t3 = Glean.testOnly.whereHasTheTimeGone.west.start(); + Glean.testOnly.whereHasTheTimeGone.west.cancel(t1); + await sleep(5); + Glean.testOnly.whereHasTheTimeGone.west.stopAndAccumulate(t2); // 10ms + Glean.testOnly.whereHasTheTimeGone.west.stopAndAccumulate(t3); // 5ms + + const timingDistributionValue = + Glean.testOnly.whereHasTheTimeGone.testGetValue(); + const NANOS_IN_MILLIS = 1e6; + // bug 1701949 - Sleep gets close, but sometimes doesn't wait long enough. + const EPSILON = 40000; + + // Variance in timing makes getting the sum impossible to know. + const sum = timingDistributionValue.west.sum; + Assert.greater(sum, 15 * NANOS_IN_MILLIS - EPSILON); + Assert.equal(2, Object.keys(timingDistributionValue.west.values).length); + Assert.deepEqual( + { + west: { + sum, + count: 2, + values: timingDistributionValue.west.values, + }, + }, + timingDistributionValue + ); +}); diff --git a/toolkit/content/aboutGlean.js b/toolkit/content/aboutGlean.js @@ -23,7 +23,7 @@ let LIMIT_OFFSET = 0; let LIMIT_COUNT = 200; let METRIC_DATA_INITIALIZED = false; const INVALID_VALUE_REASONS = { - LABELED_METRIC: 0, + DUAL_LABELED_METRIC: 0, UNKNOWN_METRIC: 1, }; const SIMPLE_TYPES = { @@ -794,8 +794,8 @@ function updateValueSelection(selection) { selection ?.attr("data-l10n-id", d => { switch (d.invalidValue) { - case INVALID_VALUE_REASONS.LABELED_METRIC: - return "about-glean-labeled-metric-warning"; + case INVALID_VALUE_REASONS.DUAL_LABELED_METRIC: + return "about-glean-dual-labeled-metric-warning"; case INVALID_VALUE_REASONS.UNKNOWN_METRIC: return "about-glean-unknown-metric-type-warning"; default: @@ -840,8 +840,8 @@ function updateDatum(datum) { } datum.loaded = true; datum.invalidValue = undefined; - } else if (datum.type.includes("Labeled")) { - datum.invalidValue = INVALID_VALUE_REASONS.LABELED_METRIC; + } else if (datum.type.includes("DualLabeled")) { + datum.invalidValue = INVALID_VALUE_REASONS.DUAL_LABELED_METRIC; } else { datum.invalidValue = INVALID_VALUE_REASONS.UNKNOWN_METRIC; } diff --git a/toolkit/locales/en-US/toolkit/about/aboutGlean.ftl b/toolkit/locales/en-US/toolkit/about/aboutGlean.ftl @@ -221,7 +221,7 @@ about-glean-button-unwatch = Unwatch about-glean-no-data-to-display = No data to display. # Do not translate strings between <code> </code> tags. -about-glean-labeled-metric-warning = Labeled metrics are not yet supported in the <code>about:glean</code> view. +about-glean-dual-labeled-metric-warning = <code>DualLabeledCounter</code> metrics are not yet supported in the <code>about:glean</code> view. about-glean-unknown-metric-type-warning = Unknown metric type. about-glean-enable-new-features-promo =