blob: 9fa07baa14a61d4d4b5d072d3008b12327dbaa26 [file]
// Copyright 2025 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_CONTEXTUAL_SEARCH_CONTEXTUAL_SEARCH_METRICS_RECORDER_H_
#define COMPONENTS_CONTEXTUAL_SEARCH_CONTEXTUAL_SEARCH_METRICS_RECORDER_H_
#include <map>
#include <memory>
#include <optional>
#include <string>
#include "components/contextual_search/contextual_search_types.h"
namespace base {
class ElapsedTimer;
} // namespace base
namespace lens {
enum class MimeType;
} // namespace lens
namespace contextual_search {
// LINT.IfChange(ContextualSearchSource)
enum class ContextualSearchSource {
kUnknown,
kNewTabPage,
kOmnibox,
kContextualTasks,
kLens,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/contextual_search/histograms.xml:ContextualSearchSource,//tools/metrics/actions/actions.xml)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// Describes the query submission details.
enum class ContextualSearchMultimodalState {
kTextOnly = 0,
kFileOnly = 1,
kTextAndFile = 2,
kMaxValue = kTextAndFile,
};
enum class SessionState {
kNone = 0,
kSessionStarted = 1,
kSessionAbandoned = 2,
kQuerySubmitted = 3,
kNavigationOccurred = 4,
};
struct SessionMetrics {
SessionMetrics();
~SessionMetrics();
// Timer to keep track of the session durations.
std::unique_ptr<base::ElapsedTimer> session_elapsed_timer;
// Number of file upload attempts per file type.
std::map<lens::MimeType, int> file_upload_attempt_count_per_type;
// Number of successful file uploads per file type.
std::map<lens::MimeType, int> file_upload_success_count_per_type;
// Number of file upload failures per file type.
std::map<lens::MimeType, int> file_upload_failure_count_per_type;
// Number of file validation errors per file type.
std::map<lens::MimeType, std::map<FileUploadErrorType, int>>
file_validation_failure_count_per_type;
// In most cases `num_query_submissions` will equal 1 except in the case
// where a user navigates to the AIM page on a new window or tab and the
// composebox remains open.
int num_query_submissions = 0;
// The number of times a tab is added as context to the session.
int tab_context_added_count = 0;
// The number of times a tab is added as context to the session via the tab
// suggestion chip.
int tab_context_added_from_tab_suggestion_chip_count = 0;
// The number of time a tab is added as context to the session via the plus
// button (i.e. not via the tab suggestion chip).
int tab_context_added_from_plus_button_count = 0;
// The number of times a tab with a duplicate title is added as context to the
// session.
int tab_with_duplicate_title_clicked_count = 0;
};
class ContextualSearchMetricsRecorder {
public:
explicit ContextualSearchMetricsRecorder(ContextualSearchSource source);
virtual ~ContextualSearchMetricsRecorder();
// Should be called when there are session state changes to keep track of
// session state metrics. Virtual for testing.
virtual void NotifySessionStateChanged(SessionState session_state);
virtual void OnFileUploadStatusChanged(
lens::MimeType file_mime_type,
FileUploadStatus file_upload_status,
const std::optional<FileUploadErrorType>& error_type);
// Maps file errors to its string version for histogram naming.
std::string FileErrorToString(FileUploadErrorType error);
// Maps mime types to its string version for histogram naming.
std::string MimeTypeToString(lens::MimeType mime_type);
// Maps contextual search sources to its string version for histogram naming.
static std::string ContextualSearchSourceToString(
ContextualSearchSource source);
ContextualSearchSource source() const { return source_; }
// Maps submission types to its string version for histogram naming.
std::string SubmissionTypeToString(SubmissionType submission_type);
// Records several metrics about the query, such the number of characters
// found in the query.
void RecordQueryMetrics(int text_length, int file_count);
void RecordFileSizeMetric(lens::MimeType mime_type, uint64_t file_size_bytes);
// Should be called when a file has been deleted.
void RecordFileDeletedMetrics(bool success,
lens::MimeType file_type,
FileUploadStatus file_status);
void RecordTabAddedMetrics(bool has_duplicate_title,
std::optional<int> recency_ranking,
bool is_tab_suggestion_chip);
// If `duplicate_title_count` < 0 then it won't be recorded.
void RecordTabContextMenuMetrics(int total_tab_count,
int duplicate_title_count);
void RecordToolsSubmissionType(SubmissionType submission_type);
void RecordToolState(SubmissionType submission_type, AimToolState tool_state);
// Records whether the config was parsed successfully.
static void RecordConfigParseSuccess(ContextualSearchSource source,
bool success);
private:
// Called when the session starts to correctly track session
// durations.
void NotifySessionStarted();
// Called when a query is submitted to correctly track the time from
// the session starting to query submission.
void NotifyQuerySubmitted();
// Should only be called when a session has been abandoned.
void RecordSessionAbandonedMetrics();
// Should only be called if a query was submitted and navigation to the AIM
// page occurred.
void RecordSessionCompletedMetrics();
// Records session durations regardless of whether the session was abandoned
// or completed successfully.
void RecordTotalSessionDuration(base::TimeDelta session_duration);
// Records all file upload attempts.
void FinalizeSessionMetrics();
// Resets all session metrics at the end of a session.
void ResetSessionMetrics();
ContextualSearchSource source_;
std::string metrics_suffix_;
std::unique_ptr<SessionMetrics> session_metrics_;
SessionState session_state_ = SessionState::kNone;
};
} // namespace contextual_search
#endif // COMPONENTS_CONTEXTUAL_SEARCH_CONTEXTUAL_SEARCH_METRICS_RECORDER_H_