-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Health Data Logs for 1.4 #11311
Health Data Logs for 1.4 #11311
Changes from 5 commits
c59ef20
40f4d24
f09c229
d673fe3
b26d604
c2c4499
806f3f5
90f9a38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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"), | ||
|
@@ -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) { | ||
|
@@ -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"), | ||
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A space after |
||
HealthLogger.clearHealthData(); | ||
result.resolve(); | ||
}) | ||
.fail(function () { | ||
|
@@ -182,4 +187,4 @@ define(function (require, exports, module) { | |
|
||
exports.getHealthData = getHealthData; | ||
exports.checkHealthDataSend = checkHealthDataSend; | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
HealthLogger.setHealthLogsEnabled(hdPref); | ||
} | ||
|
||
AppInit.appReady(function () { | ||
initTest(); | ||
HealthLogger.init(); | ||
}); | ||
|
||
addCommand(); | ||
|
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo: |
||
*/ | ||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better call |
||
jQuery.extend(healthData, getPerformanceData()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We usually use |
||
return healthData; | ||
} | ||
|
||
/** | ||
* Return all health data logged till now stored in the state prefs | ||
* @returns {Object} Health Data aggregated till now | ||
*/ | ||
function getHealthData() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A name like |
||
var healthData = PreferencesManager.getViewState(HEALTH_DATA_STATE_KEY); | ||
return healthData; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typos |
||
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; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
language = LanguageManager.getLanguageForPath(filePath), | ||
healthData = getHealthData(); | ||
healthData.fileStats = healthData.fileStats || { | ||
openedFileExt : {}, | ||
workingSetFileExt : {} | ||
}; | ||
if (language.getId() !== "unknown") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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... There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,8 @@ | |
define(function (require, exports, module) { | ||
"use strict"; | ||
|
||
var _ = require("thirdparty/lodash"); | ||
var _ = require("thirdparty/lodash"), | ||
StringUtils = require("utils/StringUtils"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"); | ||
|
@@ -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> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo |
||
* @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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typos |
||
* <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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why don't we just use |
||
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]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not your fault, but a typo anyways: |
||
* @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; | ||
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
} 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); | ||
|
@@ -384,4 +433,5 @@ define(function (require, exports, module) { | |
exports.getDelimitedPerfData = getDelimitedPerfData; | ||
exports.createPerfMeasurement = createPerfMeasurement; | ||
exports.clear = clear; | ||
exports.getHealthReport = getHealthReport; | ||
}); |
There was a problem hiding this comment.
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 forhandleFileOpen
, then forhandleFileAddToWorkingSetAndOpen
). Is it meant to be like this?There was a problem hiding this comment.
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.