Bug 1458574 - Add histogram to track file age in profile directory. r?chutten
During every scan of the profile directory, we now record the age relative to the current date of each file seen.
In theory we should rarely need to scan the profile directory, as on invocation it also stores the found time in a `times.json` file.
We therefore don't need precise tracking above 4 years (~ 1500 days).
One thing to note:
ProfileAge might get re-entered, each invocation then starting a profile directory scan, as no `times.json` is found.
The actual write of the file is done atomically, so the file should never be corrupted due to this.
MozReview-Commit-ID: 7tfbUXDrnv5
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -13714,16 +13714,26 @@
"record_in_processes": ["main"],
"alert_emails": ["jhofmann@mozilla.com"],
"bug_numbers": [1286118],
"expires_in_version": "64",
"kind": "boolean",
"keyed": true,
"description": "Permission requests (showing a permission prompt) by whether they were requested from code handling a user input event."
},
+ "PROFILE_DIRECTORY_FILE_AGE": {
+ "record_in_processes": ["main"],
+ "alert_emails": ["jrediger@mozilla.com", "telemetry-client-dev@mozilla.com"],
+ "bug_numbers": [1458574],
+ "expires_in_version": "65",
+ "high": 1500,
+ "n_buckets": 20,
+ "kind": "exponential",
+ "description": "Age of files scanned in profile directory in days when determining initial profile age."
+ },
"HTMLEDITORS_WITH_RESIZERS": {
"record_in_processes": ["content"],
"alert_emails": ["mnakano@mozilla.com"],
"bug_numbers": [1452538,1449564],
"expires_in_version": "65",
"kind": "boolean",
"releaseChannelCollection": "opt-out",
"description": "Number of HTML editors which has shown object resizers."
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -1219,16 +1219,30 @@ telemetry:
keyed: true
notification_emails:
- telemetry-client-dev@mozilla.com
- chutten@mozilla.com
release_channel_collection: opt-out
record_in_processes:
- 'all'
+ profile_directory_scans:
+ bug_numbers:
+ - 1458574
+ description: >
+ The number of times a profile directory scan was initiated in ProfileAge.jsm
+ expires: "65"
+ kind: uint
+ notification_emails:
+ - jrediger@mozilla.com
+ - telemetry-client-dev@mozilla.com
+ release_channel_collection: opt-out
+ record_in_processes:
+ - 'all'
+
telemetry.discarded:
accumulations:
bug_numbers:
- 1369041
description: >
Number of discarded accumulations to histograms in child processes
expires: "never"
kind: uint
--- a/toolkit/modules/ProfileAge.jsm
+++ b/toolkit/modules/ProfileAge.jsm
@@ -1,21 +1,33 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["ProfileAge"];
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/TelemetryUtils.jsm");
ChromeUtils.import("resource://gre/modules/osfile.jsm");
ChromeUtils.import("resource://gre/modules/Log.jsm");
ChromeUtils.import("resource://services-common/utils.js");
/**
+ * Calculate how many days passed between two dates.
+ * @param {Object} aStartDate The starting date.
+ * @param {Object} aEndDate The ending date.
+ * @return {Integer} The number of days between the two dates.
+ */
+function getElapsedTimeInDays(aStartDate, aEndDate) {
+ return TelemetryUtils.millisecondsToDays(aEndDate - aStartDate);
+}
+
+/**
* Profile access to times.json (eg, creation/reset time).
* This is separate from the provider to simplify testing and enable extraction
* to a shared location in the future.
*/
var ProfileAge = function(profile, log) {
this.profilePath = profile || OS.Constants.Path.profileDir;
if (!this.profilePath) {
throw new Error("No profile directory.");
@@ -118,39 +130,48 @@ this.ProfileAge.prototype = {
},
/**
* Traverse the contents of the profile directory, finding the oldest file
* and returning its creation timestamp.
*/
getOldestProfileTimestamp() {
let self = this;
- let oldest = Date.now() + 1000;
+ let start = Date.now();
+ let oldest = start + 1000;
let iterator = new OS.File.DirectoryIterator(this.profilePath);
self._log.debug("Iterating over profile " + this.profilePath);
if (!iterator) {
throw new Error("Unable to fetch oldest profile entry: no profile iterator.");
}
+ Services.telemetry.scalarAdd("telemetry.profile_directory_scans", 1);
+ let histogram = Services.telemetry.getHistogramById("PROFILE_DIRECTORY_FILE_AGE");
+
function onEntry(entry) {
function onStatSuccess(info) {
// OS.File doesn't seem to be behaving. See Bug 827148.
// Let's do the best we can. This whole function is defensive.
let date = info.winBirthDate || info.macBirthDate;
if (!date || !date.getTime()) {
// OS.File will only return file creation times of any kind on Mac
// and Windows, where birthTime is defined.
// That means we're unable to function on Linux, so we use mtime
// instead.
self._log.debug("No birth date. Using mtime.");
date = info.lastModificationDate;
}
if (date) {
let timestamp = date.getTime();
+ // Get the age relative to now.
+ // We don't care about dates in the future.
+ let age_in_days = Math.max(0, getElapsedTimeInDays(timestamp, start));
+ histogram.add(age_in_days);
+
self._log.debug("Using date: " + entry.path + " = " + date);
if (timestamp < oldest) {
oldest = timestamp;
}
}
}
function onStatFailure(e) {