diff --git a/components/misc_metrics/brave_search_metrics.cc b/components/misc_metrics/brave_search_metrics.cc index c7bdc3e4018..0817f3463b6 100644 --- a/components/misc_metrics/brave_search_metrics.cc +++ b/components/misc_metrics/brave_search_metrics.cc @@ -16,6 +16,7 @@ #include "build/build_config.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "components/prefs/scoped_user_pref_update.h" #include "components/search_engines/template_url.h" #include "components/search_engines/template_url_service.h" @@ -23,8 +24,12 @@ namespace misc_metrics { namespace { -constexpr int kDailyQueriesBuckets[] = {0, 3, 7}; +// Buckets for DailyQueries. Answers 0 and 1 are reserved for the zero-query +// cases (no navigation and had navigation respectively), so two dummy leading +// values push real query counts to indices 2 and above. +constexpr int kDailyQueriesBuckets[] = {0, 0, 3, 7}; constexpr char kQueriesCountKey[] = "queries"; +constexpr char kAnyNavigationKey[] = "any_navigation"; constexpr char kPrimaryQueriesCountKey[] = "primary"; constexpr char kOmniboxTypedCountKey[] = "omnibox_typed"; constexpr char kOmniboxSuggestionCountKey[] = "omnibox_suggestion"; @@ -71,6 +76,9 @@ void BraveSearchMetrics::RegisterPrefs(PrefRegistrySimple* registry) { void BraveSearchMetrics::MaybeRecordBraveQuery(const GURL& previous_url, const GURL& current_url) { + ScopedDictPrefUpdate(local_state_, kMiscMetricsBraveSearchQueryCounts) + ->Set(kAnyNavigationKey, true); + if (!IsBraveSearchURL(current_url)) { return; } @@ -148,6 +156,7 @@ void BraveSearchMetrics::ReportAllMetrics() { const base::DictValue& counts = local_state_->GetDict(kMiscMetricsBraveSearchQueryCounts); int sum = counts.FindInt(kQueriesCountKey).value_or(0); + bool any_navigation = counts.FindBool(kAnyNavigationKey).value_or(false); auto* histogram_name_ptr = base::FindOrNull(kDailyQueriesHistogramMap, engine_type); @@ -155,7 +164,13 @@ void BraveSearchMetrics::ReportAllMetrics() { ? *histogram_name_ptr : kSearchDailyQueriesOtherDefaultHistogramName; - p3a_utils::RecordToHistogramBucket(histogram_name, kDailyQueriesBuckets, sum); + if (sum == 0) { + base::UmaHistogramExactLinear(histogram_name, any_navigation ? 1 : 0, + std::size(kDailyQueriesBuckets) + 1); + } else { + p3a_utils::RecordToHistogramBucket(histogram_name, kDailyQueriesBuckets, + sum); + } int primary_queries = counts.FindInt(kPrimaryQueriesCountKey).value_or(0); if (primary_queries > 0) { diff --git a/components/misc_metrics/brave_search_metrics.h b/components/misc_metrics/brave_search_metrics.h index 74c72f08c2d..fb7e1e4ce29 100644 --- a/components/misc_metrics/brave_search_metrics.h +++ b/components/misc_metrics/brave_search_metrics.h @@ -22,15 +22,15 @@ class TemplateURLService; namespace misc_metrics { inline constexpr char kSearchDailyQueriesBraveDefaultHistogramName[] = - "Brave.Search.DailyQueries.BraveDefault"; + "Brave.Search.DailyQueries.BraveDefault.2"; inline constexpr char kSearchDailyQueriesGoogleDefaultHistogramName[] = - "Brave.Search.DailyQueries.GoogleDefault"; + "Brave.Search.DailyQueries.GoogleDefault.2"; inline constexpr char kSearchDailyQueriesDDGDefaultHistogramName[] = - "Brave.Search.DailyQueries.DDGDefault"; + "Brave.Search.DailyQueries.DDGDefault.2"; inline constexpr char kSearchDailyQueriesYahooDefaultHistogramName[] = - "Brave.Search.DailyQueries.YahooDefault"; + "Brave.Search.DailyQueries.YahooDefault.2"; inline constexpr char kSearchDailyQueriesOtherDefaultHistogramName[] = - "Brave.Search.DailyQueries.OtherDefault"; + "Brave.Search.DailyQueries.OtherDefault.2"; inline constexpr char kSearchOmniboxTypedPercentHistogramName[] = "Brave.Search.OmniboxTypedPercent"; inline constexpr char kSearchOmniboxSuggestionPercentHistogramName[] = diff --git a/components/misc_metrics/brave_search_metrics_unittest.cc b/components/misc_metrics/brave_search_metrics_unittest.cc index 85d1cef1aa9..440ea3c048b 100644 --- a/components/misc_metrics/brave_search_metrics_unittest.cc +++ b/components/misc_metrics/brave_search_metrics_unittest.cc @@ -80,9 +80,11 @@ TEST_F(BraveSearchMetricsUnitTest, DailyQueriesBuckets) { // Advance 24 hours then report. FastForwardAndReport(base::Days(1)); - // Should report bucket 1 (3 queries -> 1-3 range). + // Buckets 0 and 1 are reserved for zero-query cases (no navigation / had + // navigation). Real query counts start at index 2. + // Should report bucket 2 (3 queries -> 1-3 range). histogram_tester_.ExpectUniqueSample( - kSearchDailyQueriesBraveDefaultHistogramName, 1, 1); + kSearchDailyQueriesBraveDefaultHistogramName, 2, 1); histogram_tester_.ExpectTotalCount( kSearchDailyQueriesGoogleDefaultHistogramName, 0); histogram_tester_.ExpectTotalCount( @@ -95,9 +97,9 @@ TEST_F(BraveSearchMetricsUnitTest, DailyQueriesBuckets) { FastForwardAndReport(base::Days(1)); - // Should report bucket 2 (7 queries -> 4-7 range). + // Should report bucket 3 (7 queries -> 4-7 range). histogram_tester_.ExpectBucketCount( - kSearchDailyQueriesBraveDefaultHistogramName, 2, 1); + kSearchDailyQueriesBraveDefaultHistogramName, 3, 1); // Record 8 queries in the new window. for (int i = 0; i < 8; i++) { @@ -106,9 +108,9 @@ TEST_F(BraveSearchMetricsUnitTest, DailyQueriesBuckets) { FastForwardAndReport(base::Days(1)); - // Should report bucket 3 (8 queries -> 8+ range). + // Should report bucket 4 (8 queries -> 8+ range). histogram_tester_.ExpectBucketCount( - kSearchDailyQueriesBraveDefaultHistogramName, 3, 1); + kSearchDailyQueriesBraveDefaultHistogramName, 4, 1); histogram_tester_.ExpectTotalCount( kSearchDailyQueriesBraveDefaultHistogramName, 3); @@ -130,9 +132,9 @@ TEST_F(BraveSearchMetricsUnitTest, DailyQueriesEngineSwitch) { // Advance past 24 hours then report. FastForwardAndReport(base::Days(1)); - // Should report under Google (3 queries -> bucket 1). + // Should report under Google (3 queries -> bucket 2, 1-3 range). histogram_tester_.ExpectUniqueSample( - kSearchDailyQueriesGoogleDefaultHistogramName, 1, 1); + kSearchDailyQueriesGoogleDefaultHistogramName, 2, 1); histogram_tester_.ExpectTotalCount( kSearchDailyQueriesBraveDefaultHistogramName, 0); histogram_tester_.ExpectTotalCount(kSearchDailyQueriesDDGDefaultHistogramName, @@ -153,13 +155,13 @@ TEST_F(BraveSearchMetricsUnitTest, DailyQueriesEngineSwitch) { // Advance past 24 hours then report. FastForwardAndReport(base::Days(1)); - // Should report under OtherDefault (5 queries -> bucket 2). + // Should report under OtherDefault (5 queries -> bucket 3, 4-7 range). histogram_tester_.ExpectUniqueSample( - kSearchDailyQueriesOtherDefaultHistogramName, 2, 1); + kSearchDailyQueriesOtherDefaultHistogramName, 3, 1); histogram_tester_.ExpectTotalCount( kSearchDailyQueriesBraveDefaultHistogramName, 0); histogram_tester_.ExpectUniqueSample( - kSearchDailyQueriesGoogleDefaultHistogramName, 1, 1); + kSearchDailyQueriesGoogleDefaultHistogramName, 2, 1); histogram_tester_.ExpectTotalCount(kSearchDailyQueriesDDGDefaultHistogramName, 0); histogram_tester_.ExpectTotalCount( @@ -176,13 +178,13 @@ TEST_F(BraveSearchMetricsUnitTest, DailyQueriesEngineSwitch) { // Advance past 24 hours then report. FastForwardAndReport(base::Days(1)); - // Should report under BraveDefault (8 queries -> bucket 3). + // Should report under BraveDefault (8 queries -> bucket 4, 8+ range). histogram_tester_.ExpectUniqueSample( - kSearchDailyQueriesBraveDefaultHistogramName, 3, 1); + kSearchDailyQueriesBraveDefaultHistogramName, 4, 1); histogram_tester_.ExpectUniqueSample( - kSearchDailyQueriesOtherDefaultHistogramName, 2, 1); + kSearchDailyQueriesOtherDefaultHistogramName, 3, 1); histogram_tester_.ExpectUniqueSample( - kSearchDailyQueriesGoogleDefaultHistogramName, 1, 1); + kSearchDailyQueriesGoogleDefaultHistogramName, 2, 1); histogram_tester_.ExpectTotalCount(kSearchDailyQueriesDDGDefaultHistogramName, 0); histogram_tester_.ExpectTotalCount( @@ -195,9 +197,9 @@ TEST_F(BraveSearchMetricsUnitTest, CountsClearedAfterReport) { // Advance past 24 hours then report. FastForwardAndReport(base::Days(1)); - // Previous window reported 1 query -> bucket 1. + // Previous window reported 1 query -> bucket 2 (1-3 range). histogram_tester_.ExpectBucketCount( - kSearchDailyQueriesBraveDefaultHistogramName, 1, 1); + kSearchDailyQueriesBraveDefaultHistogramName, 2, 1); // Record 1 query in the new window. brave_search_metrics_->MaybeRecordBraveQuery(empty_url_, brave_search_url_); @@ -207,7 +209,7 @@ TEST_F(BraveSearchMetricsUnitTest, CountsClearedAfterReport) { // Should report 1 query again for the new window. histogram_tester_.ExpectBucketCount( - kSearchDailyQueriesBraveDefaultHistogramName, 1, 2); + kSearchDailyQueriesBraveDefaultHistogramName, 2, 2); } TEST_F(BraveSearchMetricsUnitTest, ClearQueryCounts) { @@ -224,11 +226,36 @@ TEST_F(BraveSearchMetricsUnitTest, ClearQueryCounts) { // Advance past 24 hours and report. FastForwardAndReport(base::Days(1)); - // Should report bucket 0 (0 queries) since counts were cleared. + // Counts cleared means sum=0 and any_navigation=false -> bucket 0. histogram_tester_.ExpectUniqueSample( kSearchDailyQueriesBraveDefaultHistogramName, 0, 1); } +TEST_F(BraveSearchMetricsUnitTest, DailyQueriesNoNavigationReportsZero) { + // No queries and no navigation in this window -> bucket 0. + FastForwardAndReport(base::Days(1)); + histogram_tester_.ExpectUniqueSample( + kSearchDailyQueriesBraveDefaultHistogramName, 0, 1); + + // After reset, another empty window also reports bucket 0. + FastForwardAndReport(base::Days(1)); + histogram_tester_.ExpectBucketCount( + kSearchDailyQueriesBraveDefaultHistogramName, 0, 2); +} + +TEST_F(BraveSearchMetricsUnitTest, + DailyQueriesNavigationButNoSearchReportsOne) { + // Navigate to a non-search URL: sets any_navigation=true but sum stays 0. + const GURL non_search_url{"https://example.com"}; + brave_search_metrics_->MaybeRecordBraveQuery(empty_url_, non_search_url); + + FastForwardAndReport(base::Days(1)); + + // any_navigation=true, sum=0 -> bucket 1. + histogram_tester_.ExpectUniqueSample( + kSearchDailyQueriesBraveDefaultHistogramName, 1, 1); +} + TEST_F(BraveSearchMetricsUnitTest, NoReportBeforeFrameExpires) { // Record queries within the 24-hour window. for (int i = 0; i < 5; i++) { diff --git a/components/p3a/metric_names.h b/components/p3a/metric_names.h index 5f6030bee9d..87d36758345 100644 --- a/components/p3a/metric_names.h +++ b/components/p3a/metric_names.h @@ -274,27 +274,27 @@ inline constexpr auto kCollectedExpressHistograms = .ephemeral = true, .attributes = MetricAttributes{MetricAttribute::kAnswerIndex, MetricAttribute::kVersion, MetricAttribute::kChannel, MetricAttribute::kPlatform, MetricAttribute::kCountryCode}, }}, - {"Brave.Search.DailyQueries.BraveDefault", MetricConfig{ + {"Brave.Search.DailyQueries.BraveDefault.2", MetricConfig{ .ephemeral = true, .attributes = MetricAttributes{MetricAttribute::kIsBrowserDefault, MetricAttribute::kAnswerIndex, MetricAttribute::kCustomAttribute, MetricAttribute::kCountryCode, MetricAttribute::kPlatform, MetricAttribute::kYoi}, .custom_attributes = {"media_session_usage"}, }}, - {"Brave.Search.DailyQueries.DDGDefault", MetricConfig{ + {"Brave.Search.DailyQueries.DDGDefault.2", MetricConfig{ .ephemeral = true, .attributes = MetricAttributes{MetricAttribute::kIsBrowserDefault, MetricAttribute::kAnswerIndex, MetricAttribute::kCustomAttribute, MetricAttribute::kCountryCode, MetricAttribute::kPlatform, MetricAttribute::kYoi}, .custom_attributes = {"media_session_usage"}, }}, - {"Brave.Search.DailyQueries.GoogleDefault", MetricConfig{ + {"Brave.Search.DailyQueries.GoogleDefault.2", MetricConfig{ .ephemeral = true, .attributes = MetricAttributes{MetricAttribute::kIsBrowserDefault, MetricAttribute::kAnswerIndex, MetricAttribute::kCustomAttribute, MetricAttribute::kCountryCode, MetricAttribute::kPlatform, MetricAttribute::kYoi}, .custom_attributes = {"media_session_usage"}, }}, - {"Brave.Search.DailyQueries.OtherDefault", MetricConfig{ + {"Brave.Search.DailyQueries.OtherDefault.2", MetricConfig{ .ephemeral = true, .attributes = MetricAttributes{MetricAttribute::kIsBrowserDefault, MetricAttribute::kAnswerIndex, MetricAttribute::kCustomAttribute, MetricAttribute::kCountryCode, MetricAttribute::kPlatform, MetricAttribute::kYoi}, .custom_attributes = {"media_session_usage"}, }}, - {"Brave.Search.DailyQueries.YahooDefault", MetricConfig{ + {"Brave.Search.DailyQueries.YahooDefault.2", MetricConfig{ .ephemeral = true, .attributes = MetricAttributes{MetricAttribute::kIsBrowserDefault, MetricAttribute::kAnswerIndex, MetricAttribute::kCustomAttribute, MetricAttribute::kCountryCode, MetricAttribute::kPlatform, MetricAttribute::kYoi}, .custom_attributes = {"media_session_usage"},