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

Commit 389d9e6

Browse files
committed
Merge pull request #11311 from adobe/abose/HealthLogs1.4
Health Data Logs for 1.4
2 parents d1a5c5c + 90f9a38 commit 389d9e6

6 files changed

Lines changed: 264 additions & 19 deletions

File tree

src/document/DocumentCommandHandlers.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ define(function (require, exports, module) {
4444
InMemoryFile = require("document/InMemoryFile"),
4545
StringUtils = require("utils/StringUtils"),
4646
Async = require("utils/Async"),
47+
HealthLogger = require("utils/HealthLogger"),
4748
Dialogs = require("widgets/Dialogs"),
4849
DefaultDialogs = require("widgets/DefaultDialogs"),
4950
Strings = require("strings"),
@@ -451,6 +452,7 @@ define(function (require, exports, module) {
451452

452453
_doOpenWithOptionalPath(fileInfo.path, silent, paneId, commandData && commandData.options)
453454
.done(function (file) {
455+
HealthLogger.fileOpened(fileInfo.path);
454456
if (!commandData || !commandData.options || !commandData.options.noPaneActivate) {
455457
MainViewManager.setActivePaneId(paneId);
456458
}
@@ -528,6 +530,7 @@ define(function (require, exports, module) {
528530
return handleFileOpen(commandData).done(function (file) {
529531
var paneId = (commandData && commandData.paneId) || MainViewManager.ACTIVE_PANE;
530532
MainViewManager.addToWorkingSet(paneId, file, commandData.index, commandData.forceRedraw);
533+
HealthLogger.fileOpened(file.fullPath, true);
531534
});
532535
}
533536

src/extensions/default/HealthData/HealthDataManager.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ define(function (require, exports, module) {
2828
"use strict";
2929

3030
var AppInit = brackets.getModule("utils/AppInit"),
31+
HealthLogger = brackets.getModule("utils/HealthLogger"),
3132
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
3233
UrlParams = brackets.getModule("utils/UrlParams").UrlParams,
3334
Strings = brackets.getModule("strings"),
@@ -69,6 +70,7 @@ define(function (require, exports, module) {
6970
oneTimeHealthData.osLanguage = brackets.app.language;
7071
oneTimeHealthData.bracketsLanguage = brackets.getLocale();
7172
oneTimeHealthData.bracketsVersion = brackets.metadata.version;
73+
$.extend(oneTimeHealthData, HealthLogger.getAggregatedHealthData());
7274

7375
HealthDataUtils.getUserInstalledExtensions()
7476
.done(function (userInstalledExtensions) {
@@ -123,7 +125,7 @@ define(function (require, exports, module) {
123125
function checkHealthDataSend() {
124126
var result = new $.Deferred(),
125127
isHDTracking = prefs.get("healthDataTracking");
126-
128+
HealthLogger.setHealthLogsEnabled(isHDTracking);
127129
window.clearTimeout(timeoutVar);
128130
if (isHDTracking) {
129131
var nextTimeToSend = PreferencesManager.getViewState("nextHealthDataSendTime"),
@@ -144,6 +146,9 @@ define(function (require, exports, module) {
144146

145147
sendHealthDataToServer()
146148
.done(function () {
149+
// We have already sent the health data, so can clear all health data
150+
// Logged till now
151+
HealthLogger.clearHealthData();
147152
result.resolve();
148153
})
149154
.fail(function () {
@@ -182,4 +187,4 @@ define(function (require, exports, module) {
182187

183188
exports.getHealthData = getHealthData;
184189
exports.checkHealthDataSend = checkHealthDataSend;
185-
});
190+
});

src/extensions/default/HealthData/main.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ define(function (require, exports, module) {
2828
"use strict";
2929

3030
var AppInit = brackets.getModule("utils/AppInit"),
31+
HealthLogger = brackets.getModule("utils/HealthLogger"),
3132
Menus = brackets.getModule("command/Menus"),
3233
CommandManager = brackets.getModule("command/CommandManager"),
3334
Strings = brackets.getModule("strings"),
3435
Commands = brackets.getModule("command/Commands"),
36+
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
3537

3638
HealthDataNotification = require("HealthDataNotification"), // self-initializes to show first-launch notification
3739
HealthDataManager = require("HealthDataManager"), // self-initializes timer to send data
@@ -58,10 +60,14 @@ define(function (require, exports, module) {
5860
brackets.test.HealthDataManager = HealthDataManager;
5961
brackets.test.HealthDataNotification = HealthDataNotification;
6062
brackets.test.HealthDataPopup = HealthDataPopup;
63+
64+
var prefs = PreferencesManager.getExtensionPrefs("healthData");
65+
HealthLogger.setHealthLogsEnabled(prefs.get("healthDataTracking"));
6166
}
6267

6368
AppInit.appReady(function () {
6469
initTest();
70+
HealthLogger.init();
6571
});
6672

6773
addCommand();

src/utils/HealthLogger.js

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a
5+
* copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the
9+
* Software is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+
* DEALINGS IN THE SOFTWARE.
21+
*
22+
*/
23+
24+
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
25+
/*global define, $*/
26+
27+
/**
28+
* Utilities functions related to Health Data logging
29+
*/
30+
define(function (require, exports, module) {
31+
"use strict";
32+
33+
var PreferencesManager = require("preferences/PreferencesManager"),
34+
LanguageManager = require("language/LanguageManager"),
35+
FileUtils = require("file/FileUtils"),
36+
PerfUtils = require("utils/PerfUtils"),
37+
38+
HEALTH_DATA_STATE_KEY = "HealthData.Logs",
39+
logHealthData = true;
40+
41+
/**
42+
* Init: creates the health log preference keys in the state.json file
43+
*/
44+
function init() {
45+
PreferencesManager.stateManager.definePreference(HEALTH_DATA_STATE_KEY, "object", {});
46+
}
47+
48+
/**
49+
* All the logging functions should be disabled if this returns false
50+
* @returns {boolean} true if health data can be logged
51+
*/
52+
function shouldLogHealthData() {
53+
return logHealthData;
54+
}
55+
56+
/**
57+
* Return the Performance related data
58+
* @returns {Object} Performance Data aggregated till now
59+
*/
60+
function getPerformanceData() {
61+
return PerfUtils.getHealthReport();
62+
}
63+
64+
/**
65+
* Return all health data logged till now stored in the state prefs
66+
* @returns {Object} Health Data aggregated till now
67+
*/
68+
function getStoredHealthData() {
69+
return PreferencesManager.getViewState(HEALTH_DATA_STATE_KEY);
70+
}
71+
72+
/**
73+
* Return the aggregate of all health data logged till now from all sources
74+
* @returns {Object} Health Data aggregated till now
75+
*/
76+
function getAggregatedHealthData() {
77+
var healthData = getStoredHealthData();
78+
$.extend(healthData, getPerformanceData());
79+
return healthData;
80+
}
81+
82+
/**
83+
* Sets the health data
84+
* @param {Object} dataObject The object to be stored as health data
85+
*/
86+
function setHealthData(dataObject) {
87+
if (!shouldLogHealthData()) {
88+
return;
89+
}
90+
PreferencesManager.setViewState(HEALTH_DATA_STATE_KEY, dataObject);
91+
}
92+
93+
/**
94+
* Returns health data logged for the given key
95+
* @returns {Object} Health Data object for the key or undefined if no health data stored
96+
*/
97+
function getHealthDataLog(key) {
98+
var healthData = getStoredHealthData();
99+
return healthData[key];
100+
}
101+
102+
/**
103+
* Sets the health data for the given key
104+
* @param {Object} dataObject The object to be stored as health data for the key
105+
*/
106+
function setHealthDataLog(key, dataObject) {
107+
var healthData = getStoredHealthData();
108+
healthData[key] = dataObject;
109+
setHealthData(healthData);
110+
}
111+
112+
/**
113+
* Clears all the health data recorded till now
114+
*/
115+
function clearHealthData() {
116+
PreferencesManager.setViewState(HEALTH_DATA_STATE_KEY, {});
117+
//clear the performance related health data also
118+
PerfUtils.clear();
119+
}
120+
121+
/**
122+
* Enable or disable health data logs
123+
* @param {boolean} enabled true to enable health logs
124+
*/
125+
function setHealthLogsEnabled(enabled) {
126+
logHealthData = enabled;
127+
if (!enabled) {
128+
clearHealthData();
129+
}
130+
}
131+
132+
/**
133+
* Whenever a file is opened call this function. The function will record the number of times
134+
* the standard file types have been opened. We only log the standard filetypes
135+
* @param {String} filePath The path of the file to be registered
136+
* @param {boolean} addedToWorkingSet set to true if extensions of files added to the
137+
* working set needs to be logged
138+
*/
139+
function fileOpened(filePath, addedToWorkingSet) {
140+
if (!shouldLogHealthData()) {
141+
return;
142+
}
143+
var fileExtension = FileUtils.getFileExtension(filePath),
144+
language = LanguageManager.getLanguageForPath(filePath),
145+
healthData = getStoredHealthData(),
146+
fileExtCountMap = [];
147+
healthData.fileStats = healthData.fileStats || {
148+
openedFileExt : {},
149+
workingSetFileExt : {}
150+
};
151+
if (language.getId() !== "unknown") {
152+
fileExtCountMap = addedToWorkingSet ? healthData.fileStats.workingSetFileExt : healthData.fileStats.openedFileExt;
153+
if (!fileExtCountMap[fileExtension]) {
154+
fileExtCountMap[fileExtension] = 0;
155+
}
156+
fileExtCountMap[fileExtension]++;
157+
setHealthData(healthData);
158+
}
159+
}
160+
161+
// Define public API
162+
exports.getHealthDataLog = getHealthDataLog;
163+
exports.setHealthDataLog = setHealthDataLog;
164+
exports.getAggregatedHealthData = getAggregatedHealthData;
165+
exports.clearHealthData = clearHealthData;
166+
exports.fileOpened = fileOpened;
167+
exports.setHealthLogsEnabled = setHealthLogsEnabled;
168+
exports.shouldLogHealthData = shouldLogHealthData;
169+
exports.init = init;
170+
});

src/utils/PerfUtils.js

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
define(function (require, exports, module) {
3131
"use strict";
3232

33-
var _ = require("thirdparty/lodash");
33+
var _ = require("thirdparty/lodash"),
34+
StringUtils = require("utils/StringUtils");
3435

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

305306
/**
306-
* Returns the performance data as a tab deliminted string
307-
* @return {string}
307+
* return single value, or comma separated values for an array or return aggregated values with
308+
* <min value, average, max value, standard deviation>
309+
* @param {Array} entry An array or a single value
310+
* @param {Boolean} aggregateStats If set, the returned value will be aggregated in the form -
311+
* <min(avg)max[standard deviation]>
312+
* @returns {String} a single value, or comma separated values in an array or
313+
* <min(avg)max[standard deviation]> if aggregateStats is set
308314
*/
309-
function getDelimitedPerfData() {
310-
var getValue = function (entry) {
311-
// return single value, or tab deliminted values for an array
312-
if (Array.isArray(entry)) {
313-
var i, values = "";
314-
315+
var getValueAsString = function (entry, aggregateStats) {
316+
if (Array.isArray(entry)) {
317+
var i, values = "", min = entry[0], max = entry[0], avg = 0, sum = 0, sd = 0;
318+
319+
for (i = 0; i < entry.length; i++) {
320+
sum = sum + entry[i];
321+
values += entry[i];
322+
if (i < entry.length - 1) {
323+
values += ", ";
324+
}
325+
}
326+
if (aggregateStats) {
327+
avg = Math.round(sum / entry.length);
328+
sum = 0;
315329
for (i = 0; i < entry.length; i++) {
316-
values += entry[i];
317-
if (i < entry.length - 1) {
318-
values += ", ";
330+
sum = sum + Math.pow((entry[i] - avg), 2);
331+
if (entry[i] < min) {
332+
min = entry[i];
333+
} else if (entry[i] > max) {
334+
max = entry[i];
319335
}
320336
}
321-
return values;
322-
} else {
323-
return entry;
337+
sd = Math.round(Math.sqrt(sum / entry.length));
338+
return min + "(" + avg + ")" + max + "[" + sd + "]";
324339
}
325-
};
340+
return values;
341+
} else {
342+
return entry;
343+
}
344+
};
326345

346+
/**
347+
* Returns the performance data as a tab delimited string
348+
* @return {string}
349+
*/
350+
function getDelimitedPerfData() {
327351
var result = "";
328352
_.forEach(perfData, function (entry, testName) {
329-
result += getValue(entry) + "\t" + testName + "\n";
353+
result += getValueAsString(entry) + "\t" + testName + "\n";
330354
});
331355

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

371+
/**
372+
* Returns the Performance metrics to be logged for health report
373+
* @returns {Object} An object with the helath data logs to be send
374+
*/
375+
function getHealthReport() {
376+
var healthReport = {
377+
projectLoadTimes : "",
378+
fileOpenTimes : ""
379+
};
380+
381+
_.forEach(perfData, function (entry, testName) {
382+
if (StringUtils.startsWith(testName, "Application Startup")) {
383+
healthReport.AppStartupTime = getValueAsString(entry);
384+
} else if (StringUtils.startsWith(testName, "brackets module dependencies resolved")) {
385+
healthReport.ModuleDepsResolved = getValueAsString(entry);
386+
} else if (StringUtils.startsWith(testName, "Load Project")) {
387+
healthReport.projectLoadTimes += ":" + getValueAsString(entry, true);
388+
} else if (StringUtils.startsWith(testName, "Open File")) {
389+
healthReport.fileOpenTimes += ":" + getValueAsString(entry, true);
390+
}
391+
});
392+
393+
return healthReport;
394+
}
395+
347396
function searchData(regExp) {
348397
var keys = Object.keys(perfData).filter(function (key) {
349398
return regExp.test(key);
@@ -384,4 +433,5 @@ define(function (require, exports, module) {
384433
exports.getDelimitedPerfData = getDelimitedPerfData;
385434
exports.createPerfMeasurement = createPerfMeasurement;
386435
exports.clear = clear;
436+
exports.getHealthReport = getHealthReport;
387437
});

0 commit comments

Comments
 (0)