blob: 4a5c810407f4773bd5ec463ce3fc72f430e3271c [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_COMPOSE_CORE_BROWSER_COMPOSE_METRICS_H_
#define COMPONENTS_COMPOSE_CORE_BROWSER_COMPOSE_METRICS_H_
#include "base/time/time.h"
#include "components/compose/core/browser/compose_enums.mojom.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
namespace base {
class TimeDelta;
} // namespace base
namespace compose {
// Compose histogram names.
extern const char kComposeDialogOpenLatency[];
extern const char kComposeDialogSelectionLength[];
extern const char kComposeRequestReason[];
extern const char kComposeRequestDurationOkSuffix[];
extern const char kComposeRequestDurationErrorSuffix[];
extern const char kComposeRequestStatus[];
extern const char kComposeSessionComposeCount[];
extern const char kComposeSessionCloseReason[];
extern const char kComposeSessionDialogShownCount[];
extern const char kComposeSessionEventCounts[];
extern const char kComposeSessionDuration[];
extern const char kComposeSessionOverOneDay[];
extern const char kComposeSessionUndoCount[];
extern const char kComposeSessionUpdateInputCount[];
extern const char kComposeShowStatus[];
extern const char kComposeFirstRunSessionCloseReason[];
extern const char kComposeFirstRunSessionDialogShownCount[];
extern const char kComposeMSBBSessionCloseReason[];
extern const char kComposeMSBBSessionDialogShownCount[];
extern const char kInnerTextNodeOffsetFound[];
extern const char kComposeContextMenuCtr[];
extern const char kOpenComposeDialogResult[];
// Enum for calculating the CTR of the Compose context menu item.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. Keep in sync with
// ComposeContextMenuCtrEvent in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeContextMenuCtrEvent {
kMenuItemDisplayed = 0,
kMenuItemClicked = 1,
kMaxValue = kMenuItemClicked,
};
// Keep in sync with ComposeRequestReason in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeRequestReason {
kFirstRequest = 0,
kRetryRequest = 1,
kUpdateRequest = 2,
kLengthShortenRequest = 3,
kLengthElaborateRequest = 4,
kToneCasualRequest = 5,
kToneFormalRequest = 6,
kMaxValue = kToneFormalRequest,
};
// Keep in sync with ComposeMSBBSessionCloseReasonType in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeMSBBSessionCloseReason {
kMSBBEndedImplicitly = 0,
kMSBBCloseButtonPressed = 1,
kMSBBAcceptedWithoutInsert = 2,
kMSBBAcceptedWithInsert = 3,
kMaxValue = kMSBBAcceptedWithInsert,
};
// Keep in sync with ComposeFirstRunSessionCloseReasonType in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeFirstRunSessionCloseReason {
kEndedImplicitly = 0,
kCloseButtonPressed = 1,
kFirstRunDisclaimerAcknowledgedWithoutInsert = 2,
kFirstRunDisclaimerAcknowledgedWithInsert = 3,
kNewSessionWithSelectedText = 4,
kMaxValue = kNewSessionWithSelectedText,
};
// Keep in sync with ComposeSessionCloseReasonType in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeSessionCloseReason {
kAcceptedSuggestion = 0,
kCloseButtonPressed = 1,
kEndedImplicitly = 2,
kNewSessionWithSelectedText = 3,
kCanceledBeforeResponseReceived = 4,
kMaxValue = kCanceledBeforeResponseReceived,
};
// Keep in sync with ComposeSessionEventCounts in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeSessionEventTypes {
kDialogShown = 0,
kFREShown = 1,
kFREAccepted = 2,
kMSBBShown = 3,
kMSBBSettingsOpened = 4,
kMSBBEnabled = 5,
kStartedWithSelection = 6,
kCreateClicked = 7,
kUpdateClicked = 8,
kRetryClicked = 9,
kUndoClicked = 10,
kShortenClicked = 11,
kElaborateClicked = 12,
kCasualClicked = 13,
kFormalClicked = 14,
kThumbsDown = 15,
kThumbsUp = 16,
kInsertClicked = 17,
kCloseClicked = 18,
kEditClicked = 19,
kCancelEditClicked = 20,
kAnyModifierUsed = 21,
kRedoClicked = 22,
kMaxValue = kRedoClicked,
};
// Enum for recording the show status of the Compose context menu item.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. Keep in sync with
// ComposeShowStatus in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeShowStatus {
kShouldShow = 0,
kGenericBlocked = 1,
kIncompatibleFieldType = 2,
// kDisabledMsbb is no longer used now that we have a MSBB dialog.
kDisabledMsbb = 3, // obsolete
kSignedOut = 4,
kUnsupportedLanguage = 5,
kFormFieldInCrossOriginFrame = 6,
kPerUrlChecksFailed = 7,
kUserNotAllowedByOptimizationGuide = 8,
kNotComposeEligible = 9,
kIncorrectScheme = 10,
kFormFieldNestedInFencedFrame = 11,
kFeatureFlagDisabled = 12,
kDisabledOnChromeOS = 13,
kMaxValue = kDisabledOnChromeOS,
};
enum class EvalLocation : int {
// Response was evaluated on the server.
kServer,
// Response was evaluated on the device.
kOnDevice,
};
// Keep in sync with ComposeSessionEvalLocation in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class SessionEvalLocation {
// No responses were evaluated.
kNone = 0,
// All responses were evaluated on the server.
kServer = 1,
// All responses were evaluated on the device.
kOnDevice = 2,
// Some responses were evaluated on the server and some on the device.
kMixed = 3,
kMaxValue = kMixed,
};
// Enum for recording the feedback state of a Compose request.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. Keep in sync with
// ComposeRequestFeedback in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeRequestFeedback {
kNoFeedback = 0,
kPositiveFeedback = 1,
kNegativeFeedback = 2,
kRequestError = 3,
kMaxValue = kRequestError,
};
// Struct containing event and logging information for an individual
// |ComposeSession|.
struct ComposeSessionEvents {
ComposeSessionEvents();
ComposeSessionEvents(ComposeSessionEvents& e) = delete;
ComposeSessionEvents& operator=(ComposeSessionEvents& e) = delete;
~ComposeSessionEvents() = default;
// Logging counters.
// The total number of Compose Requests for the session.
unsigned int compose_count = 0;
// Times we have shown the compose dialog.
unsigned int dialog_shown_count = 0;
// Times we have shown the first run dialog.
unsigned int fre_dialog_shown_count = 0;
// Times we have shown the dialog to enable MSBB.
unsigned int msbb_dialog_shown_count = 0;
// Times the user has pressed "undo" this session.
unsigned int undo_count = 0;
// Times the user has pressed "redo" this session.
unsigned int redo_count = 0;
// Compose request after input edited.
unsigned int update_input_count = 0;
// Tiems the user has pressed the "Retry" button.
unsigned int regenerate_count = 0;
// Times the user has picked the "Shorter" option.
unsigned int shorten_count = 0;
// Times the user has picked the "Elaborate" option.
unsigned int lengthen_count = 0;
// Times the user has picked the "Formal" option.
unsigned int formal_count = 0;
// Times the user has picked the "Casual" option.
unsigned int casual_count = 0;
// Logging flags
// True if the FRE was completed in the session.
bool fre_completed_in_session = false;
// True if the MSBB settings were opened.
bool msbb_settings_opened = false;
// True if the MSBB was enabled in the session.
bool msbb_enabled_in_session = false;
// True if the session started with selected text.
bool has_initial_text = false;
// True if thumbs up was ever clicked during the session.
bool has_thumbs_up = false;
// True if thumbs down was ever clicked during the session.
bool has_thumbs_down = false;
// True if the results were eventually inserted back to the web page.
bool inserted_results = false;
// True if the the user closed the compose session via the "x" button.
bool close_clicked = false;
// True if the user has pressed the "Edit" button this session.
bool did_click_edit = false;
// True if the user has pressed "Cancel" on the editing view for this session.
bool did_click_cancel_on_edit = false;
// Number of on-device responses received.
unsigned int on_device_responses = 0;
// Number of server responses received.
unsigned int server_responses = 0;
};
// Enum with the possible reasons for it being impossible to open the Compose
// dialog after the user requested it.
// Keep in sync with OpenComposeDialogResult in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class OpenComposeDialogResult {
kSuccess = 0,
kNoChromeComposeClient = 1,
kNoRenderFrameHost = 2,
kNoContentAutofillDriver = 3,
kAutofillFormDataNotFound = 4,
kAutofillFormFieldDataNotFound = 5,
kNoWebContents = 6,
kFailedCreatingComposeDialogView = 7,
kAutofillFormDataNotFoundAfterSelectAll = 8,
kMaxValue = kAutofillFormDataNotFoundAfterSelectAll
};
// Enum to log if the inner text successfuly found an offset
// Keep in sync with ComposeInnerTextNodeOffset in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeInnerTextNodeOffset {
kNoOffsetFound = 0,
kOffsetFound = 1,
kMaxValue = kOffsetFound
};
// Enum to log if all text was selected on behalf of the user.
// Keep in sync with ComposeSelectAllStatus in
// src/tools/metrics/histograms/metadata/compose/enums.xml.
enum class ComposeSelectAllStatus {
kNoSelectAll = 0,
kSelectedAll = 1,
kMaxValue = kSelectedAll
};
// Class that automatically reports any UKM metrics for the page-level Compose
// UKM as defined in go/ukm-collection-chrome-compose.
class PageUkmTracker {
public:
PageUkmTracker(ukm::SourceId source_id);
~PageUkmTracker();
// The compose menu item was shown in a context menu.
void MenuItemShown();
// The compose menu item was clicked, opening Compose.
void MenuItemClicked();
// The composed text was accepted and inserted into the webpage by the user.
void ComposeTextInserted();
// The compose dialog was requested but not shown due to problems obtaining
// form data from Autofill.
void ShowDialogAbortedDueToMissingFormData();
void ShowDialogAbortedDueToMissingFormFieldData();
// Records UKM if any of the above events happened during this object's
// lifetime. Called in the destructor.
void MaybeLogUkm();
private:
bool event_was_recorded_ = false;
unsigned int menu_item_shown_count_ = 0;
unsigned int menu_item_clicked_count_ = 0;
unsigned int compose_text_inserted_count_ = 0;
unsigned int missing_form_data_count_ = 0;
unsigned int missing_form_field_data_count_ = 0;
ukm::SourceId source_id;
};
void LogComposeContextMenuCtr(ComposeContextMenuCtrEvent event);
void LogComposeContextMenuShowStatus(ComposeShowStatus status);
void LogOpenComposeDialogResult(OpenComposeDialogResult result);
void LogComposeRequestReason(ComposeRequestReason reason);
void LogComposeRequestReason(EvalLocation eval_location,
ComposeRequestReason reason);
void LogComposeRequestStatus(compose::mojom::ComposeStatus status);
void LogComposeRequestStatus(EvalLocation eval_location,
compose::mojom::ComposeStatus status);
// Log the duration of a compose request. |is_ok| indicates the status of
// the request.
void LogComposeRequestDuration(base::TimeDelta duration,
EvalLocation eval_location,
bool is_ok);
void LogComposeFirstRunSessionCloseReason(
ComposeFirstRunSessionCloseReason reason);
// Log session based metrics when a FRE session ends.
void LogComposeFirstRunSessionDialogShownCount(
ComposeFirstRunSessionCloseReason reason,
int dialog_shown_count);
void LogComposeMSBBSessionCloseReason(ComposeMSBBSessionCloseReason reason);
// Log session based metrics when a consent session ends.
void LogComposeMSBBSessionDialogShownCount(ComposeMSBBSessionCloseReason reason,
int dialog_shown_count);
SessionEvalLocation GetSessionEvalLocationFromEvents(
const ComposeSessionEvents& session_events);
std::optional<EvalLocation> GetEvalLocationFromEvents(
const ComposeSessionEvents& session_events);
// Log session based metrics when a session ends.
// Should only be called once per session.
void LogComposeSessionCloseMetrics(ComposeSessionCloseReason reason,
const ComposeSessionEvents& session_events);
// Log session based UKM metrics when the session ends.
void LogComposeSessionCloseUkmMetrics(
ukm::SourceId source_id,
const ComposeSessionEvents& session_events);
// Log the amount trimmed from the inner text from the page (in bytes) when the
// dialog is opened.
void LogComposeDialogInnerTextShortenedBy(int shortened_by);
// Log the size (in bytes) of the untrimmed inner text from the page when the
// dialog is opened.
void LogComposeDialogInnerTextSize(int size);
// Log if the inner text node offset was found successfully.
void LogComposeDialogInnerTextOffsetFound(bool inner_offset_found);
// Log the time taken for the dialog to be fully shown and interactable.
void LogComposeDialogOpenLatency(base::TimeDelta duration);
// Log the character length of the selection when the dialog is opened.
void LogComposeDialogSelectionLength(int length);
// Log the session duration with |session_suffix| applied to histogram name.
void LogComposeSessionDuration(
base::TimeDelta session_duration,
std::string session_suffix = "",
std::optional<EvalLocation> eval_location = std::nullopt);
void LogComposeRequestFeedback(EvalLocation eval_location,
ComposeRequestFeedback feedback);
void LogComposeSelectAllStatus(ComposeSelectAllStatus select_all_status);
} // namespace compose
#endif // COMPONENTS_COMPOSE_CORE_BROWSER_COMPOSE_METRICS_H_