The Feature Usage Metrics library provides a unified approach to report feature usage events. The tracked events have standard names and new features could be easily incorporated on the data analytics side.
Design doc for Sharing SFUL in Chrome & ChromeOS.
Any changes should first be made to the feature usage library in chromium here, and then exported to ChromeOS.
This library is the part of Standard Feature Usage Logging (Googlers could see go/sful and go/sful-dd). The goal is to make metrics calculation and analysis easily scalable to the new features. Both for feature owners and for data analytics team.
The following events are reported by the library (for details see FeatureUsageEvent)
The first two are reported periodically every 30 minutes. To correctly track 1-, 7-, 28-days users. These events are also reported on the object creation and on the system resume from suspension. The feature usage library encapsulates this logic.
For more details see original CL.
You need to do the following things to integrate your feature, all described in detail below.
Example:
CROS_WORKON_SUBTREE="common-mk feature_usage package .gn"
For more information on ebuild, please see How to write an ebuild for a platform2 package.
In the BUILD.gn
file, add libfeature_usage
to the dependencies of any target that needs it.
Include the <feature_usage/feature_usage_metrics.h>
header file.
You need to add a new variant into <variants name="FeaturesLoggingUsageEvents">
//tools/metrics/histograms/metadata/chromeos/histograms.xml
:<variant name="YourFeature" summary="your feature"> <owner>you@chromium.org<owner> <owner>your-team@chromium.org</owner> </variant>
In your feature summary, it will be good to include that the metric is coming from ChromiumOS vs Chromium.
You need to implement FeatureUsageMetrics::Delegate
and pass it to the FeatureUsageMetrics
. Delegate is called to report periodic events (eligible, accessible, enabled). Delegate is called on the same sequence FeatureUsageMetrics was created. FeatureUsageMetrics must be used only on the sequence it was created.
class MyDelegate : public FeatureUsageMetrics::Delegate { public: bool IsEligible() const final { ... } // Optional. Default implementation returns `std::nullopt` which do not emit // any UMA events. std::optional<bool> IsAccessible() const final { ... } // If `IsEnabled` returns true `IsEligible` must return true too. bool IsEnabled() const final { ... } };
feature_usage_metrics_ = std::make_unique<FeatureUsageMetrics>( "YourFeature", my_delegate);
YourFeature
must correspond to the histogram and never change. MyDelegate
object must outlive the FeatureUsageMetrics
object.
Call feature_usage_metrics_->RecordUsage(bool success);
on every usage attempt. Success indicates whether or not the attempt to use was successful. Your feature might not have failed attempts. In that case always call with success=true
.
MyDelegate::IsEligible
and MyDelegate::IsEnabled
(also MyDelegate::IsAccessible
if implemented) functions must return true
when RecordUsage
is called.
If your feature has a notion of time usage use feature_usage_metrics_->StartSuccessfulUsage();
and feature_usage_metrics_->StopSuccessfulUsage();
to record feature usage time.
StartSuccessfulUsage
calls without StopSuccessfulUsage
call in-between.StartSuccessfulUsage
is called the usage time is reported periodically together with IsEligible
and IsEnabled
(also IsAccessible
if implemented).StartSuccessfulUsage
is not followed by StopSuccessfulUsage
the remaining usage time is recorded at the object shutdown.StartSuccessfulUsage
must be preceded by exactly one RecordUsage(true)
. There should be no RecordUsage
calls in-between StartSuccessfulUsage
and StopSuccessfulUsage
calls.Example:
// feature_usage_metrics_->StartSuccessfulUsage(); should be preceded by RecordUsage(true) feature_usage_metrics_->RecordUsage(false); // feature_usage_metrics_->StartSuccessfulUsage(); should be preceded by RecordUsage(true) feature_usage_metrics_->RecordUsage(true); feature_usage_metrics_->StartSuccessfulUsage(); feature_usage_metrics_->StopSuccessfulUsage(); // feature_usage_metrics_->StartSuccessfulUsage(); should be preceded by RecordUsage(true) feature_usage_metrics_->RecordUsage(true); feature_usage_metrics_->RecordUsage(true); // feature_usage_metrics_->StartSuccessfulUsage(); should be preceded by exactly one RecordUsage(true) .... feature_usage_metrics_->StartSuccessfulUsage(); feature_usage_metrics_->reset(); // Usage time is recorded similar to StopSuccessfulUsage