1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/indexed_db/indexed_db_reporting.h"
6
7 #include <string>
8
9 #include "base/metrics/histogram_functions.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/strcat.h"
12 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
13 #include "content/browser/indexed_db/indexed_db_leveldb_env.h"
14 #include "url/origin.h"
15
16 namespace content {
17 namespace indexed_db {
18
19 namespace {
20
OriginToCustomHistogramSuffix(const url::Origin & origin)21 std::string OriginToCustomHistogramSuffix(const url::Origin& origin) {
22 if (origin.host() == "docs.google.com")
23 return ".Docs";
24 return std::string();
25 }
26
ParseAndReportIOErrorDetails(const std::string & histogram_name,const leveldb::Status & s)27 void ParseAndReportIOErrorDetails(const std::string& histogram_name,
28 const leveldb::Status& s) {
29 leveldb_env::MethodID method;
30 base::File::Error error = base::File::FILE_OK;
31 leveldb_env::ErrorParsingResult result =
32 leveldb_env::ParseMethodAndError(s, &method, &error);
33 if (result == leveldb_env::NONE)
34 return;
35 base::LinearHistogram::FactoryGet(
36 base::StrCat({histogram_name, ".EnvMethod"}), 1, leveldb_env::kNumEntries,
37 leveldb_env::kNumEntries + 1,
38 base::HistogramBase::kUmaTargetedHistogramFlag)
39 ->Add(method);
40
41 if (result == leveldb_env::METHOD_AND_BFE) {
42 DCHECK_LT(error, 0);
43 base::LinearHistogram::FactoryGet(
44 base::StrCat(
45 {histogram_name, ".BFE.", leveldb_env::MethodIDToString(method)}),
46 1, -base::File::FILE_ERROR_MAX, -base::File::FILE_ERROR_MAX + 1,
47 base::HistogramBase::kUmaTargetedHistogramFlag)
48 ->Add(-error);
49 }
50 }
51
ParseAndReportCorruptionDetails(const std::string & histogram_name,const leveldb::Status & status)52 void ParseAndReportCorruptionDetails(const std::string& histogram_name,
53 const leveldb::Status& status) {
54 int error = leveldb_env::GetCorruptionCode(status);
55 DCHECK_GE(error, 0);
56 const int kNumPatterns = leveldb_env::GetNumCorruptionCodes();
57 base::LinearHistogram::FactoryGet(
58 base::StrCat({histogram_name, ".Corruption"}), 1, kNumPatterns,
59 kNumPatterns + 1, base::HistogramBase::kUmaTargetedHistogramFlag)
60 ->Add(error);
61 }
62
63 } // namespace
64
ReportOpenStatus(IndexedDBBackingStoreOpenResult result,const url::Origin & origin)65 void ReportOpenStatus(IndexedDBBackingStoreOpenResult result,
66 const url::Origin& origin) {
67 base::UmaHistogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus",
68 result, INDEXED_DB_BACKING_STORE_OPEN_MAX);
69 const std::string suffix = OriginToCustomHistogramSuffix(origin);
70 // Data from the WebCore.IndexedDB.BackingStore.OpenStatus histogram is used
71 // to generate a graph. So as not to alter the meaning of that graph,
72 // continue to collect all stats there (above) but also now collect docs stats
73 // separately (below).
74 if (!suffix.empty()) {
75 base::LinearHistogram::FactoryGet(
76 base::StrCat({"WebCore.IndexedDB.BackingStore.OpenStatus", suffix}), 1,
77 INDEXED_DB_BACKING_STORE_OPEN_MAX,
78 INDEXED_DB_BACKING_STORE_OPEN_MAX + 1,
79 base::HistogramBase::kUmaTargetedHistogramFlag)
80 ->Add(result);
81 }
82 }
83
ReportInternalError(const char * type,IndexedDBBackingStoreErrorSource location)84 void ReportInternalError(const char* type,
85 IndexedDBBackingStoreErrorSource location) {
86 base::Histogram::FactoryGet(
87 base::StrCat({"WebCore.IndexedDB.BackingStore.", type, "Error"}), 1,
88 INTERNAL_ERROR_MAX, INTERNAL_ERROR_MAX + 1,
89 base::HistogramBase::kUmaTargetedHistogramFlag)
90 ->Add(location);
91 }
92
ReportSchemaVersion(int version,const url::Origin & origin)93 void ReportSchemaVersion(int version, const url::Origin& origin) {
94 UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.SchemaVersion", version,
95 kLatestKnownSchemaVersion + 1);
96 const std::string suffix = OriginToCustomHistogramSuffix(origin);
97 if (!suffix.empty()) {
98 base::LinearHistogram::FactoryGet(
99 base::StrCat({"WebCore.IndexedDB.SchemaVersion", suffix}), 0,
100 indexed_db::kLatestKnownSchemaVersion,
101 indexed_db::kLatestKnownSchemaVersion + 1,
102 base::HistogramBase::kUmaTargetedHistogramFlag)
103 ->Add(version);
104 }
105 }
106
ReportV2Schema(bool has_broken_blobs,const url::Origin & origin)107 void ReportV2Schema(bool has_broken_blobs, const url::Origin& origin) {
108 base::UmaHistogramBoolean("WebCore.IndexedDB.SchemaV2HasBlobs",
109 has_broken_blobs);
110 const std::string suffix = OriginToCustomHistogramSuffix(origin);
111 if (!suffix.empty()) {
112 base::BooleanHistogram::FactoryGet(
113 base::StrCat({"WebCore.IndexedDB.SchemaV2HasBlobs", suffix}),
114 base::HistogramBase::kUmaTargetedHistogramFlag)
115 ->Add(has_broken_blobs);
116 }
117 }
118
ReportLevelDBError(const std::string & histogram_name,const leveldb::Status & s)119 void ReportLevelDBError(const std::string& histogram_name,
120 const leveldb::Status& s) {
121 if (s.ok()) {
122 NOTREACHED();
123 return;
124 }
125 enum {
126 LEVEL_DB_NOT_FOUND,
127 LEVEL_DB_CORRUPTION,
128 LEVEL_DB_IO_ERROR,
129 LEVEL_DB_OTHER,
130 LEVEL_DB_MAX_ERROR
131 };
132 int leveldb_error = LEVEL_DB_OTHER;
133 if (s.IsNotFound())
134 leveldb_error = LEVEL_DB_NOT_FOUND;
135 else if (s.IsCorruption())
136 leveldb_error = LEVEL_DB_CORRUPTION;
137 else if (s.IsIOError())
138 leveldb_error = LEVEL_DB_IO_ERROR;
139 base::Histogram::FactoryGet(histogram_name, 1, LEVEL_DB_MAX_ERROR,
140 LEVEL_DB_MAX_ERROR + 1,
141 base::HistogramBase::kUmaTargetedHistogramFlag)
142 ->Add(leveldb_error);
143 if (s.IsIOError())
144 ParseAndReportIOErrorDetails(histogram_name, s);
145 else
146 ParseAndReportCorruptionDetails(histogram_name, s);
147 }
148
149 } // namespace indexed_db
150 } // namespace content
151