blob: 154a69860e9651dd83f7ef31c4b8e0e02e33a0e9 [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 "chrome/browser/web_applications/web_app_logging.h"
#include <string>
#include "base/feature_list.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "chrome/browser/web_applications/web_app_install_utils.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "chrome/common/chrome_features.h"
#include "components/webapps/browser/installable/installable_metrics.h"
#include "components/webapps/browser/web_contents/web_app_url_loader.h"
#include "components/webapps/common/web_app_id.h"
#include "net/http/http_status_code.h"
namespace web_app {
namespace {
bool IsEmptyIconBitmapsForIconUrl(const IconsMap& icons_map,
const GURL& icon_url) {
IconsMap::const_iterator iter = icons_map.find(icon_url);
if (iter == icons_map.end())
return true;
const std::vector<SkBitmap>& icon_bitmaps = iter->second;
if (icon_bitmaps.empty())
return true;
for (const SkBitmap& icon_bitmap : icon_bitmaps) {
if (!icon_bitmap.isNull() && !icon_bitmap.drawsNothing())
return false;
}
return true;
}
} // namespace
InstallErrorLogEntry::InstallErrorLogEntry(
bool background_installation,
webapps::WebappInstallSource install_surface)
: background_installation_(background_installation),
install_surface_(install_surface) {
if (base::FeatureList::IsEnabled(features::kRecordWebAppDebugInfo))
error_dict_ = std::make_unique<base::Value::Dict>();
}
InstallErrorLogEntry::~InstallErrorLogEntry() = default;
base::Value::Dict InstallErrorLogEntry::TakeErrorDict() {
DCHECK(error_dict_);
base::Value::Dict error_dict = std::move(*error_dict_);
*error_dict_ = base::Value::Dict();
return error_dict;
}
void InstallErrorLogEntry::LogUrlLoaderError(
const char* stage,
const std::string& url,
webapps::WebAppUrlLoaderResult result) {
if (!error_dict_)
return;
base::Value::Dict url_loader_error;
url_loader_error.Set("WebAppUrlLoader::Result",
ConvertUrlLoaderResultToString(result));
LogErrorObject(stage, url, std::move(url_loader_error));
}
void InstallErrorLogEntry::LogExpectedAppIdError(
const char* stage,
const std::string& url,
const webapps::AppId& app_id,
const webapps::AppId& expected_app_id) {
if (!error_dict_)
return;
base::Value::Dict expected_app_id_error;
expected_app_id_error.Set("expected_app_id", expected_app_id);
expected_app_id_error.Set("app_id", app_id);
LogErrorObject(stage, url, std::move(expected_app_id_error));
}
void InstallErrorLogEntry::LogDownloadedIconsErrors(
const WebAppInstallInfo& web_app_info,
IconsDownloadedResult icons_downloaded_result,
const IconsMap& icons_map,
const DownloadedIconsHttpResults& icons_http_results) {
if (!error_dict_)
return;
base::Value::Dict icon_errors;
{
// Reports errors only, omits successful entries.
base::Value::List icons_http_errors;
for (const auto& url_and_http_code : icons_http_results) {
const GURL& icon_url = url_and_http_code.first.url;
int http_status_code = url_and_http_code.second;
const char* http_code_desc = net::GetHttpReasonPhrase(
static_cast<net::HttpStatusCode>(http_status_code));
// If the SkBitmap for`icon_url` is missing in `icons_map` then we report
// this miss as an error, even for net::HttpStatusCode::HTTP_OK.
if (IsEmptyIconBitmapsForIconUrl(icons_map, icon_url)) {
base::Value::Dict icon_http_error;
icon_http_error.Set("icon_url", icon_url.spec());
icon_http_error.Set("icon_size",
url_and_http_code.first.size.ToString());
icon_http_error.Set("http_status_code", http_status_code);
icon_http_error.Set("http_code_desc", http_code_desc);
icons_http_errors.Append(std::move(icon_http_error));
}
}
if (icons_downloaded_result != IconsDownloadedResult::kCompleted ||
!icons_http_errors.empty()) {
icon_errors.Set("icons_downloaded_result",
IconsDownloadedResultToString(icons_downloaded_result));
}
if (!icons_http_errors.empty())
icon_errors.Set("icons_http_results", std::move(icons_http_errors));
}
if (web_app_info.is_generated_icon)
icon_errors.Set("is_generated_icon", true);
if (!icon_errors.empty()) {
LogErrorObject("OnIconsRetrieved", web_app_info.start_url.spec(),
std::move(icon_errors));
}
}
void InstallErrorLogEntry::LogHeaderIfLogEmpty(const std::string& url) {
if (!error_dict_ || !error_dict_->empty())
return;
error_dict_->Set("!url", url);
error_dict_->Set("install_surface", static_cast<int>(install_surface_));
error_dict_->Set("background_installation", background_installation_);
error_dict_->Set("stages", base::Value::List());
}
void InstallErrorLogEntry::LogErrorObject(const char* stage,
const std::string& url,
base::Value::Dict object) {
if (!error_dict_)
return;
LogHeaderIfLogEmpty(url);
object.Set("!stage", stage);
error_dict_->FindList("stages")->Append(std::move(object));
}
} // namespace web_app