blob: b78d07879ac92ee5613f79ff39bcad9a4881d4f0 [file] [log] [blame]
// Copyright (c) 2014 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.
/**
* @fileoverview Utility methods for accessing chrome.metricsPrivate API.
*
* To be included as a first script in main.html
*/
var metrics; // Needs to be defined in each window which uses metrics.
const metricsBase = {};
/**
* A map from interval name to interval start timestamp.
*/
metricsBase.intervals = {};
/**
* A mapping of enum names to valid values. This object is consulted
* any time an enum value is being reported un-accompanied by a list
* of valid values.
*
* <p>Values mut be provided by base classes. Values should correspond exactly
* with values from histograms.xml.
*
* @private {!Object<!Array<*>|number>}
*/
metricsBase.validEnumValues_ = {};
/**
* Start the named time interval.
* Should be followed by a call to recordInterval with the same name.
*
* @param {string} name Unique interval name.
*/
metricsBase.startInterval = name => {
metricsBase.intervals[name] = Date.now();
};
/**
* Convert a short metric name to the full format.
*
* @param {string} name Short metric name.
* @return {string} Full metric name.
* @private
*/
metricsBase.convertName_ = name => {
throw new Error('metricsBase.convertName_() must be overrideen by subclass.');
};
/**
* Wrapper method for calling chrome.fileManagerPrivate safely.
* @param {string} methodName Method name.
* @param {Array<Object>} args Arguments.
* @private
*/
metricsBase.call_ = (methodName, args) => {
try {
chrome.metricsPrivate[methodName].apply(chrome.metricsPrivate, args);
} catch (e) {
console.error(e.stack);
}
// Support writing metrics.log in manual testing to log method calls.
if (/** @type{{ log: (boolean|undefined) }} */ (metrics).log) {
console.log('chrome.metricsPrivate.' + methodName, args);
}
};
/**
* Records a value than can range from 1 to 10,000.
* @param {string} name Short metric name.
* @param {number} value Value to be recorded.
*/
metricsBase.recordMediumCount = (name, value) => {
metrics.call_('recordMediumCount', [metrics.convertName_(name), value]);
};
/**
* Records a value than can range from 1 to 100.
* @param {string} name Short metric name.
* @param {number} value Value to be recorded.
*/
metricsBase.recordSmallCount = (name, value) => {
metrics.call_('recordSmallCount', [metrics.convertName_(name), value]);
};
/**
* Records an elapsed time of no more than 10 seconds.
* @param {string} name Short metric name.
* @param {number} time Time to be recorded in milliseconds.
*/
metricsBase.recordTime = (name, time) => {
metrics.call_('recordTime', [metrics.convertName_(name), time]);
};
/**
* Records a boolean value to the given metric.
* @param {string} name Short metric name.
* @param {boolean} value The value to be recorded.
*/
metricsBase.recordBoolean = (name, value) => {
metrics.call_('recordBoolean', [metrics.convertName_(name), value]);
};
/**
* Records an action performed by the user.
* @param {string} name Short metric name.
*/
metricsBase.recordUserAction = name => {
metrics.call_('recordUserAction', [metrics.convertName_(name)]);
};
/**
* Records an elapsed time of no more than 10 seconds.
* @param {string} name Short metric name.
* @param {number} value Numeric value to be recorded in units
* that match the histogram definition (in histograms.xml).
*/
metricsBase.recordValue = (name, value) => {
metrics.call_('recordValue', [metrics.convertName_(name), value]);
};
/**
* Complete the time interval recording.
*
* Should be preceded by a call to startInterval with the same name. *
*
* @param {string} name Unique interval name.
*/
metricsBase.recordInterval = name => {
if (name in metrics.intervals) {
metrics.recordTime(name, Date.now() - metrics.intervals[name]);
} else {
console.error('Unknown interval: ' + name);
}
};
/**
* Record an enum value.
*
* @param {string} name Metric name.
* @param {*} value Enum value.
* @param {Array<*>|number=} opt_validValues Array of valid values
* or a boundary number (one-past-the-end) value.
*/
metricsBase.recordEnum = (name, value, opt_validValues) => {
let boundaryValue;
let index;
let validValues = opt_validValues;
if (metrics.validEnumValues_ && name in metrics.validEnumValues_) {
console.assert(validValues === undefined);
validValues = metrics.validEnumValues_[name];
}
console.assert(validValues !== undefined);
if (validValues.constructor.name == 'Array') {
index = validValues.indexOf(value);
boundaryValue = validValues.length;
} else {
index = /** @type {number} */ (value);
boundaryValue = validValues;
}
// Collect invalid values in the overflow bucket at the end.
if (index < 0 || index >= boundaryValue) {
index = boundaryValue - 1;
}
// Setting min to 1 looks strange but this is exactly the recommended way
// of using histograms for enum-like types. Bucket #0 works as a regular
// bucket AND the underflow bucket.
// (Source: UMA_HISTOGRAM_ENUMERATION definition in base/metrics/histogram.h)
const metricDescr = {
'metricName': metrics.convertName_(name),
'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR,
'min': 1,
'max': boundaryValue,
'buckets': boundaryValue
};
metrics.call_('recordValue', [metricDescr, index]);
};