blob: 3b7dbf71f37c89306d598f17b9e73285844ffd8b [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "history_clusters_debug_jsons.h"
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "base/i18n/time_formatting.h"
#include "base/json/json_writer.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/history/core/browser/history_types.h"
#include "components/history_clusters/core/history_clusters_util.h"
namespace history_clusters {
namespace {
base::Value::Dict GetDebugJSONDictForAnnotatedVisit(
const history::AnnotatedVisit& visit) {
base::Value::Dict debug_visit;
debug_visit.Set("visitId", base::NumberToString(visit.visit_row.visit_id));
debug_visit.Set("url",
visit.content_annotations.search_normalized_url.is_empty()
? visit.url_row.url().spec()
: visit.content_annotations.search_normalized_url.spec());
debug_visit.Set("title", visit.url_row.title());
debug_visit.Set(
"foregroundTimeSecs",
base::NumberToString(
visit.context_annotations.total_foreground_duration.InSeconds()));
debug_visit.Set(
"visitDurationSecs",
base::NumberToString(visit.visit_row.visit_duration.InSeconds()));
debug_visit.Set(
"navigationTimeMs",
base::NumberToString(visit.visit_row.visit_time.ToDeltaSinceWindowsEpoch()
.InMilliseconds()));
debug_visit.Set("pageEndReason", visit.context_annotations.page_end_reason);
debug_visit.Set("pageTransition",
base::NumberToString(visit.visit_row.transition));
debug_visit.Set(
"referringVisitId",
base::NumberToString(visit.referring_visit_of_redirect_chain_start));
debug_visit.Set(
"openerVisitId",
base::NumberToString(visit.opener_visit_of_redirect_chain_start));
debug_visit.Set("originatorCacheGuid", visit.visit_row.originator_cache_guid);
debug_visit.Set(
"originatorReferringVisitId",
base::NumberToString(visit.visit_row.originator_referring_visit));
debug_visit.Set(
"originatorOpenerVisitId",
base::NumberToString(visit.visit_row.originator_opener_visit));
debug_visit.Set("urlForDeduping",
visit.content_annotations.search_normalized_url.is_empty()
? ComputeURLForDeduping(visit.url_row.url()).spec()
: visit.content_annotations.search_normalized_url.spec());
debug_visit.Set("visitSource", base::NumberToString(visit.source));
debug_visit.Set("isKnownToSync", visit.visit_row.is_known_to_sync);
debug_visit.Set("normalized_url",
visit.content_annotations.search_normalized_url.is_empty()
? visit.url_row.url().spec()
: visit.content_annotations.search_normalized_url.spec());
// Content annotations.
base::Value::List debug_categories;
for (const auto& category :
visit.content_annotations.model_annotations.categories) {
base::Value::Dict debug_category;
debug_category.Set("name", category.id);
debug_category.Set("value", category.weight);
debug_categories.Append(std::move(debug_category));
}
debug_visit.Set("categories", std::move(debug_categories));
base::Value::List debug_entities;
for (const auto& entity :
visit.content_annotations.model_annotations.entities) {
base::Value::Dict debug_entity;
debug_entity.Set("name", entity.id);
debug_entity.Set("value", entity.weight);
debug_entities.Append(std::move(debug_entity));
}
debug_visit.Set("entities", std::move(debug_entities));
debug_visit.Set("visibility",
visit.content_annotations.model_annotations.visibility_score);
debug_visit.Set("searchTerms", visit.content_annotations.search_terms);
if (!visit.content_annotations.search_terms.empty()) {
debug_visit.Set("hasRelatedSearches",
!visit.content_annotations.related_searches.empty());
}
debug_visit.Set("hasUrlKeyedImage",
visit.content_annotations.has_url_keyed_image);
return debug_visit;
}
} // namespace
std::string GetDebugTime(const base::Time time) {
return time.is_null() ? "null" : base::TimeFormatAsIso8601(time);
}
// Gets a loggable JSON representation of `visits`.
std::string GetDebugJSONForVisits(
const std::vector<history::AnnotatedVisit>& visits) {
base::Value::List debug_visits_list;
for (auto& visit : visits) {
debug_visits_list.Append(GetDebugJSONDictForAnnotatedVisit(visit));
}
base::Value::Dict debug_value;
debug_value.Set("visits", std::move(debug_visits_list));
std::string debug_string;
if (!base::JSONWriter::WriteWithOptions(
debug_value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &debug_string)) {
debug_string = "Error: Could not write visits to JSON.";
}
return debug_string;
}
// Gets a loggable JSON representation of `clusters`.
std::string GetDebugJSONForClusters(
const std::vector<history::Cluster>& clusters) {
base::Value::List debug_clusters_list;
for (const auto& cluster : clusters) {
base::Value::Dict debug_cluster;
debug_cluster.Set("id", static_cast<int>(cluster.cluster_id));
debug_cluster.Set("label", cluster.label.value_or(u""));
base::Value::List debug_keywords;
for (const auto& keyword_data_p : cluster.keyword_to_data_map) {
debug_keywords.Append(base::UTF16ToUTF8(keyword_data_p.first));
}
debug_cluster.Set("keywords", std::move(debug_keywords));
debug_cluster.Set("should_show_on_prominent_ui_surfaces",
cluster.should_show_on_prominent_ui_surfaces);
debug_cluster.Set("triggerability_calculated",
cluster.triggerability_calculated);
base::Value::List debug_visits;
for (const auto& visit : cluster.visits) {
base::Value::Dict debug_visit =
GetDebugJSONDictForAnnotatedVisit(visit.annotated_visit);
debug_visit.Set("score", visit.score);
debug_visit.Set("interaction_state",
history::ClusterVisit::InteractionStateToInt(
visit.interaction_state));
debug_visit.Set("site_engagement_score", visit.engagement_score);
base::Value::List debug_duplicate_visits;
for (const auto& duplicate_visit : visit.duplicate_visits)
debug_duplicate_visits.Append(duplicate_visit.url.spec());
debug_visit.Set("duplicate_visits", std::move(debug_duplicate_visits));
debug_visits.Append(std::move(debug_visit));
}
debug_cluster.Set("visits", std::move(debug_visits));
debug_clusters_list.Append(std::move(debug_cluster));
}
base::Value::Dict debug_value;
debug_value.Set("clusters", std::move(debug_clusters_list));
std::string debug_string;
if (!base::JSONWriter::WriteWithOptions(
debug_value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &debug_string)) {
debug_string = "Error: Could not write clusters to JSON.";
}
return debug_string;
}
template <typename T>
std::string GetDebugJSONForUrlKeywordSet(
const std::unordered_set<T>& keyword_set) {
base::Value::List keyword_list;
for (const auto& keyword : keyword_set) {
keyword_list.Append(keyword);
}
std::string debug_string;
if (!base::JSONWriter::WriteWithOptions(
keyword_list, base::JSONWriter::OPTIONS_PRETTY_PRINT,
&debug_string)) {
debug_string = "Error: Could not write keywords list to JSON.";
}
return debug_string;
}
template std::string GetDebugJSONForUrlKeywordSet<std::u16string>(
const std::unordered_set<std::u16string>&);
template std::string GetDebugJSONForUrlKeywordSet<std::string>(
const std::unordered_set<std::string>&);
std::string GetDebugJSONForKeywordMap(
const std::unordered_map<std::u16string, history::ClusterKeywordData>&
keyword_to_data_map) {
base::Value::List debug_keywords;
for (const auto& keyword_data_p : keyword_to_data_map) {
debug_keywords.Append(base::UTF16ToUTF8(keyword_data_p.first));
}
std::string debug_string;
if (!base::JSONWriter::WriteWithOptions(
debug_keywords, base::JSONWriter::OPTIONS_PRETTY_PRINT,
&debug_string)) {
debug_string = "Error: Could not write keywords list to JSON.";
}
return debug_string;
}
} // namespace history_clusters