tor-browser

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

commit 8c5a5504e9841668e60b1292e481e549f0492e65
parent 93e210ba11011cbc6f156d82c2d81b9ea8f1b453
Author: Bas Schouten <bschouten@mozilla.com>
Date:   Wed,  8 Oct 2025 15:12:46 +0000

Bug 1988716 - Part 2: Add ProcessGet() function to labeled metrics. r=chutten,toolkit-telemetry-reviewers

This patch allows labeled metrics to easily and in a standardized manner label themselves according to the process they're recorded in. It does this by adding a base a ProcessGet() function that automatically creates a label for the right process.

In the process I've also cleaned up the code to use a single template rather than a set of specializations to increase code re-use, and using compile time evaluations to ensure no additional code is generated.

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

Diffstat:
Mtoolkit/components/glean/bindings/private/Labeled.cpp | 28++++++++++++++++++++++++++++
Mtoolkit/components/glean/bindings/private/Labeled.h | 529++++++++++++++++++-------------------------------------------------------------
Mtoolkit/components/glean/tests/gtest/TestFog.cpp | 9+++++++++
3 files changed, 157 insertions(+), 409 deletions(-)

diff --git a/toolkit/components/glean/bindings/private/Labeled.cpp b/toolkit/components/glean/bindings/private/Labeled.cpp @@ -12,6 +12,9 @@ #include "mozilla/glean/bindings/MetricTypes.h" #include "mozilla/glean/bindings/ScalarGIFFTMap.h" #include "nsString.h" +#include "nsXULAppAPI.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/RemoteType.h" namespace mozilla::glean { @@ -52,4 +55,29 @@ void GleanLabeled::GetSupportedNames(nsTArray<nsString>& aNames) { // We really don't know, so don't do anything. } +namespace impl { + +// Helper function to get the current process type string for telemetry labeling +nsCString GetProcessTypeForTelemetry() { + nsCString processType(XRE_GetProcessTypeString()); + + // For content processes, check the specific remote type + if (processType.EqualsLiteral("tab")) { + auto* cc = mozilla::dom::ContentChild::GetSingleton(); + if (cc) { + const nsACString& remoteType = cc->GetRemoteType(); + if (remoteType == EXTENSION_REMOTE_TYPE) { + processType.AssignLiteral("extension"); + } else if (remoteType == INFERENCE_REMOTE_TYPE) { + processType.AssignLiteral("inference"); + } + // Otherwise keep "tab" for regular content processes + } + } + + return processType; +} + +} // namespace impl + } // namespace mozilla::glean diff --git a/toolkit/components/glean/bindings/private/Labeled.h b/toolkit/components/glean/bindings/private/Labeled.h @@ -28,39 +28,8 @@ namespace mozilla::glean { namespace impl { -template <typename T, typename E> -class Labeled { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - /** - * Gets a specific metric for a given label. - * - * If a set of acceptable labels were specified in the `metrics.yaml` file, - * and the given label is not in the set, it will be recorded under the - * special `OTHER_LABEL` label. - * - * If a set of acceptable labels was not specified in the `metrics.yaml` file, - * only the first 16 unique labels will be used. - * After that, any additional labels will be recorded under the special - * `OTHER_LABEL` label. - * - * @param aLabel - a snake_case string under 30 characters in length, - * otherwise the metric will be recorded under the special - * `OTHER_LABEL` label and an error will be recorded. - */ - T Get(const nsACString& aLabel) const; - - /** - * Gets a specific metric for a given label, using the label's enum variant. - * - * @param aLabel - a variant of this label's label enum. - */ - T EnumGet(E aLabel) const; - - private: - const uint32_t mId; -}; +// Helper function to get the current process type string for telemetry labeling +nsCString GetProcessTypeForTelemetry(); static inline void UpdateLabeledMirror(Telemetry::ScalarID aMirrorId, uint32_t aSubmetricId, @@ -82,333 +51,114 @@ static inline void UpdateLabeledDistributionMirror( }); } -template <typename E> -class Labeled<BooleanMetric, E> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - BooleanMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_boolean_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored scalar so we can mirror its operations. - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - UpdateLabeledMirror(mirrorId.extract(), submetricId, aLabel); - } - return BooleanMetric(submetricId); - } - - BooleanMetric EnumGet(E aLabel) const { - auto submetricId = - fog_labeled_boolean_enum_get(mId, static_cast<uint16_t>(aLabel)); - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - // Telemetry's keyed scalars operate on (16-bit) strings, - // so we're going to need the string for this enum. - nsCString label; - fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); - UpdateLabeledMirror(mirrorId.extract(), submetricId, label); - } - return BooleanMetric(submetricId); - } - - private: - const uint32_t mId; -}; - -template <typename E> -class Labeled<CounterMetric<CounterType::eBaseOrLabeled>, E> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - CounterMetric<CounterType::eBaseOrLabeled> Get( - const nsACString& aLabel) const { - auto submetricId = fog_labeled_counter_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored scalar so we can mirror its operations. - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - UpdateLabeledMirror(mirrorId.extract(), submetricId, aLabel); - } else if (auto mirrorHgramId = HistogramIdForMetric(mId)) { - UpdateLabeledDistributionMirror(mirrorHgramId.extract(), submetricId, - aLabel); - } - return CounterMetric<CounterType::eBaseOrLabeled>(submetricId); - } - - CounterMetric<CounterType::eBaseOrLabeled> EnumGet(E aLabel) const { - auto submetricId = - fog_labeled_counter_enum_get(mId, static_cast<uint16_t>(aLabel)); - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - // Telemetry's keyed scalars operate on (16-bit) strings, - // so we're going to need the string for this enum. - nsCString label; - fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); - UpdateLabeledMirror(mirrorId.extract(), submetricId, label); - } else if (auto mirrorHgramId = HistogramIdForMetric(mId)) { - nsCString label; - fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); - UpdateLabeledDistributionMirror(mirrorHgramId.extract(), submetricId, - label); - } - return CounterMetric<CounterType::eBaseOrLabeled>(submetricId); - } +template <typename T> +inline uint32_t fog_labeled_get(uint32_t aId, const nsACString* aLabel); +template <typename T> +inline uint32_t fog_labeled_enum_get(uint32_t aId, uint16_t aLabel); + +#define FOG_LABEL_TYPE_MAP(type, name) \ + template <> \ + inline uint32_t fog_labeled_get<type>(uint32_t aId, \ + const nsACString* aLabel) { \ + return fog_labeled_##name##_get(aId, aLabel); \ + } \ + template <> \ + inline uint32_t fog_labeled_enum_get<type>(uint32_t aId, uint16_t aLabel) { \ + return fog_labeled_##name##_enum_get(aId, aLabel); \ + } + +FOG_LABEL_TYPE_MAP(BooleanMetric, boolean) +FOG_LABEL_TYPE_MAP(QuantityMetric, quantity) +FOG_LABEL_TYPE_MAP(StringMetric, string) +FOG_LABEL_TYPE_MAP(CounterMetric<CounterType::eBaseOrLabeled>, counter) +FOG_LABEL_TYPE_MAP(CustomDistributionMetric, custom_distribution) +FOG_LABEL_TYPE_MAP(MemoryDistributionMetric, memory_distribution) +FOG_LABEL_TYPE_MAP(TimingDistributionMetric, timing_distribution) - private: - const uint32_t mId; -}; - -template <typename E> -class Labeled<CustomDistributionMetric, E> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - CustomDistributionMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_custom_distribution_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored hgram so we can mirror its operations. - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, aLabel); - } - return CustomDistributionMetric(submetricId); - } - - CustomDistributionMetric EnumGet(E aLabel) const { - auto submetricId = fog_labeled_custom_distribution_enum_get( - mId, static_cast<uint16_t>(aLabel)); - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - // Telemetry's keyed histograms operate on strings, - // so we're going to need to store the string for this enum. - nsCString label; - fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, label); - } - return CustomDistributionMetric(submetricId); - } - - private: - const uint32_t mId; -}; - -template <typename E> -class Labeled<MemoryDistributionMetric, E> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - MemoryDistributionMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_memory_distribution_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored hgram so we can mirror its operations. - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, aLabel); - } - return MemoryDistributionMetric(submetricId); - } - - MemoryDistributionMetric EnumGet(E aLabel) const { - auto submetricId = fog_labeled_memory_distribution_enum_get( - mId, static_cast<uint16_t>(aLabel)); - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - // Telemetry's keyed histograms operate on strings, - // so we're going to need to store the string for this enum. - nsCString label; - fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, label); - } - return MemoryDistributionMetric(submetricId); - } - - private: - const uint32_t mId; -}; - -template <typename E> -class Labeled<QuantityMetric, E> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - QuantityMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_quantity_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored scalar so we can mirror its operations. - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - UpdateLabeledMirror(mirrorId.extract(), submetricId, aLabel); - } - return QuantityMetric(submetricId); - } - - QuantityMetric EnumGet(E aLabel) const { - auto submetricId = - fog_labeled_quantity_enum_get(mId, static_cast<uint16_t>(aLabel)); - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - // Telemetry's keyed scalars operate on (16-bit) strings, - // so we're going to need the string for this enum. - nsCString label; - fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); - UpdateLabeledMirror(mirrorId.extract(), submetricId, label); - } - return QuantityMetric(submetricId); - } - - private: - const uint32_t mId; -}; - -template <typename E> -class Labeled<StringMetric, E> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - StringMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_string_get(mId, &aLabel); - // Why no GIFFT map here? - // Labeled Strings can't be mirrored. Telemetry has no compatible probe. - return StringMetric(submetricId); - } - - StringMetric EnumGet(E aLabel) const { - auto submetricId = - fog_labeled_string_enum_get(mId, static_cast<uint16_t>(aLabel)); - // Why no GIFFT map here? - // Labeled Strings can't be mirrored. Telemetry has no compatible probe. - return StringMetric(submetricId); - } - - private: - const uint32_t mId; -}; - -template <typename E> -class Labeled<TimingDistributionMetric, E> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - TimingDistributionMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_timing_distribution_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored hgram so we can mirror its operations. - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, aLabel); - } - return TimingDistributionMetric(submetricId); - } - - TimingDistributionMetric EnumGet(E aLabel) const { - auto submetricId = fog_labeled_timing_distribution_enum_get( - mId, static_cast<uint16_t>(aLabel)); - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - // Telemetry's keyed histograms operate on strings, - // so we're going to need to store the string for this enum. - nsCString label; - fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, label); - } - return TimingDistributionMetric(submetricId); - } - - private: - const uint32_t mId; -}; - -template <> -class Labeled<BooleanMetric, DynamicLabel> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - BooleanMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_boolean_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored scalar so we can mirror its operations. - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - UpdateLabeledMirror(mirrorId.extract(), submetricId, aLabel); - } - return BooleanMetric(submetricId); - } - - BooleanMetric EnumGet(DynamicLabel aLabel) const = delete; - - private: - const uint32_t mId; -}; - -template <> -class Labeled<CounterMetric<CounterType::eBaseOrLabeled>, DynamicLabel> { +template <typename T, typename E> +class Labeled { public: constexpr explicit Labeled(uint32_t id) : mId(id) {} - CounterMetric<CounterType::eBaseOrLabeled> Get( - const nsACString& aLabel) const { - auto submetricId = fog_labeled_counter_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored scalar so we can mirror its operations. - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - UpdateLabeledMirror(mirrorId.extract(), submetricId, aLabel); - } else if (auto mirrorHgramId = HistogramIdForMetric(mId)) { - UpdateLabeledDistributionMirror(mirrorHgramId.extract(), submetricId, - aLabel); - } - return CounterMetric<CounterType::eBaseOrLabeled>(submetricId); - } - - CounterMetric<CounterType::eBaseOrLabeled> EnumGet( - DynamicLabel aLabel) const = delete; - - private: - const uint32_t mId; -}; - -template <> -class Labeled<CustomDistributionMetric, DynamicLabel> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} + /** + * Gets a specific metric for a given label. + * + * If a set of acceptable labels were specified in the `metrics.yaml` file, + * and the given label is not in the set, it will be recorded under the + * special `OTHER_LABEL` label. + * + * If a set of acceptable labels was not specified in the `metrics.yaml` file, + * only the first 16 unique labels will be used. + * After that, any additional labels will be recorded under the special + * `OTHER_LABEL` label. + * + * @param aLabel - a snake_case string under 30 characters in length, + * otherwise the metric will be recorded under the special + * `OTHER_LABEL` label and an error will be recorded. + */ + T Get(const nsACString& aLabel) const { + uint32_t submetricId = fog_labeled_get<T>(mId, &aLabel); - CustomDistributionMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_custom_distribution_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored hgram so we can mirror its operations. - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, aLabel); + Maybe<ScalarID> mirrorId; + if constexpr (MayBeScalarMirror()) { + mirrorId = ScalarIdForMetric(mId); + if (mirrorId) { + UpdateLabeledMirror(mirrorId.extract(), submetricId, aLabel); + } } - return CustomDistributionMetric(submetricId); - } - - CustomDistributionMetric EnumGet(DynamicLabel aLabel) const = delete; - - private: - const uint32_t mId; -}; - -template <> -class Labeled<TimingDistributionMetric, DynamicLabel> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - TimingDistributionMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_memory_distribution_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored hgram so we can mirror its operations. - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, aLabel); + if constexpr (MayBeDistributionMirror()) { + if (!mirrorId) { + if (Maybe<HistogramID> mirrorHgramId = HistogramIdForMetric(mId)) { + UpdateLabeledDistributionMirror(mirrorHgramId.extract(), submetricId, + aLabel); + } + } } - return TimingDistributionMetric(submetricId); + return T(submetricId); } - TimingDistributionMetric EnumGet(DynamicLabel aLabel) const = delete; - - TimingDistributionMetric MaybeTruncateAndGet(const nsACString& aLabel) const { + /** + * Gets a specific metric for a given label, using the label's enum variant. + * + * @param aLabel - a variant of this label's label enum. + */ + template <typename U = T> + std::enable_if_t<!std::is_same_v<U, DynamicLabel>, T> EnumGet( + E aLabel) const { + uint32_t submetricId = + fog_labeled_enum_get<T>(mId, static_cast<uint16_t>(aLabel)); + + Maybe<ScalarID> mirrorId; + if constexpr (MayBeScalarMirror()) { + mirrorId = ScalarIdForMetric(mId); + if (mirrorId) { + // Telemetry's keyed scalars operate on (16-bit) strings, + // so we're going to need the string for this enum. + nsCString label; + fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); + UpdateLabeledMirror(mirrorId.extract(), submetricId, label); + } + } + if constexpr (MayBeDistributionMirror()) { + if (!mirrorId) { + if (Maybe<HistogramID> mirrorHgramId = HistogramIdForMetric(mId)) { + nsCString label; + fog_labeled_enum_to_str(mId, static_cast<uint16_t>(aLabel), &label); + UpdateLabeledDistributionMirror(mirrorHgramId.extract(), submetricId, + label); + } + } + } + return T(submetricId); + } + + // This is a workaround only needed in a rare case, ensure it's only compiled + // there. + template <typename U = T, typename V = E> + std::enable_if_t<std::is_same_v<U, TimingDistributionMetric> && + std::is_same_v<V, DynamicLabel>, + T> + MaybeTruncateAndGet(const nsACString& aLabel) const { // bug 1959765 is for incorporating this behaviour into the SDK. if (aLabel.Length() < 112) { return Get(aLabel); @@ -419,70 +169,31 @@ class Labeled<TimingDistributionMetric, DynamicLabel> { return Get(truncated); } - private: - const uint32_t mId; -}; - -template <> -class Labeled<QuantityMetric, DynamicLabel> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - QuantityMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_quantity_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored scalar so we can mirror its operations. - auto mirrorId = ScalarIdForMetric(mId); - if (mirrorId) { - UpdateLabeledMirror(mirrorId.extract(), submetricId, aLabel); - } - return QuantityMetric(submetricId); - } + /** + * Gets a specific metric for the current process type. + * + * Automatically determines the process type and returns the appropriate + * labeled metric instance. For content processes, distinguishes between + * regular "tab" processes, "inference" processes, and "extension" processes. + */ + T ProcessGet() const { return Get(GetProcessTypeForTelemetry()); } - QuantityMetric EnumGet(DynamicLabel aLabel) const = delete; + protected: + uint32_t mId; private: - const uint32_t mId; -}; - -template <> -class Labeled<StringMetric, DynamicLabel> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - StringMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_string_get(mId, &aLabel); - // Why no GIFFT map here? - // Labeled Strings can't be mirrored. Telemetry has no compatible probe. - return StringMetric(submetricId); + static constexpr bool MayBeScalarMirror() { + return std::is_same_v<T, BooleanMetric> || + std::is_same_v<T, CounterMetric<CounterType::eBaseOrLabeled>> || + std::is_same_v<T, QuantityMetric>; } - StringMetric EnumGet(DynamicLabel aLabel) const = delete; - - private: - const uint32_t mId; -}; - -template <> -class Labeled<MemoryDistributionMetric, DynamicLabel> { - public: - constexpr explicit Labeled(uint32_t id) : mId(id) {} - - MemoryDistributionMetric Get(const nsACString& aLabel) const { - auto submetricId = fog_labeled_timing_distribution_get(mId, &aLabel); - // If this labeled metric is mirrored, we need to map the submetric id back - // to the label string and mirrored hgram so we can mirror its operations. - auto mirrorId = HistogramIdForMetric(mId); - if (mirrorId) { - UpdateLabeledDistributionMirror(mirrorId.extract(), submetricId, aLabel); - } - return MemoryDistributionMetric(submetricId); + static constexpr bool MayBeDistributionMirror() { + return std::is_same_v<T, CounterMetric<CounterType::eBaseOrLabeled>> || + std::is_same_v<T, CustomDistributionMetric> || + std::is_same_v<T, MemoryDistributionMetric> || + std::is_same_v<T, TimingDistributionMetric>; } - - MemoryDistributionMetric EnumGet(DynamicLabel aLabel) const = delete; - - private: - const uint32_t mId; }; } // namespace impl diff --git a/toolkit/components/glean/tests/gtest/TestFog.cpp b/toolkit/components/glean/tests/gtest/TestFog.cpp @@ -437,6 +437,15 @@ TEST_F(FOGFixture, TestLabeledCounterWithLabelsWorks) { .ref()); } +TEST_F(FOGFixture, TestLabeledCounterProcessGetWorks) { + test_only::mabels_kitchen_counters.ProcessGet().Add(5); + + ASSERT_EQ(5, test_only::mabels_kitchen_counters.Get("default"_ns) + .TestGetValue() + .unwrap() + .ref()); +} + TEST_F(FOGFixture, TestLabeledStringWorks) { ASSERT_EQ(mozilla::Nothing(), test_only::mabels_balloon_strings.Get("twine"_ns)