summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authorrogerta@chromium.org <rogerta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-26 18:08:43 +0000
committerrogerta@chromium.org <rogerta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-26 18:08:43 +0000
commit438772df5a7055847d061d49a8c18e6fc77daedb (patch)
treec748b7ff544f07d888a6978cac99c7c1b5d261b6 /chrome/browser/extensions
parent46ef2ce78952914d3723b07aae28b024a1e8a6ad (diff)
downloadchromium_src-438772df5a7055847d061d49a8c18e6fc77daedb.zip
chromium_src-438772df5a7055847d061d49a8c18e6fc77daedb.tar.gz
chromium_src-438772df5a7055847d061d49a8c18e6fc77daedb.tar.bz2
Add a metrics extensions API.
See http://docs.google.com/View?id=dd4ngnpz_0dpsb8n96 for API proposal. BUG=0 TEST=See unit tests as part of this CL Review URL: http://codereview.chromium.org/657037 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40130 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/extension_apitest.cc4
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc16
-rw-r--r--chrome/browser/extensions/extension_metrics_apitest.cc152
-rw-r--r--chrome/browser/extensions/extension_metrics_module.cc153
-rw-r--r--chrome/browser/extensions/extension_metrics_module.h65
5 files changed, 390 insertions, 0 deletions
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index 25eff22..e5a0768 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/test/ui_test_utils.h"
@@ -103,4 +104,7 @@ Extension* ExtensionApiTest::GetSingleLoadedExtension() {
void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) {
ExtensionBrowserTest::SetUpCommandLine(command_line);
test_data_dir_ = test_data_dir_.AppendASCII("api_test");
+
+ // Needed for metrics extension API tests.
+ command_line->AppendSwitch(switches::kEnableMetricsExtensionApi);
}
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 35b73a5..8f868eb 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/extension_history_api.h"
#include "chrome/browser/extensions/extension_i18n_api.h"
#include "chrome/browser/extensions/extension_message_service.h"
+#include "chrome/browser/extensions/extension_metrics_module.h"
#include "chrome/browser/extensions/extension_page_actions_module.h"
#include "chrome/browser/extensions/extension_page_actions_module_constants.h"
#include "chrome/browser/extensions/extension_popup_api.h"
@@ -34,6 +35,7 @@
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/result_codes.h"
#include "chrome/common/url_constants.h"
@@ -169,6 +171,20 @@ void FactoryRegistry::ResetFunctions() {
// Processes.
RegisterFunction<GetProcessForTabFunction>();
+ // Metrics.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableMetricsExtensionApi)) {
+ RegisterFunction<MetricsRecordUserActionFunction>();
+ RegisterFunction<MetricsRecordValueFunction>();
+ RegisterFunction<MetricsRecordPercentageFunction>();
+ RegisterFunction<MetricsRecordCountFunction>();
+ RegisterFunction<MetricsRecordSmallCountFunction>();
+ RegisterFunction<MetricsRecordMediumCountFunction>();
+ RegisterFunction<MetricsRecordTimeFunction>();
+ RegisterFunction<MetricsRecordMediumTimeFunction>();
+ RegisterFunction<MetricsRecordLongTimeFunction>();
+ }
+
// Test.
RegisterFunction<ExtensionTestPassFunction>();
RegisterFunction<ExtensionTestFailFunction>();
diff --git a/chrome/browser/extensions/extension_metrics_apitest.cc b/chrome/browser/extensions/extension_metrics_apitest.cc
new file mode 100644
index 0000000..39d342a
--- /dev/null
+++ b/chrome/browser/extensions/extension_metrics_apitest.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <map>
+
+#include "base/histogram.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_registrar.h"
+
+namespace {
+
+// The tests that are run by this extension are expected to record the following
+// user actions, with the specified counts. If the tests in test.js are
+// modified, this array may need to be updated.
+struct RecordedUserAction {
+ const char* name; // base name of metric without extension id.
+ int count; // number of times the metric was recorded.
+} g_user_actions[] = {
+ {"test.ua.1", 1},
+ {"test.ua.2", 2},
+};
+
+// The tests that are run by this extension are expected to record the following
+// histograms. If the tests in test.js are modified, this array may need to be
+// updated.
+struct RecordedHistogram {
+ const char* name; // base name of metric without extension id.
+ Histogram::ClassType type;
+ int min;
+ int max;
+ size_t buckets;
+} g_histograms[] = {
+ {"test.h.1", Histogram::HISTOGRAM, 1, 100, 50}, // custom
+ {"test.h.2", Histogram::LINEAR_HISTOGRAM, 1, 200, 50}, // custom
+ {"test.h.3", Histogram::LINEAR_HISTOGRAM, 1, 101, 102}, // percentage
+ {"test.time", Histogram::HISTOGRAM, 1, 10000, 50},
+ {"test.medium.time", Histogram::HISTOGRAM, 1, 180000, 50},
+ {"test.long.time", Histogram::HISTOGRAM, 1, 3600000, 50},
+ {"test.count", Histogram::HISTOGRAM, 1, 1000000, 50},
+ {"test.medium.count", Histogram::HISTOGRAM, 1, 10000, 50},
+ {"test.small.count", Histogram::HISTOGRAM, 1, 100, 50},
+};
+
+// Build the full name of a metrics for the given extension. Each metric
+// is made up of the unique name within the extension followed by the
+// extension's id.
+std::string BuildFullName(const std::string& name, const Extension* extension) {
+ std::string full_name(name);
+ full_name += extension->id();
+ return full_name;
+}
+
+// This class observes and collects user action notifications that are sent
+// by the tests, so that they can be examined afterwards for correctness.
+class UserActionObserver : public NotificationObserver {
+ public:
+ UserActionObserver();
+
+ void ValidateUserActions(const Extension* extension,
+ const RecordedUserAction* recorded,
+ int count);
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ typedef std::map<std::string, int> UserActionCountMap;
+
+ int num_metrics() const {
+ return count_map_.size();
+ }
+
+ int GetMetricCount(const std::string& name) const {
+ UserActionCountMap::const_iterator i = count_map_.find(name);
+ return i == count_map_.end() ? -1 : i->second;
+ }
+
+ NotificationRegistrar registrar_;
+ UserActionCountMap count_map_;
+};
+
+UserActionObserver::UserActionObserver() {
+ registrar_.Add(this, NotificationType::USER_ACTION,
+ NotificationService::AllSources());
+}
+
+void UserActionObserver::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ const char* name = *Details<const char*>(details).ptr();
+ ++(count_map_[name]);
+}
+
+void UserActionObserver::ValidateUserActions(const Extension* extension,
+ const RecordedUserAction* recorded,
+ int count) {
+ EXPECT_EQ(count, num_metrics());
+
+ for (int i = 0; i < count; ++i) {
+ const RecordedUserAction& ua = recorded[i];
+ EXPECT_EQ(ua.count, GetMetricCount(BuildFullName(ua.name, extension)));
+ }
+}
+
+void ValidateHistograms(const Extension* extension,
+ const RecordedHistogram* recorded,
+ int count) {
+ StatisticsRecorder::Histograms histograms;
+ StatisticsRecorder::GetHistograms(&histograms);
+
+ // Code other than the tests tun here will record some histogram values, but
+ // we will ignore those. This function validates that all the histogram we
+ // expect to see are present in the list, and that their basic info is
+ // correct.
+ for (int i = 0; i < count; ++i) {
+ const RecordedHistogram& r = recorded[i];
+ std::string name(BuildFullName(r.name, extension));
+
+ size_t j = 0;
+ for (j = 0; j < histograms.size(); ++j) {
+ scoped_refptr<Histogram> histogram(histograms[j]);
+
+ if (name == histogram->histogram_name()) {
+ EXPECT_EQ(r.type, histogram->histogram_type());
+ EXPECT_EQ(r.min, histogram->declared_min());
+ EXPECT_EQ(r.max, histogram->declared_max());
+ EXPECT_EQ(r.buckets, histogram->bucket_count());
+ break;
+ }
+ }
+ EXPECT_LT(j, histograms.size());
+ }
+}
+
+} // anonymous namespace
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Metrics) {
+ UserActionObserver observer;
+
+ ASSERT_TRUE(RunExtensionTest("metrics")) << message_;
+ Extension* extension = GetSingleLoadedExtension();
+ ASSERT_TRUE(extension);
+
+ observer.ValidateUserActions(extension,
+ g_user_actions,
+ arraysize(g_user_actions));
+ ValidateHistograms(extension, g_histograms, arraysize(g_histograms));
+}
diff --git a/chrome/browser/extensions/extension_metrics_module.cc b/chrome/browser/extensions/extension_metrics_module.cc
new file mode 100644
index 0000000..30db486
--- /dev/null
+++ b/chrome/browser/extensions/extension_metrics_module.cc
@@ -0,0 +1,153 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_metrics_module.h"
+
+#include "base/histogram.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/browser/metrics/user_metrics.h"
+
+namespace {
+
+// Build the full name of a metrics for the given extension. Each metric
+// is made up of the unique name within the extension followed by the
+// extension's id. This keeps the metrics from one extension unique from
+// other extensions, as well as those metrics from chrome itself.
+std::string BuildMetricName(const std::string& name,
+ const Extension* extension) {
+ std::string full_name(name);
+ full_name += extension->id();
+ return full_name;
+}
+
+} // anonymous namespace
+
+// These extension function classes are enabled only if the
+// enable-metrics-extension-api command line switch is used. Refer to
+// extension_function_dispatcher.cc to see how they are enabled.
+
+bool MetricsRecordUserActionFunction::RunImpl() {
+ std::string name;
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_STRING));
+ EXTENSION_FUNCTION_VALIDATE(args_->GetAsString(&name));
+
+ name = BuildMetricName(name, GetExtension());
+ UserMetrics::RecordComputedAction(name, profile());
+ return true;
+}
+
+bool MetricsHistogramHelperFunction::GetNameAndSample(std::string* name,
+ int* sample) {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST));
+ const ListValue* args = args_as_list();
+
+ EXTENSION_FUNCTION_VALIDATE(args->GetString(0, name));
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger(1, sample));
+ return true;
+}
+
+bool MetricsHistogramHelperFunction::RecordValue(const std::string& name,
+ Histogram::ClassType type,
+ int min,
+ int max,
+ size_t buckets,
+ int sample) {
+ std::string full_name = BuildMetricName(name, GetExtension());
+ scoped_refptr<Histogram> counter;
+ if (type == Histogram::LINEAR_HISTOGRAM) {
+ counter = LinearHistogram::FactoryGet(full_name,
+ min,
+ max,
+ buckets,
+ Histogram::kUmaTargetedHistogramFlag);
+ } else {
+ counter = Histogram::FactoryGet(full_name,
+ min,
+ max,
+ buckets,
+ Histogram::kUmaTargetedHistogramFlag);
+ }
+
+ counter->Add(sample);
+ return true;
+}
+
+bool MetricsRecordValueFunction::RunImpl() {
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST));
+ const ListValue* args = args_as_list();
+
+ int sample;
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger(1, &sample));
+
+ // Get the histogram parameters from the metric type object.
+ DictionaryValue* metric_type;
+ EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(0, &metric_type));
+
+ std::string name;
+ std::string type;
+ int min;
+ int max;
+ int buckets;
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetString(L"metricName", &name));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetString(L"type", &type));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger(L"min", &min));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger(L"max", &max));
+ EXTENSION_FUNCTION_VALIDATE(metric_type->GetInteger(L"buckets", &buckets));
+
+ Histogram::ClassType histogram_type(type == "histogram-linear" ?
+ Histogram::LINEAR_HISTOGRAM : Histogram::HISTOGRAM);
+ return RecordValue(name, histogram_type, min, max, buckets, sample);
+}
+
+bool MetricsRecordPercentageFunction::RunImpl() {
+ std::string name;
+ int sample;
+ EXTENSION_FUNCTION_VALIDATE(GetNameAndSample(&name, &sample));
+ return RecordValue(name, Histogram::LINEAR_HISTOGRAM, 1, 101, 102, sample);
+}
+
+bool MetricsRecordCountFunction::RunImpl() {
+ std::string name;
+ int sample;
+ EXTENSION_FUNCTION_VALIDATE(GetNameAndSample(&name, &sample));
+ return RecordValue(name, Histogram::HISTOGRAM, 1, 1000000, 50, sample);
+}
+
+bool MetricsRecordSmallCountFunction::RunImpl() {
+ std::string name;
+ int sample;
+ EXTENSION_FUNCTION_VALIDATE(GetNameAndSample(&name, &sample));
+ return RecordValue(name, Histogram::HISTOGRAM, 1, 100, 50, sample);
+}
+
+bool MetricsRecordMediumCountFunction::RunImpl() {
+ std::string name;
+ int sample;
+ EXTENSION_FUNCTION_VALIDATE(GetNameAndSample(&name, &sample));
+ return RecordValue(name, Histogram::HISTOGRAM, 1, 10000, 50, sample);
+}
+
+bool MetricsRecordTimeFunction::RunImpl() {
+ std::string name;
+ int sample;
+ EXTENSION_FUNCTION_VALIDATE(GetNameAndSample(&name, &sample));
+ static const int kTenSecMs = 10 * 1000;
+ return RecordValue(name, Histogram::HISTOGRAM, 1, kTenSecMs, 50, sample);
+}
+
+bool MetricsRecordMediumTimeFunction::RunImpl() {
+ std::string name;
+ int sample;
+ EXTENSION_FUNCTION_VALIDATE(GetNameAndSample(&name, &sample));
+ static const int kThreeMinMs = 3 * 60 * 1000;
+ return RecordValue(name, Histogram::HISTOGRAM, 1, kThreeMinMs, 50, sample);
+}
+
+bool MetricsRecordLongTimeFunction::RunImpl() {
+ std::string name;
+ int sample;
+ EXTENSION_FUNCTION_VALIDATE(GetNameAndSample(&name, &sample));
+ static const int kOneHourMs = 60 * 60 * 1000;
+ return RecordValue(name, Histogram::HISTOGRAM, 1, kOneHourMs, 50, sample);
+}
diff --git a/chrome/browser/extensions/extension_metrics_module.h b/chrome/browser/extensions/extension_metrics_module.h
new file mode 100644
index 0000000..c2ffdd2
--- /dev/null
+++ b/chrome/browser/extensions/extension_metrics_module.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_METRICS_MODULE_H__
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_METRICS_MODULE_H__
+
+#include <string>
+
+#include "base/histogram.h"
+#include "chrome/browser/extensions/extension_function.h"
+
+class MetricsRecordUserActionFunction : public SyncExtensionFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordUserAction")
+};
+
+class MetricsHistogramHelperFunction : public SyncExtensionFunction {
+ protected:
+ bool GetNameAndSample(std::string* name, int* sample);
+ virtual bool RecordValue(const std::string& name, Histogram::ClassType type,
+ int min, int max, size_t buckets, int sample);
+};
+
+class MetricsRecordValueFunction : public MetricsHistogramHelperFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordValue")
+};
+
+class MetricsRecordPercentageFunction : public MetricsHistogramHelperFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordPercentage")
+};
+
+class MetricsRecordCountFunction : public MetricsHistogramHelperFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordCount")
+};
+
+class MetricsRecordSmallCountFunction : public MetricsHistogramHelperFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordSmallCount")
+};
+
+class MetricsRecordMediumCountFunction : public MetricsHistogramHelperFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordMediumCount")
+};
+
+class MetricsRecordTimeFunction : public MetricsHistogramHelperFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordTime")
+};
+
+class MetricsRecordMediumTimeFunction : public MetricsHistogramHelperFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordMediumTime")
+};
+
+class MetricsRecordLongTimeFunction : public MetricsHistogramHelperFunction {
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("metrics.recordLongTime")
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_METRICS_MODULE_H__