Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

Health Data Logs for 1.4 #11311

Merged
merged 8 commits into from
Jul 11, 2015
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/document/DocumentCommandHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ define(function (require, exports, module) {
InMemoryFile = require("document/InMemoryFile"),
StringUtils = require("utils/StringUtils"),
Async = require("utils/Async"),
HealthLogger = require("utils/HealthLogger"),
Dialogs = require("widgets/Dialogs"),
DefaultDialogs = require("widgets/DefaultDialogs"),
Strings = require("strings"),
Expand Down Expand Up @@ -451,6 +452,7 @@ define(function (require, exports, module) {

_doOpenWithOptionalPath(fileInfo.path, silent, paneId, commandData && commandData.options)
.done(function (file) {
HealthLogger.fileOpened(fileInfo.path);
if (!commandData || !commandData.options || !commandData.options.noPaneActivate) {
MainViewManager.setActivePaneId(paneId);
}
Expand Down Expand Up @@ -528,6 +530,7 @@ define(function (require, exports, module) {
return handleFileOpen(commandData).done(function (file) {
var paneId = (commandData && commandData.paneId) || MainViewManager.ACTIVE_PANE;
MainViewManager.addToWorkingSet(paneId, file, commandData.index, commandData.forceRedraw);
HealthLogger.fileOpened(file.fullPath, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way, we call fileOpened two times (one time for handleFileOpen, then for handleFileAddToWorkingSetAndOpen). Is it meant to be like this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is meant to track twice, one log tracks all files opened to working set, and another the total of all files opened.

});
}

Expand Down
9 changes: 7 additions & 2 deletions src/extensions/default/HealthData/HealthDataManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ define(function (require, exports, module) {
"use strict";

var AppInit = brackets.getModule("utils/AppInit"),
HealthLogger = brackets.getModule("utils/HealthLogger"),
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
UrlParams = brackets.getModule("utils/UrlParams").UrlParams,
Strings = brackets.getModule("strings"),
Expand Down Expand Up @@ -69,6 +70,7 @@ define(function (require, exports, module) {
oneTimeHealthData.osLanguage = brackets.app.language;
oneTimeHealthData.bracketsLanguage = brackets.getLocale();
oneTimeHealthData.bracketsVersion = brackets.metadata.version;
$.extend(oneTimeHealthData, HealthLogger.getAggregatedHealthData());

HealthDataUtils.getUserInstalledExtensions()
.done(function (userInstalledExtensions) {
Expand Down Expand Up @@ -123,7 +125,7 @@ define(function (require, exports, module) {
function checkHealthDataSend() {
var result = new $.Deferred(),
isHDTracking = prefs.get("healthDataTracking");

HealthLogger.setHealthLogsEnabled(isHDTracking);
window.clearTimeout(timeoutVar);
if (isHDTracking) {
var nextTimeToSend = PreferencesManager.getViewState("nextHealthDataSendTime"),
Expand All @@ -144,6 +146,9 @@ define(function (require, exports, module) {

sendHealthDataToServer()
.done(function () {
//We have already sent the health data, so can clear ll health data
//Logged till now
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A space after // would be nice here and ll in clear ll health seems to be a typo.

HealthLogger.clearHealthData();
result.resolve();
})
.fail(function () {
Expand Down Expand Up @@ -182,4 +187,4 @@ define(function (require, exports, module) {

exports.getHealthData = getHealthData;
exports.checkHealthDataSend = checkHealthDataSend;
});
});
7 changes: 7 additions & 0 deletions src/extensions/default/HealthData/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ define(function (require, exports, module) {
"use strict";

var AppInit = brackets.getModule("utils/AppInit"),
HealthLogger = brackets.getModule("utils/HealthLogger"),
Menus = brackets.getModule("command/Menus"),
CommandManager = brackets.getModule("command/CommandManager"),
Strings = brackets.getModule("strings"),
Commands = brackets.getModule("command/Commands"),
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),

HealthDataNotification = require("HealthDataNotification"), // self-initializes to show first-launch notification
HealthDataManager = require("HealthDataManager"), // self-initializes timer to send data
Expand All @@ -58,10 +60,15 @@ define(function (require, exports, module) {
brackets.test.HealthDataManager = HealthDataManager;
brackets.test.HealthDataNotification = HealthDataNotification;
brackets.test.HealthDataPopup = HealthDataPopup;

var prefs = PreferencesManager.getExtensionPrefs("healthData"),
hdPref = prefs.get("healthDataTracking");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hdPref should have been isHDTracking like it has been used in HealthDataManager.js

HealthLogger.setHealthLogsEnabled(hdPref);
}

AppInit.appReady(function () {
initTest();
HealthLogger.init();
});

addCommand();
Expand Down
167 changes: 167 additions & 0 deletions src/utils/HealthLogger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/

/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define, jQuery*/

/**
* Utilities functions related to Health data loggig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: loggig, Utility functions
Also, Health data should be either all lowercase or all titlecase, but not mixed up.

*/
define(function (require, exports, module) {
"use strict";

var PreferencesManager = require("preferences/PreferencesManager"),
LanguageManager = require("language/LanguageManager"),
FileUtils = require("file/FileUtils"),
PerfUtils = require("utils/PerfUtils"),

HEALTH_DATA_STATE_KEY = "HealthData.Logs",
logHealthData = true;

/**
* Init: creates the health log preference keys in the state.json file
*/
function init() {
PreferencesManager.stateManager.definePreference(HEALTH_DATA_STATE_KEY, "object", {});
}

/**
* Return the Performance related data
* @returns {Object} Performance Data aggregated till now
*/
function getPerformanceData() {
var perfData = PerfUtils.getHealthReport();
return perfData;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be simple.

function getPerformanceData() {
    return PerfUtils.getHealthReport();
}

}

/**
* Return the aggregate of all health data logged till now from all sources
* @returns {Object} Health Data aggregated till now
*/
function getAggregatedHealthData() {
var healthData = PreferencesManager.getViewState(HEALTH_DATA_STATE_KEY);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better call getHealthData here to access the stored data.

jQuery.extend(healthData, getPerformanceData());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use $ instead of jQuery.

return healthData;
}

/**
* Return all health data logged till now stored in the state prefs
* @returns {Object} Health Data aggregated till now
*/
function getHealthData() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A name like getStoredHealthData might suit better

var healthData = PreferencesManager.getViewState(HEALTH_DATA_STATE_KEY);
return healthData;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also apply here.


/**
* Sets the health data
* @param {Object} dataObject The object to be stored as health data
*/
function setHealthData(dataObject) {
PreferencesManager.setViewState(HEALTH_DATA_STATE_KEY, dataObject);
}

/**
* Returns health data logged for the given key
* @returns {Object} Health Data object for the key or undefined if no health data stored
*/
function getHealthDataLog(key) {
var healthData = getHealthData();
return healthData[key];
}

/**
* Sets the health data for the given key
* @param {Object} dataObject The object to be stored as health data for the key
*/
function setHealthDataLog(key, dataObject) {
var healthData = getHealthData();
healthData[key] = dataObject;
setHealthData(healthData);
}

/**
* Clears all the health data recorded till now
*/
function clearHealthData() {
PreferencesManager.setViewState(HEALTH_DATA_STATE_KEY, {});
//clear the preformance relaed health data also
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typos relaed, preformance, may be this comment could join the JSDoc comment above.

PerfUtils.clear();
}

/**
* Enable or disable health data logs
* @param {Boolean} enabled true to enable health logs
*/
function setHealthLogsEnabled(enabled) {
logHealthData = enabled;
if (!enabled) {
clearHealthData();
}
}

/**
* All the logging functions should be disabled if this returns false
* @returns {Boolean} true if health data can be logged
*/
function shouldLogHealthData() {
return logHealthData;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is a simple getter that is used only once and also not being exported, so we could eliminate it and use logHealthData where shouldLogHealthData is being called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exported for access from other modules for future use.


/**
* When ever a file is opened call this function. The function will record the number of times
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Whenever

* the standard file types have been opened. We only log the standard filetypes
* @param {String} filePath The path of the file to be registered
* @param {Boolean} addedToWorkingSet set to true if extensions of files added to the
* working set needs to be logged
*/
function fileOpened(filePath, addedToWorkingSet) {
if (!shouldLogHealthData()) {
return;
}
var fileextension = FileUtils.getFileExtension(filePath),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fileextension should be in camalCase to be more readable.

language = LanguageManager.getLanguageForPath(filePath),
healthData = getHealthData();
healthData.fileStats = healthData.fileStats || {
openedFileExt : {},
workingSetFileExt : {}
};
if (language.getId() !== "unknown") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Belated, but: is there a reason we don't want to log unrecognized file extensions too? Seems like it'd be a useful way of identifying gaps in our default set of syntax highlighters & file-extension mappings...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File names and extensions I think are personal information. So it felt like one step short of sending all filenames opened in brackets to the servers- which makes even me paranoid. 😖

if (addedToWorkingSet) {
healthData.fileStats.workingSetFileExt[fileextension] = healthData.fileStats.workingSetFileExt[fileextension] ? healthData.fileStats.workingSetFileExt[fileextension] + 1 : 1;
} else {
healthData.fileStats.openedFileExt[fileextension] = healthData.fileStats.openedFileExt[fileextension] ? healthData.fileStats.openedFileExt[fileextension] + 1 : 1;
}
setHealthData(healthData);
}
}

// Define public API
exports.getHealthDataLog = getHealthDataLog;
exports.setHealthDataLog = setHealthDataLog;
exports.getAggregatedHealthData = getAggregatedHealthData;
exports.clearHealthData = clearHealthData;
exports.fileOpened = fileOpened;
exports.setHealthLogsEnabled = setHealthLogsEnabled;
exports.init = init;
});
84 changes: 67 additions & 17 deletions src/utils/PerfUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
define(function (require, exports, module) {
"use strict";

var _ = require("thirdparty/lodash");
var _ = require("thirdparty/lodash"),
StringUtils = require("utils/StringUtils");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation issue here.


// make sure the global brackets variable is loaded
require("utils/Global");
Expand Down Expand Up @@ -303,30 +304,53 @@ define(function (require, exports, module) {
}

/**
* Returns the performance data as a tab deliminted string
* @return {string}
* return single value, or `,` seperated values for an array or return aggregated values with
* <min value, average, maxv value, stantard deviation>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo maxv value

* @param {Array} entry An array or a single value
* @param {Boolean} aggregateStats If set, the returned value will be aggregated in the form -
* <min(avg)max[standard deviation]>
* @returns {String} a single value, or coma seperated values in an array or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typos coma, seperated

* <min(avg)max[standard deviation]> if aggregateStats is set
*/
function getDelimitedPerfData() {
var getValue = function (entry) {
// return single value, or tab deliminted values for an array
if (Array.isArray(entry)) {
var i, values = "";

var getValueAsString = function (entry, aggregateStats) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we just use function getValueAsString instead of assigning it?

if (Array.isArray(entry)) {
var i, values = "", min = entry[0], max = entry[0], avg = 0, sum = 0, sd = 0;

for (i = 0; i < entry.length; i++) {
sum = sum + entry[i];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use += here, too.

values += entry[i];
if (i < entry.length - 1) {
values += ", ";
}
}
if (aggregateStats) {
avg = Math.round(sum / entry.length);
sum = 0;
for (i = 0; i < entry.length; i++) {
values += entry[i];
if (i < entry.length - 1) {
values += ", ";
sum = sum + Math.pow((entry[i] - avg), 2);
if (entry[i] < min) {
min = entry[i];
} else if (entry[i] > max) {
max = entry[i];
}
}
return values;
} else {
return entry;
sd = Math.round(Math.sqrt(sum / entry.length));
return min + "(" + avg + ")" + max + "[" + sd + "]";
}
};
return values;
} else {
return entry;
}
};

/**
* Returns the performance data as a tab deliminted string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not your fault, but a typo anyways: deliminted

* @return {string}
*/
function getDelimitedPerfData() {
var result = "";
_.forEach(perfData, function (entry, testName) {
result += getValue(entry) + "\t" + testName + "\n";
result += getValueAsString(entry) + "\t" + testName + "\n";
});

return result;
Expand All @@ -344,6 +368,31 @@ define(function (require, exports, module) {
return perfData[id];
}

/**
* Returns the Performance metrics to be logged for health report
* @returns {Object} An object with the helath data logs to be send
*/
function getHealthReport() {
var healthReport = {
projectLoadTimes : "",
fileOpenTimes : ""
};

_.forEach(perfData, function (entry, testName) {
if (StringUtils.startsWith(testName, "Application Startup")) {
healthReport.AppStartupTime = getValueAsString(entry);
} else if (StringUtils.startsWith(testName, "brackets module dependencies resolved")) {
healthReport.ModuleDepsResolved = getValueAsString(entry);
} else if (StringUtils.startsWith(testName, "Load Project")) {
healthReport.projectLoadTimes = healthReport.projectLoadTimes + ":" + getValueAsString(entry, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use += (same goes for below)

} else if (StringUtils.startsWith(testName, "Open File")) {
healthReport.fileOpenTimes = healthReport.fileOpenTimes + ":" + getValueAsString(entry, true);
}
});

return healthReport;
}

function searchData(regExp) {
var keys = Object.keys(perfData).filter(function (key) {
return regExp.test(key);
Expand Down Expand Up @@ -384,4 +433,5 @@ define(function (require, exports, module) {
exports.getDelimitedPerfData = getDelimitedPerfData;
exports.createPerfMeasurement = createPerfMeasurement;
exports.clear = clear;
exports.getHealthReport = getHealthReport;
});
Loading