Commit 1c3f4126 authored by Max Curran's avatar Max Curran Committed by Commit Bot

Added page load UMA metrics for the trigger decision of the initial

state of Translate.

At the beginning of a page load, Translate looks at many different
signals to determine if: 1) the page should automatically be translated,
2) the translate UI should be shown, or 3) nothing should be done
related to translate. These new metrics record which signal caused the
initial state (called trigger decision). In the event that multiple
signals were true, only the first value is recorded.

Full design doc: https://docs.google.com/document/d/1dyWh1Xw5VgUA00VA-5PTgKQ6ItziPBnSyeDR8saJ9vM/edit?usp=sharing
More details on trigger decision: https://docs.google.com/document/d/11TJqU_YyJoxJE1huEqKECBa_OZ05O4WESXMJ2WeT4F0/edit?usp=sharing

Bug: 1114868
Change-Id: I48d296cacc157741124db09db166a253a95b37be
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2490676Reviewed-by: default avatarIlya Sherman <isherman@chromium.org>
Reviewed-by: default avatarWeilun Shi <sweilun@chromium.org>
Reviewed-by: default avatarScott Little <sclittle@chromium.org>
Reviewed-by: default avatarRyan Sturm <ryansturm@chromium.org>
Commit-Queue: Max Curran <curranmax@chromium.org>
Cr-Commit-Position: refs/heads/master@{#823370}
parent 64b8c765
......@@ -40,6 +40,16 @@ class MockTranslateMetricsLoggerContainer
ranker_version);
}
void LogTriggerDecision(
translate::TriggerDecision trigger_decision) override {
mock_translate_metrics_logger_->LogTriggerDecision(trigger_decision);
}
void LogAutofillAssistantDeferredTriggerDecision() override {
mock_translate_metrics_logger_
->LogAutofillAssistantDeferredTriggerDecision();
}
private:
translate::testing::MockTranslateMetricsLogger*
mock_translate_metrics_logger_; // Weak.
......
......@@ -26,6 +26,8 @@ class MockTranslateMetricsLogger : public TranslateMetricsLogger {
MOCK_METHOD1(OnForegroundChange, void(bool));
MOCK_METHOD1(RecordMetrics, void(bool));
MOCK_METHOD2(LogRankerMetrics, void(RankerDecision, uint32_t));
MOCK_METHOD1(LogTriggerDecision, void(TriggerDecision));
MOCK_METHOD0(LogAutofillAssistantDeferredTriggerDecision, void());
};
} // namespace testing
......
......@@ -775,6 +775,14 @@ const TranslateTriggerDecision TranslateManager::ComputePossibleOutcomes(
}
FilterForUserPrefs(&decision, translate_prefs, page_language_code);
if (decision.should_suppress_from_ranker()) {
// Delay logging this until after FilterForUserPrefs because TriggerDecision
// values from FilterForUserPrefs have higher priority.
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledByRanker);
}
FilterAutoTranslate(&decision, translate_prefs, page_language_code);
FilterForHrefTranslate(&decision, translate_prefs, page_language_code);
FilterForPredefinedTarget(&decision, translate_prefs, page_language_code);
......@@ -796,12 +804,16 @@ void TranslateManager::FilterIsTranslatePossible(
decision->PreventAllTriggering();
decision->initiation_statuses.push_back(
TranslateBrowserMetrics::INITIATION_STATUS_DOESNT_NEED_TRANSLATION);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledDoesntNeedTranslation);
}
if (!base::FeatureList::IsEnabled(translate::kTranslate)) {
decision->PreventAllTriggering();
decision->initiation_statuses.push_back(
TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_SWITCH);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledTranslationFeatureDisabled);
}
// Also, skip if the connection is currently offline - initiation doesn't make
......@@ -810,6 +822,8 @@ void TranslateManager::FilterIsTranslatePossible(
decision->PreventAllTriggering();
decision->initiation_statuses.push_back(
TranslateBrowserMetrics::INITIATION_STATUS_NO_NETWORK);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledOffline);
}
// Skip translation if autofill assistant is running.
......@@ -819,6 +833,8 @@ void TranslateManager::FilterIsTranslatePossible(
decision->initiation_statuses.push_back(
TranslateBrowserMetrics::
INITIATION_STATUS_DISABLED_BY_AUTOFILL_ASSISTANT);
GetActiveTranslateMetricsLogger()
->LogAutofillAssistantDeferredTriggerDecision();
}
if (!ignore_missing_key_for_testing_ &&
......@@ -830,6 +846,8 @@ void TranslateManager::FilterIsTranslatePossible(
decision->PreventAllTriggering();
decision->initiation_statuses.push_back(
TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_KEY);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledMissingAPIKey);
}
// MHTML pages currently cannot be translated.
......@@ -838,6 +856,8 @@ void TranslateManager::FilterIsTranslatePossible(
decision->PreventAllTriggering();
decision->initiation_statuses.push_back(
TranslateBrowserMetrics::INITIATION_STATUS_MIME_TYPE_IS_NOT_SUPPORTED);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledMIMETypeNotSupported);
}
// Don't translate any Chrome specific page, e.g., New Tab Page, Download,
......@@ -847,6 +867,8 @@ void TranslateManager::FilterIsTranslatePossible(
decision->PreventAllTriggering();
decision->initiation_statuses.push_back(
TranslateBrowserMetrics::INITIATION_STATUS_URL_IS_NOT_SUPPORTED);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledURLNotSupported);
}
if (!translate_prefs->IsOfferTranslateEnabled()) {
......@@ -855,6 +877,8 @@ void TranslateManager::FilterIsTranslatePossible(
TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_PREFS);
decision->ranker_events.push_back(
metrics::TranslateEventProto::DISABLED_BY_PREF);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledNeverOfferTranslations);
}
// Don't translate similar languages (ex: en-US to en).
......@@ -866,6 +890,8 @@ void TranslateManager::FilterIsTranslatePossible(
decision->PreventShowingUI();
decision->initiation_statuses.push_back(
TranslateBrowserMetrics::INITIATION_STATUS_SIMILAR_LANGUAGES);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledSimilarLanguages);
}
// Nothing to do if either the language Chrome is in or the language of
......@@ -881,6 +907,8 @@ void TranslateManager::FilterIsTranslatePossible(
TranslateBrowserMetrics::INITIATION_STATUS_LANGUAGE_IS_NOT_SUPPORTED);
decision->ranker_events.push_back(
metrics::TranslateEventProto::UNSUPPORTED_LANGUAGE);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledUnsupportedLanguage);
}
}
......@@ -903,6 +931,8 @@ void TranslateManager::FilterAutoTranslate(
TranslateBrowserMetrics::INITIATION_STATUS_AUTO_BY_CONFIG);
decision->ranker_events.push_back(
metrics::TranslateEventProto::AUTO_TRANSLATION_BY_PREF);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kAutomaticTranslationByPref);
} else if (!link_auto_translate_target.empty()) {
// This page was navigated through a click from a translated page.
decision->auto_translate_target = link_auto_translate_target;
......@@ -910,6 +940,8 @@ void TranslateManager::FilterAutoTranslate(
TranslateBrowserMetrics::INITIATION_STATUS_AUTO_BY_LINK);
decision->ranker_events.push_back(
metrics::TranslateEventProto::AUTO_TRANSLATION_BY_LINK);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kAutomaticTranslationByLink);
}
if (decision->auto_translate_target.empty()) {
......@@ -950,6 +982,8 @@ void TranslateManager::FilterForUserPrefs(
TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_CONFIG);
decision->ranker_events.push_back(
metrics::TranslateEventProto::LANGUAGE_DISABLED_BY_USER_CONFIG);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledNeverTranslateLanguage);
}
// Don't translate any user black-listed URLs.
......@@ -978,6 +1012,8 @@ void TranslateManager::FilterForUserPrefs(
TranslateBrowserMetrics::INITIATION_STATUS_DISABLED_BY_CONFIG);
decision->ranker_events.push_back(
metrics::TranslateEventProto::URL_DISABLED_BY_USER_CONFIG);
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kDisabledNeverTranslateSite);
}
}
......@@ -1088,6 +1124,10 @@ bool TranslateManager::MaterializeDecision(
decision.href_translate_target, TranslateErrors::NONE, false);
}
if (did_show_ui)
GetActiveTranslateMetricsLogger()->LogTriggerDecision(
TriggerDecision::kShowUI);
return did_show_ui;
}
......
......@@ -19,6 +19,28 @@ enum class RankerDecision {
kMaxValue = kDontShowUI,
};
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class TriggerDecision {
kUninitialized = 0,
kDisabledDoesntNeedTranslation = 1,
kDisabledTranslationFeatureDisabled = 2,
kDisabledOffline = 3,
kDisabledMissingAPIKey = 4,
kDisabledMIMETypeNotSupported = 5,
kDisabledURLNotSupported = 6,
kDisabledNeverOfferTranslations = 7,
kDisabledSimilarLanguages = 8,
kDisabledUnsupportedLanguage = 9,
kDisabledNeverTranslateLanguage = 10,
kDisabledNeverTranslateSite = 11,
kDisabledByRanker = 12,
kShowUI = 13,
kAutomaticTranslationByLink = 14,
kAutomaticTranslationByPref = 15,
kMaxValue = kAutomaticTranslationByPref,
};
// TranslateMetricsLogger tracks and logs various UKM and UMA metrics for Chrome
// Translate over the course of a page load.
class TranslateMetricsLogger {
......@@ -39,6 +61,12 @@ class TranslateMetricsLogger {
virtual void LogRankerMetrics(RankerDecision ranker_decision,
uint32_t ranker_version) = 0;
// Records trigger decision that impacts the initial state of Translate. The
// highest priority trigger decision will be logged to UMA at the end of the
// page load.
virtual void LogTriggerDecision(TriggerDecision trigger_decision) = 0;
virtual void LogAutofillAssistantDeferredTriggerDecision() = 0;
};
} // namespace translate
......
......@@ -9,10 +9,14 @@
namespace translate {
const char kTranslatePageLoadAutofillAssistantDeferredTriggerDecision[] =
"Translate.PageLoad.AutofillAssistantDeferredTriggerDecision";
const char kTranslatePageLoadRankerDecision[] =
"Translate.PageLoad.Ranker.Decision";
const char kTranslatePageLoadRankerVersion[] =
"Translate.PageLoad.Ranker.Version";
const char kTranslatePageLoadTriggerDecision[] =
"Translate.PageLoad.TriggerDecision";
TranslateMetricsLoggerImpl::TranslateMetricsLoggerImpl(
base::WeakPtr<TranslateManager> translate_manager)
......@@ -49,6 +53,11 @@ void TranslateMetricsLoggerImpl::RecordPageLoadUmaMetrics() {
ranker_decision_);
base::UmaHistogramSparse(kTranslatePageLoadRankerVersion,
int(ranker_version_));
base::UmaHistogramEnumeration(kTranslatePageLoadTriggerDecision,
trigger_decision_);
base::UmaHistogramBoolean(
kTranslatePageLoadAutofillAssistantDeferredTriggerDecision,
autofill_assistant_deferred_trigger_decision_);
}
void TranslateMetricsLoggerImpl::LogRankerMetrics(
......@@ -58,4 +67,16 @@ void TranslateMetricsLoggerImpl::LogRankerMetrics(
ranker_version_ = ranker_version;
}
void TranslateMetricsLoggerImpl::LogTriggerDecision(
TriggerDecision trigger_decision) {
// Only stores the first non-kUninitialized trigger decision in the event that
// there are multiple.
if (trigger_decision_ == TriggerDecision::kUninitialized)
trigger_decision_ = trigger_decision;
}
void TranslateMetricsLoggerImpl::LogAutofillAssistantDeferredTriggerDecision() {
autofill_assistant_deferred_trigger_decision_ = true;
}
} // namespace translate
......@@ -12,8 +12,10 @@
namespace translate {
extern const char kTranslatePageLoadAutofillAssistantDeferredTriggerDecision[];
extern const char kTranslatePageLoadRankerDecision[];
extern const char kTranslatePageLoadRankerVersion[];
extern const char kTranslatePageLoadTriggerDecision[];
class NullTranslateMetricsLogger : public TranslateMetricsLogger {
public:
......@@ -25,6 +27,8 @@ class NullTranslateMetricsLogger : public TranslateMetricsLogger {
void RecordMetrics(bool is_final) override {}
void LogRankerMetrics(RankerDecision ranker_decision,
uint32_t ranker_version) override {}
void LogTriggerDecision(TriggerDecision trigger_decision) override {}
void LogAutofillAssistantDeferredTriggerDecision() override {}
};
class TranslateManager;
......@@ -47,6 +51,8 @@ class TranslateMetricsLoggerImpl : public TranslateMetricsLogger {
void RecordMetrics(bool is_final) override;
void LogRankerMetrics(RankerDecision ranker_decision,
uint32_t ranker_version) override;
void LogTriggerDecision(TriggerDecision trigger_decision) override;
void LogAutofillAssistantDeferredTriggerDecision() override;
// TODO(curranmax): Add appropriate functions for the Translate code to log
// relevant events. https://crbug.com/1114868.
......@@ -69,6 +75,11 @@ class TranslateMetricsLoggerImpl : public TranslateMetricsLogger {
RankerDecision ranker_decision_{RankerDecision::kUninitialized};
uint32_t ranker_version_{0};
// Stores the reason for the initial state of the page load. In the case there
// are multiple reasons, only the first reported reason is stored.
TriggerDecision trigger_decision_{TriggerDecision::kUninitialized};
bool autofill_assistant_deferred_trigger_decision_{false};
base::WeakPtrFactory<TranslateMetricsLoggerImpl> weak_method_factory_{this};
};
......
......@@ -41,8 +41,12 @@ TEST_F(TranslateMetricsLoggerImplTest, MultipleRecordMetrics) {
translate::RankerDecision::kShowUI;
uint32_t ranker_model_version = 1234;
translate::TriggerDecision trigger_decision =
translate::TriggerDecision::kDisabledNeverTranslateLanguage;
translate_metrics_logger()->LogRankerMetrics(ranker_decision,
ranker_model_version);
translate_metrics_logger()->LogTriggerDecision(trigger_decision);
// Simulate |RecordMetrics| being called multiple times.
translate_metrics_logger()->RecordMetrics(false);
......@@ -56,6 +60,11 @@ TEST_F(TranslateMetricsLoggerImplTest, MultipleRecordMetrics) {
translate::kTranslatePageLoadRankerDecision, ranker_decision, 1);
histogram_tester()->ExpectUniqueSample(
translate::kTranslatePageLoadRankerVersion, ranker_model_version, 1);
histogram_tester()->ExpectUniqueSample(
translate::kTranslatePageLoadTriggerDecision, trigger_decision, 1);
histogram_tester()->ExpectUniqueSample(
translate::kTranslatePageLoadAutofillAssistantDeferredTriggerDecision,
false, 1);
}
TEST_F(TranslateMetricsLoggerImplTest, LogRankerMetrics) {
......@@ -73,3 +82,38 @@ TEST_F(TranslateMetricsLoggerImplTest, LogRankerMetrics) {
histogram_tester()->ExpectUniqueSample(
translate::kTranslatePageLoadRankerVersion, ranker_model_version, 1);
}
TEST_F(TranslateMetricsLoggerImplTest, LogTriggerDecision) {
// If we log multiple trigger decisions, we expect that only the first one is
// recorded.
std::vector<translate::TriggerDecision> trigger_decisions = {
translate::TriggerDecision::kAutomaticTranslationByLink,
translate::TriggerDecision::kDisabledByRanker,
translate::TriggerDecision::kDisabledUnsupportedLanguage};
for (auto trigger_decision : trigger_decisions)
translate_metrics_logger()->LogTriggerDecision(trigger_decision);
translate_metrics_logger()->RecordMetrics(true);
histogram_tester()->ExpectUniqueSample(
translate::kTranslatePageLoadTriggerDecision, trigger_decisions[0], 1);
}
TEST_F(TranslateMetricsLoggerImplTest,
LogAutofillAssistantDeferredTriggerDecision) {
translate::TriggerDecision trigger_decision =
translate::TriggerDecision::kShowUI;
// Simulate the autofill assistant running the first time.
translate_metrics_logger()->LogAutofillAssistantDeferredTriggerDecision();
translate_metrics_logger()->LogTriggerDecision(trigger_decision);
translate_metrics_logger()->RecordMetrics(true);
histogram_tester()->ExpectUniqueSample(
translate::kTranslatePageLoadTriggerDecision, trigger_decision, 1);
histogram_tester()->ExpectUniqueSample(
translate::kTranslatePageLoadAutofillAssistantDeferredTriggerDecision,
true, 1);
}
......@@ -73011,6 +73011,25 @@ Full version information for the fingerprint enum values:
<int value="4" label="Default English"/>
</enum>
<enum name="TranslateTriggerDecision">
<int value="0" label="Uninitialized"/>
<int value="1" label="Disabled, doesn't need translation"/>
<int value="2" label="Disabled, translation feature disabled"/>
<int value="3" label="Disabled, offline"/>
<int value="4" label="Disabled, missing API key"/>
<int value="5" label="Disabled, MIME type not supported"/>
<int value="6" label="Disabled, URL not supported"/>
<int value="7" label="Disabled, never offer translations"/>
<int value="8" label="Disabled, similar languages"/>
<int value="9" label="Disabled, unsupported language"/>
<int value="10" label="Disabled, never translate language"/>
<int value="11" label="Disabled, never translate site"/>
<int value="12" label="Disabled, ranker decision"/>
<int value="13" label="Show UI"/>
<int value="14" label="Automatic translation, by link"/>
<int value="15" label="Automatic translation, by user preference"/>
</enum>
<enum name="TriggerHelpUIResult">
<int value="0" label="SUCCESS"/>
<int value="1" label="FAILURE"/>
......@@ -458,6 +458,19 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary>
</histogram>
<histogram name="Translate.PageLoad.AutofillAssistantDeferredTriggerDecision"
enum="BooleanDeferred" expires_after="2021-04-04">
<owner>curranmax@google.com</owner>
<owner>megjablon@google.com</owner>
<owner>chrome-language@google.com</owner>
<summary>
Whether or not the Autofill Assistant defered determining the initial state
of Chrome Translate for a page load. This value is logged once the page load
is completed or the first time that Chrome is backgrounded during the course
of the page load, whichever comes first.
</summary>
</histogram>
<histogram name="Translate.PageLoad.Ranker.Decision"
enum="TranslateRankerDecision" expires_after="2021-04-04">
<owner>curranmax@google.com</owner>
......@@ -483,6 +496,18 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary>
</histogram>
<histogram name="Translate.PageLoad.TriggerDecision"
enum="TranslateTriggerDecision" expires_after="2021-04-04">
<owner>curranmax@google.com</owner>
<owner>megjablon@google.com</owner>
<owner>chrome-language@google.com</owner>
<summary>
Logs the highest priority reason for the initial state of Translate for the
page load. This value is logged at the end of the page load or the first
time Chrome is backgrounded during the page load, whichever comes first.
</summary>
</histogram>
<histogram name="Translate.PageScheme" enum="TranslateScheme"
expires_after="M77">
<owner>kenjibaheux@google.com</owner>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment