--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -1506,23 +1506,29 @@ var KeyValueTable = {
let valueField = document.createElement("td");
valueField.appendChild(document.createTextNode(value + "\n"));
newRow.appendChild(valueField);
}
}
};
var GenericTable = {
+
+ defaultHeadings: [
+ bundle.GetStringFromName("keysHeader"),
+ bundle.GetStringFromName("valuesHeader")
+ ],
+
/**
* Returns a n-column table.
* @param rows An array of arrays, each containing data to render
* for one row.
* @param headings The column header strings.
*/
- render(rows, headings) {
+ render(rows, headings = this.defaultHeadings) {
let table = document.createElement("table");
this.renderHeader(table, headings);
this.renderBody(table, rows);
return table;
},
/**
* Create the table header.
@@ -1568,17 +1574,17 @@ var GenericTable = {
for (let i = 0; i < row.length; ++i) {
let suffix = (i == (row.length - 1)) ? "\n" : "\t";
let field = document.createElement("td");
field.appendChild(document.createTextNode(row[i] + suffix));
newRow.appendChild(field);
}
}
- }
+ },
};
var KeyedHistogram = {
render(parent, id, keyedHistogram) {
let outerDiv = document.createElement("div");
outerDiv.className = "keyed-histogram";
outerDiv.id = id;
@@ -1618,17 +1624,17 @@ var AddonDetails = {
let providerSection = document.createElement("h2");
let titleText = bundle.formatStringFromName("addonProvider", [provider], 1);
providerSection.appendChild(document.createTextNode(titleText));
addonSection.appendChild(providerSection);
addonSection.appendChild(
KeyValueTable.render(addonDetails[provider],
this.tableIDTitle, this.tableDetailsTitle));
}
- }
+ },
};
var Scalars = {
/**
* Render the scalar data - if present - from the payload in a simple key-value table.
* @param aPayload A payload object to render the data from.
*/
render(aPayload) {
@@ -1650,17 +1656,17 @@ var Scalars = {
if (!hasData) {
return;
}
const headingName = bundle.GetStringFromName("namesHeader");
const headingValue = bundle.GetStringFromName("valuesHeader");
const table = KeyValueTable.render(scalars, headingName, headingValue);
scalarsSection.appendChild(table);
- }
+ },
};
var KeyedScalars = {
/**
* Render the keyed scalar data - if present - from the payload in a simple key-value table.
* @param aPayload A payload object to render the data from.
*/
render(aPayload) {
@@ -1689,17 +1695,17 @@ var KeyedScalars = {
// Add the name of the scalar.
let scalarNameSection = document.createElement("h2");
scalarNameSection.appendChild(document.createTextNode(scalar));
scalarsSection.appendChild(scalarNameSection);
// Populate the section with the key-value pairs from the scalar.
const table = KeyValueTable.render(keyedScalars[scalar], headingName, headingValue);
scalarsSection.appendChild(table);
}
- }
+ },
};
var Events = {
/**
* Render the event data - if present - from the payload in a simple table.
* @param aPayload A payload object to render the data from.
*/
render(aPayload) {
@@ -1732,17 +1738,17 @@ var Events = {
"methodHeader",
"objectHeader",
"valuesHeader",
"extraHeader",
].map(h => bundle.GetStringFromName(h));
const table = GenericTable.render(events, headings);
eventsSection.appendChild(table);
- }
+ },
};
/**
* Helper function for showing either the toggle element or "No data collected" message for a section
*
* @param aSectionID ID of the section element that needs to be changed
* @param aHasData true (default) indicates that toggle should be displayed
*/
@@ -1912,62 +1918,186 @@ var LateWritesSingleton = {
if (!lateWrites) {
return;
}
let stacks = lateWrites.stacks;
let memoryMap = lateWrites.memoryMap;
StackRenderer.renderStacks("late-writes", stacks, memoryMap,
LateWritesSingleton.renderHeader);
- }
+ },
};
-/**
- * Helper function for sorting the startup milestones in the Simple Measurements
- * section into temporal order.
- *
- * @param aSimpleMeasurements Telemetry ping's "Simple Measurements" data
- * @return Sorted measurements
- */
-function sortStartupMilestones(aSimpleMeasurements) {
- const telemetryTimestamps = TelemetryTimestamps.get();
- let startupEvents = Services.startup.getStartupInfo();
- delete startupEvents["process"];
+var HistogramSection = {
+ render(aPayload) {
+ let hgramDiv = document.getElementById("histograms");
+ removeAllChildNodes(hgramDiv);
+
+ let histograms = aPayload.histograms;
+
+ let hgramsSelect = document.getElementById("histograms-processes");
+ let hgramsOption = hgramsSelect.selectedOptions.item(0);
+ let hgramsProcess = hgramsOption.getAttribute("value");
+ // "parent" histograms/keyedHistograms aren't under "parent". Fix that up.
+ if (hgramsProcess === "parent") {
+ hgramsProcess = "";
+ }
+ if (hgramsProcess &&
+ "processes" in aPayload &&
+ hgramsProcess in aPayload.processes) {
+ histograms = aPayload.processes[hgramsProcess].histograms;
+ }
+
+ let hasData = Object.keys(histograms).length > 0;
+ setHasData("histograms-section", hasData || hgramsSelect.options.length);
+
+ if (hasData) {
+ for (let [name, hgram] of Object.entries(histograms)) {
+ Histogram.render(hgramDiv, name, hgram, {unpacked: true});
+ }
+
+ let filterBox = document.getElementById("histograms-filter");
+ filterBox.addEventListener("input", Histogram.histogramFilterChanged);
+ if (filterBox.value.trim() != "") { // on load, no need to filter if empty
+ Histogram.filterHistograms(hgramDiv, filterBox.value);
+ }
+
+ setHasData("histograms-section", true);
+ }
+ },
+}
- function keyIsMilestone(k) {
- return (k in startupEvents) || (k in telemetryTimestamps);
- }
+var KeyedHistogramSection = {
+ render(aPayload) {
+ let keyedDiv = document.getElementById("keyed-histograms");
+ removeAllChildNodes(keyedDiv);
+
+ let keyedHistograms = aPayload.keyedHistograms;
- let sortedKeys = Object.keys(aSimpleMeasurements);
+ let keyedHgramsSelect = document.getElementById("keyed-histograms-processes");
+ let keyedHgramsOption = keyedHgramsSelect.selectedOptions.item(0);
+ let keyedHgramsProcess = keyedHgramsOption.getAttribute("value");
+ // "parent" histograms/keyedHistograms aren't under "parent". Fix that up.
+ if (keyedHgramsProcess === "parent") {
+ keyedHgramsProcess = "";
+ }
+ if (keyedHgramsProcess &&
+ "processes" in aPayload &&
+ keyedHgramsProcess in aPayload.processes) {
+ keyedHistograms = aPayload.processes[keyedHgramsProcess].keyedHistograms;
+ }
+
+ setHasData("keyed-histograms-section", keyedHgramsSelect.options.length);
+ if (keyedHistograms) {
+ let hasData = false;
+ for (let [id, keyed] of Object.entries(keyedHistograms)) {
+ if (Object.keys(keyed).length > 0) {
+ hasData = true;
+ KeyedHistogram.render(keyedDiv, id, keyed, {unpacked: true});
+ }
+ }
+ setHasData("keyed-histograms-section", hasData || keyedHgramsSelect.options.length);
+ }
+ },
+}
+
+var AddonHistogramSection = {
+ render(aPayload) {
+ let addonDiv = document.getElementById("addon-histograms");
+ removeAllChildNodes(addonDiv);
- // Sort the measurements, with startup milestones at the front + ordered by time
- sortedKeys.sort(function keyCompare(keyA, keyB) {
- let isKeyAMilestone = keyIsMilestone(keyA);
- let isKeyBMilestone = keyIsMilestone(keyB);
+ let addonHistogramsRendered = false;
+ let addonData = aPayload.addonHistograms;
+ if (addonData) {
+ for (let [addon, histograms] of Object.entries(addonData)) {
+ for (let [name, hgram] of Object.entries(histograms)) {
+ addonHistogramsRendered = true;
+ Histogram.render(addonDiv, addon + ": " + name, hgram, {unpacked: true});
+ }
+ }
+ }
+
+ setHasData("addon-histograms-section", addonHistogramsRendered);
+ },
+}
+
+var SessionInformation = {
+ render(aPayload) {
+ let infoSection = document.getElementById("session-info");
+ removeAllChildNodes(infoSection);
+
+ let hasData = Object.keys(aPayload.info).length > 0;
+ setHasData("session-info-section", hasData);
+
+ if (hasData) {
+ const table = GenericTable.render(explodeObject(aPayload.info));
+ infoSection.appendChild(table);
+ }
+ },
+}
+
+var SimpleMeasurements = {
+ render(aPayload) {
+ let simpleSection = document.getElementById("simple-measurements");
+ removeAllChildNodes(simpleSection);
+
+ let simpleMeasurements = this.sortStartupMilestones(aPayload.simpleMeasurements);
+ let hasData = Object.keys(simpleMeasurements).length > 0;
+ setHasData("simple-measurements-section", hasData);
+
+ if (hasData) {
+ const table = GenericTable.render(explodeObject(simpleMeasurements));
+ simpleSection.appendChild(table);
+ }
+ },
- // First order by startup vs non-startup measurement
- if (isKeyAMilestone && !isKeyBMilestone)
- return -1;
- if (!isKeyAMilestone && isKeyBMilestone)
- return 1;
- // Don't change order of non-startup measurements
- if (!isKeyAMilestone && !isKeyBMilestone)
- return 0;
+ /**
+ * Helper function for sorting the startup milestones in the Simple Measurements
+ * section into temporal order.
+ *
+ * @param aSimpleMeasurements Telemetry ping's "Simple Measurements" data
+ * @return Sorted measurements
+ */
+ sortStartupMilestones(aSimpleMeasurements) {
+ const telemetryTimestamps = TelemetryTimestamps.get();
+ let startupEvents = Services.startup.getStartupInfo();
+ delete startupEvents["process"];
+
+ function keyIsMilestone(k) {
+ return (k in startupEvents) || (k in telemetryTimestamps);
+ }
+
+ let sortedKeys = Object.keys(aSimpleMeasurements);
- // If both keys are startup measurements, order them by value
- return aSimpleMeasurements[keyA] - aSimpleMeasurements[keyB];
- });
+ // Sort the measurements, with startup milestones at the front + ordered by time
+ sortedKeys.sort(function keyCompare(keyA, keyB) {
+ let isKeyAMilestone = keyIsMilestone(keyA);
+ let isKeyBMilestone = keyIsMilestone(keyB);
- // Insert measurements into a result object in sort-order
- let result = {};
- for (let key of sortedKeys) {
- result[key] = aSimpleMeasurements[key];
- }
+ // First order by startup vs non-startup measurement
+ if (isKeyAMilestone && !isKeyBMilestone)
+ return -1;
+ if (!isKeyAMilestone && isKeyBMilestone)
+ return 1;
+ // Don't change order of non-startup measurements
+ if (!isKeyAMilestone && !isKeyBMilestone)
+ return 0;
- return result;
+ // If both keys are startup measurements, order them by value
+ return aSimpleMeasurements[keyA] - aSimpleMeasurements[keyB];
+ });
+
+ // Insert measurements into a result object in sort-order
+ let result = {};
+ for (let key of sortedKeys) {
+ result[key] = aSimpleMeasurements[key];
+ }
+
+ return result;
+ },
}
function renderProcessList(ping, selectEl) {
removeAllChildNodes(selectEl);
let option = document.createElement("option");
option.appendChild(document.createTextNode("parent"));
option.setAttribute("value", "parent");
option.selected = true;
@@ -2059,20 +2189,16 @@ function displayPingData(ping, updatePay
try {
displayRichPingData(ping, updatePayloadList);
} catch (err) {
PingPicker._showRawPingData();
}
}
function displayRichPingData(ping, updatePayloadList) {
- // Update the structured data rendering.
- const keysHeader = bundle.GetStringFromName("keysHeader");
- const valuesHeader = bundle.GetStringFromName("valuesHeader");
-
// Update the payload list and process lists
if (updatePayloadList) {
renderPayloadList(ping);
renderProcessList(ping, document.getElementById("scalars-processes"));
renderProcessList(ping, document.getElementById("keyed-scalars-processes"));
renderProcessList(ping, document.getElementById("histograms-processes"));
renderProcessList(ping, document.getElementById("keyed-histograms-processes"));
renderProcessList(ping, document.getElementById("events-processes"));
@@ -2118,125 +2244,33 @@ function displayRichPingData(ping, updat
// Show thread hang stats
ThreadHangStats.render(payload);
// Show captured stacks.
CapturedStacks.render(payload);
// Show simple measurements
- let simpleMeasurements = sortStartupMilestones(payload.simpleMeasurements);
- let hasData = Object.keys(simpleMeasurements).length > 0;
- setHasData("simple-measurements-section", hasData);
- let simpleSection = document.getElementById("simple-measurements");
- removeAllChildNodes(simpleSection);
-
- if (hasData) {
- simpleSection.appendChild(KeyValueTable.render(simpleMeasurements,
- keysHeader, valuesHeader));
- }
+ SimpleMeasurements.render(payload);
LateWritesSingleton.renderLateWrites(payload.lateWrites);
// Show basic session info gathered
- hasData = Object.keys(ping.payload.info).length > 0;
- setHasData("session-info-section", hasData);
- let infoSection = document.getElementById("session-info");
- removeAllChildNodes(infoSection);
-
- if (hasData) {
- infoSection.appendChild(KeyValueTable.render(ping.payload.info,
- keysHeader, valuesHeader));
- }
+ SessionInformation.render(payload);
// Show scalar data.
Scalars.render(payload);
KeyedScalars.render(payload);
// Show histogram data
- let hgramDiv = document.getElementById("histograms");
- removeAllChildNodes(hgramDiv);
-
- let histograms = payload.histograms;
-
- let hgramsSelect = document.getElementById("histograms-processes");
- let hgramsOption = hgramsSelect.selectedOptions.item(0);
- let hgramsProcess = hgramsOption.getAttribute("value");
- // "parent" histograms/keyedHistograms aren't under "parent". Fix that up.
- if (hgramsProcess === "parent") {
- hgramsProcess = "";
- }
- if (hgramsProcess &&
- "processes" in ping.payload &&
- hgramsProcess in ping.payload.processes) {
- histograms = ping.payload.processes[hgramsProcess].histograms;
- }
-
- hasData = Object.keys(histograms).length > 0;
- setHasData("histograms-section", hasData || hgramsSelect.options.length);
-
- if (hasData) {
- for (let [name, hgram] of Object.entries(histograms)) {
- Histogram.render(hgramDiv, name, hgram, {unpacked: true});
- }
-
- let filterBox = document.getElementById("histograms-filter");
- filterBox.addEventListener("input", Histogram.histogramFilterChanged);
- if (filterBox.value.trim() != "") { // on load, no need to filter if empty
- Histogram.filterHistograms(hgramDiv, filterBox.value);
- }
-
- setHasData("histograms-section", true);
- }
+ HistogramSection.render(payload);
// Show keyed histogram data
- let keyedDiv = document.getElementById("keyed-histograms");
- removeAllChildNodes(keyedDiv);
-
- let keyedHistograms = payload.keyedHistograms;
-
- let keyedHgramsSelect = document.getElementById("keyed-histograms-processes");
- let keyedHgramsOption = keyedHgramsSelect.selectedOptions.item(0);
- let keyedHgramsProcess = keyedHgramsOption.getAttribute("value");
- // "parent" histograms/keyedHistograms aren't under "parent". Fix that up.
- if (keyedHgramsProcess === "parent") {
- keyedHgramsProcess = "";
- }
- if (keyedHgramsProcess &&
- "processes" in ping.payload &&
- keyedHgramsProcess in ping.payload.processes) {
- keyedHistograms = ping.payload.processes[keyedHgramsProcess].keyedHistograms;
- }
-
- setHasData("keyed-histograms-section", keyedHgramsSelect.options.length);
- if (keyedHistograms) {
- let hasData = false;
- for (let [id, keyed] of Object.entries(keyedHistograms)) {
- if (Object.keys(keyed).length > 0) {
- hasData = true;
- KeyedHistogram.render(keyedDiv, id, keyed, {unpacked: true});
- }
- }
- setHasData("keyed-histograms-section", hasData || keyedHgramsSelect.options.length);
- }
+ KeyedHistogramSection.render(payload);
// Show event data.
Events.render(payload);
// Show addon histogram data
- let addonDiv = document.getElementById("addon-histograms");
- removeAllChildNodes(addonDiv);
-
- let addonHistogramsRendered = false;
- let addonData = payload.addonHistograms;
- if (addonData) {
- for (let [addon, histograms] of Object.entries(addonData)) {
- for (let [name, hgram] of Object.entries(histograms)) {
- addonHistogramsRendered = true;
- Histogram.render(addonDiv, addon + ": " + name, hgram, {unpacked: true});
- }
- }
- }
-
- setHasData("addon-histograms-section", addonHistogramsRendered);
+ AddonHistogramSection.render(payload);
}
window.addEventListener("load", onLoad);