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 "components/feature_engagement/internal/stats.h"
6
7 #include <string>
8
9 #include "base/metrics/histogram_functions.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/metrics/user_metrics.h"
12 #include "components/feature_engagement/public/feature_list.h"
13
14 namespace feature_engagement {
15 namespace stats {
16 namespace {
17
18 // Histogram suffixes for database metrics, must match the ones in
19 // histograms.xml.
20 const char kEventStoreSuffix[] = "EventStore";
21 const char kAvailabilityStoreSuffix[] = "AvailabilityStore";
22
23 // A shadow histogram across all features. Also the base name for the suffix
24 // based feature specific histograms; for example for IPH_MyFun, it would be:
25 // InProductHelp.ShouldTriggerHelpUI.IPH_MyFun.
26 const char kShouldTriggerHelpUIHistogram[] =
27 "InProductHelp.ShouldTriggerHelpUI";
28
29 // Helper function to log a TriggerHelpUIResult.
LogTriggerHelpUIResult(const std::string & name,TriggerHelpUIResult result)30 void LogTriggerHelpUIResult(const std::string& name,
31 TriggerHelpUIResult result) {
32 // Must not use histograms macros here because we pass in the histogram name.
33 base::UmaHistogramEnumeration(name, result, TriggerHelpUIResult::COUNT);
34 base::UmaHistogramEnumeration(kShouldTriggerHelpUIHistogram, result,
35 TriggerHelpUIResult::COUNT);
36 }
37
38 } // namespace
39
ToDbHistogramSuffix(StoreType type)40 std::string ToDbHistogramSuffix(StoreType type) {
41 switch (type) {
42 case StoreType::EVENTS_STORE:
43 return std::string(kEventStoreSuffix);
44 case StoreType::AVAILABILITY_STORE:
45 return std::string(kAvailabilityStoreSuffix);
46 default:
47 NOTREACHED();
48 return std::string();
49 }
50 }
51
RecordNotifyEvent(const std::string & event_name,const Configuration * config,bool is_model_ready)52 void RecordNotifyEvent(const std::string& event_name,
53 const Configuration* config,
54 bool is_model_ready) {
55 DCHECK(!event_name.empty());
56 DCHECK(config);
57
58 // Find which feature this event belongs to.
59 const Configuration::ConfigMap& features =
60 config->GetRegisteredFeatureConfigs();
61 std::string feature_name;
62 for (const auto& element : features) {
63 const std::string fname = element.first;
64 const FeatureConfig& feature_config = element.second;
65
66 // Track used event separately.
67 if (feature_config.used.name == event_name) {
68 feature_name = fname;
69 DCHECK(!feature_name.empty());
70 std::string used_event_action = "InProductHelp.NotifyUsedEvent.";
71 used_event_action.append(feature_name);
72 base::RecordComputedAction(used_event_action);
73 break;
74 }
75
76 // Find if the |event_name| matches any configuration.
77 for (const auto& event : feature_config.event_configs) {
78 if (event.name == event_name) {
79 feature_name = fname;
80 break;
81 }
82 }
83 if (feature_config.trigger.name == event_name) {
84 feature_name = fname;
85 break;
86 }
87 }
88
89 // Do nothing if no events in the configuration matches the |event_name|.
90 if (feature_name.empty())
91 return;
92
93 std::string event_action = "InProductHelp.NotifyEvent.";
94 event_action.append(feature_name);
95 base::RecordComputedAction(event_action);
96
97 std::string event_histogram = "InProductHelp.NotifyEventReadyState.";
98 event_histogram.append(feature_name);
99 base::UmaHistogramBoolean(event_histogram, is_model_ready);
100 }
101
RecordShouldTriggerHelpUI(const base::Feature & feature,const FeatureConfig & feature_config,const ConditionValidator::Result & result)102 void RecordShouldTriggerHelpUI(const base::Feature& feature,
103 const FeatureConfig& feature_config,
104 const ConditionValidator::Result& result) {
105 // Records the user action.
106 std::string name = std::string(kShouldTriggerHelpUIHistogram)
107 .append(".")
108 .append(feature.name);
109 base::RecordComputedAction(name);
110
111 // Total count histogram, used to compute the percentage of each failure type,
112 // in addition to a user action for whether the result was to trigger or not.
113 if (result.NoErrors()) {
114 LogTriggerHelpUIResult(name,
115 feature_config.tracking_only
116 ? TriggerHelpUIResult::SUCCESS_TRACKING_ONLY
117 : TriggerHelpUIResult::SUCCESS);
118 std::string action_name = "InProductHelp.ShouldTriggerHelpUIResult.";
119 action_name.append(feature_config.tracking_only ? "WouldHaveTriggered"
120 : "Triggered");
121 action_name.append(".");
122 action_name.append(feature.name);
123 base::RecordComputedAction(action_name);
124 } else {
125 LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE);
126 std::string action_name =
127 "InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.";
128 action_name.append(feature.name);
129 base::RecordComputedAction(action_name);
130 }
131
132 // Histogram about the failure reasons.
133 if (!result.event_model_ready_ok) {
134 LogTriggerHelpUIResult(name,
135 TriggerHelpUIResult::FAILURE_EVENT_MODEL_NOT_READY);
136 }
137 if (!result.currently_showing_ok) {
138 LogTriggerHelpUIResult(name,
139 TriggerHelpUIResult::FAILURE_CURRENTLY_SHOWING);
140 }
141 if (!result.feature_enabled_ok) {
142 LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_FEATURE_DISABLED);
143 }
144 if (!result.config_ok) {
145 LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_CONFIG_INVALID);
146 }
147 if (!result.used_ok) {
148 LogTriggerHelpUIResult(
149 name, TriggerHelpUIResult::FAILURE_USED_PRECONDITION_UNMET);
150 }
151 if (!result.trigger_ok) {
152 LogTriggerHelpUIResult(
153 name, TriggerHelpUIResult::FAILURE_TRIGGER_PRECONDITION_UNMET);
154 }
155 if (!result.preconditions_ok) {
156 LogTriggerHelpUIResult(
157 name, TriggerHelpUIResult::FAILURE_OTHER_PRECONDITION_UNMET);
158 }
159 if (!result.session_rate_ok) {
160 LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_SESSION_RATE);
161 }
162 if (!result.availability_model_ready_ok) {
163 LogTriggerHelpUIResult(
164 name, TriggerHelpUIResult::FAILURE_AVAILABILITY_MODEL_NOT_READY);
165 }
166 if (!result.availability_ok) {
167 LogTriggerHelpUIResult(
168 name, TriggerHelpUIResult::FAILURE_AVAILABILITY_PRECONDITION_UNMET);
169 }
170 if (!result.display_lock_ok) {
171 LogTriggerHelpUIResult(name, TriggerHelpUIResult::FAILURE_DISPLAY_LOCK);
172 }
173 }
174
RecordUserDismiss()175 void RecordUserDismiss() {
176 base::RecordAction(base::UserMetricsAction("InProductHelp.Dismissed"));
177 }
178
RecordDbUpdate(bool success,StoreType type)179 void RecordDbUpdate(bool success, StoreType type) {
180 std::string histogram_name =
181 "InProductHelp.Db.Update." + ToDbHistogramSuffix(type);
182 base::UmaHistogramBoolean(histogram_name, success);
183 }
184
RecordDbInitEvent(bool success,StoreType type)185 void RecordDbInitEvent(bool success, StoreType type) {
186 std::string histogram_name =
187 "InProductHelp.Db.Init." + ToDbHistogramSuffix(type);
188 base::UmaHistogramBoolean(histogram_name, success);
189 }
190
RecordEventDbLoadEvent(bool success,const std::vector<Event> & events)191 void RecordEventDbLoadEvent(bool success, const std::vector<Event>& events) {
192 std::string histogram_name =
193 "InProductHelp.Db.Load." + ToDbHistogramSuffix(StoreType::EVENTS_STORE);
194 base::UmaHistogramBoolean(histogram_name, success);
195 UMA_HISTOGRAM_BOOLEAN("InProductHelp.Db.Load", success);
196
197 if (!success)
198 return;
199
200 // Tracks total number of events records when the database is successfully
201 // loaded.
202 int event_count = 0;
203 for (const auto& event : events)
204 event_count += event.events_size();
205 UMA_HISTOGRAM_COUNTS_1000("InProductHelp.Db.TotalEvents", event_count);
206 }
207
RecordAvailabilityDbLoadEvent(bool success)208 void RecordAvailabilityDbLoadEvent(bool success) {
209 std::string histogram_name =
210 "InProductHelp.Db.Load." +
211 ToDbHistogramSuffix(StoreType::AVAILABILITY_STORE);
212 base::UmaHistogramBoolean(histogram_name, success);
213 UMA_HISTOGRAM_BOOLEAN("InProductHelp.Db.Load", success);
214 }
215
RecordConfigParsingEvent(ConfigParsingEvent event)216 void RecordConfigParsingEvent(ConfigParsingEvent event) {
217 UMA_HISTOGRAM_ENUMERATION("InProductHelp.Config.ParsingEvent", event,
218 ConfigParsingEvent::COUNT);
219 }
220
221 } // namespace stats
222 } // namespace feature_engagement
223