зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1797284 - Teach about:logging to start the Firefox Profiler, with the appropriate profiler preset for a particular logging preset. r=julienw,mossop,flod
This has some provision to continue working if the tab is closed or reloaded, but it's not fool proof. Eventually we might want to move this to a service, but it's already very useful as it is. Differential Revision: https://phabricator.services.mozilla.com/D160213
This commit is contained in:
Родитель
672e753099
Коммит
ec1a47fdf5
|
@ -110,6 +110,7 @@ export type RecordingState =
|
|||
export type PageContext =
|
||||
| "devtools"
|
||||
| "devtools-remote"
|
||||
| "aboutlogging"
|
||||
| "aboutprofiling"
|
||||
| "aboutprofiling-remote";
|
||||
|
||||
|
|
|
@ -452,6 +452,7 @@ function getPrefPostfix(pageContext) {
|
|||
switch (pageContext) {
|
||||
case "devtools":
|
||||
case "aboutprofiling":
|
||||
case "aboutlogging":
|
||||
// Don't use any postfix on the prefs.
|
||||
return "";
|
||||
case "devtools-remote":
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
<div id="logging">
|
||||
<h1 id="title" data-l10n-id="about-logging-page-title"></h1>
|
||||
<div class=page-section>
|
||||
<button id="start-logging-button" data-l10n-id="about-logging-start-logging"></button>
|
||||
<button id="stop-logging-button" data-l10n-id="about-logging-stop-logging"></button>
|
||||
<button id="toggle-logging-button" data-l10n-id="about-logging-start-logging"></button>
|
||||
</div>
|
||||
<div id=log-module-selection class=page-section>
|
||||
<h2 data-l10n-id="about-logging-log-modules-selection"></h2>
|
||||
|
@ -44,7 +43,19 @@
|
|||
<div>
|
||||
<span hidden id="buttons-disabled" data-l10n-id="about-logging-buttons-disabled"></span>
|
||||
</div>
|
||||
<h2 data-l10n-id="about-logging-logging-output-selection"></h2>
|
||||
<div id=logging-output-profiler>
|
||||
<input type="radio" id="radio-logging-profiler" name="logging-output" value="profiler" checked>
|
||||
<label for="profiler" data-l10n-id="about-logging-logging-to-profiler"></label>
|
||||
</div>
|
||||
<div id=logging-output-file>
|
||||
<input type="radio" id="radio-logging-file" name="logging-output" value="file">
|
||||
<label for="file" data-l10n-id="about-logging-logging-to-file"></label>
|
||||
<div>
|
||||
<span hidden id="buttons-disabled" data-l10n-id="about-logging-buttons-disabled"></span>
|
||||
</div>
|
||||
<div>
|
||||
<div id="log-file-configuration">
|
||||
<div>
|
||||
<label for="current-log-file" data-l10n-id="about-logging-current-log-file"></label>
|
||||
<span id="current-log-file"></span>
|
||||
|
@ -56,13 +67,13 @@
|
|||
<button id="set-log-file-button" data-l10n-id="about-logging-set-log-file"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
<p id="log-tutorial" data-l10n-id="about-logging-log-tutorial">
|
||||
<a data-l10n-name="logging" href="https://firefox-source-docs.mozilla.org/networking/http/logging.html"></a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
const { XPCOMUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/XPCOMUtils.sys.mjs"
|
||||
);
|
||||
const gDashboard = Cc["@mozilla.org/network/dashboard;1"].getService(
|
||||
Ci.nsIDashboard
|
||||
);
|
||||
|
@ -10,8 +13,36 @@ const gDirServ = Cc["@mozilla.org/file/directory_service;1"].getService(
|
|||
Ci.nsIDirectoryServiceProvider
|
||||
);
|
||||
|
||||
const $ = document.querySelector.bind(document);
|
||||
const { ProfilerMenuButton } = ChromeUtils.import(
|
||||
"resource://devtools/client/performance-new/popup/menu-button.jsm.js"
|
||||
);
|
||||
const { CustomizableUI } = ChromeUtils.import(
|
||||
"resource:///modules/CustomizableUI.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "ProfilerPopupBackground", function() {
|
||||
return ChromeUtils.import(
|
||||
"resource://devtools/client/performance-new/popup/background.jsm.js"
|
||||
);
|
||||
});
|
||||
|
||||
const $ = document.querySelector.bind(document);
|
||||
const $$ = document.querySelectorAll.bind(document);
|
||||
|
||||
/**
|
||||
* All the information associated with a logging presets:
|
||||
* - `modules` is the list of log modules and option, the same that would have
|
||||
* been set as a MOZ_LOG environment variable
|
||||
* - l10nIds.label and l10nIds.description are the Ids of the strings that
|
||||
* appear in the dropdown selector, and a one-liner describing the purpose of
|
||||
* a particular logging preset
|
||||
* - profilerPreset is the name of a Firefox Profiler preset [1]. In general,
|
||||
* the profiler preset will have the correct set of threads for a particular
|
||||
* logging preset, so that all logging statements are recorded in the profile
|
||||
* as markers.
|
||||
*
|
||||
* [1]: The keys of https://searchfox.org/mozilla-central/rev/88f285c5163f73abd209d4f73cfa476660351982/devtools/client/performance-new/popup/background.jsm.js#119
|
||||
*/
|
||||
const gLoggingPresets = {
|
||||
networking: {
|
||||
modules:
|
||||
|
@ -20,6 +51,7 @@ const gLoggingPresets = {
|
|||
label: "about-logging-preset-networking-label",
|
||||
description: "about-logging-preset-networking-description",
|
||||
},
|
||||
profilerPreset: "networking",
|
||||
},
|
||||
"media-playback": {
|
||||
modules:
|
||||
|
@ -28,6 +60,7 @@ const gLoggingPresets = {
|
|||
label: "about-logging-preset-media-playback-label",
|
||||
description: "about-logging-preset-media-playback-description",
|
||||
},
|
||||
profilerPreset: "media",
|
||||
},
|
||||
custom: {
|
||||
modules: "",
|
||||
|
@ -38,6 +71,12 @@ const gLoggingPresets = {
|
|||
},
|
||||
};
|
||||
|
||||
const gLoggingSettings = {
|
||||
loggingOutputType: "profiler",
|
||||
running: false,
|
||||
loggingPreset: "",
|
||||
};
|
||||
|
||||
function populatePresets() {
|
||||
let dropdown = $("#logging-preset-dropdown");
|
||||
for (let presetName in gLoggingPresets) {
|
||||
|
@ -46,6 +85,9 @@ function populatePresets() {
|
|||
document.l10n.setAttributes(option, preset.l10nIds.label);
|
||||
option.value = presetName;
|
||||
dropdown.appendChild(option);
|
||||
if (option.value === gLoggingSettings.loggingPreset) {
|
||||
option.setAttribute("selected", true);
|
||||
}
|
||||
}
|
||||
|
||||
function setPresetAndDescription(preset) {
|
||||
|
@ -53,22 +95,44 @@ function populatePresets() {
|
|||
$("#logging-preset-description"),
|
||||
gLoggingPresets[preset].l10nIds.description
|
||||
);
|
||||
gLoggingSettings.loggingPreset = preset;
|
||||
}
|
||||
|
||||
dropdown.onchange = function() {
|
||||
// When switching to custom, leave the existing module list, to allow
|
||||
// editing.
|
||||
if (dropdown.value != "custom") {
|
||||
$("#log-modules").value = gLoggingPresets[dropdown.value].modules;
|
||||
}
|
||||
setPresetAndDescription(dropdown.value);
|
||||
Services.prefs.setCharPref("logging.config.preset", dropdown.value);
|
||||
setLogModules();
|
||||
Services.prefs.setCharPref("logging.config.preset", dropdown.value);
|
||||
};
|
||||
|
||||
$("#log-modules").value = gLoggingPresets[dropdown.value].modules;
|
||||
setPresetAndDescription(dropdown.value);
|
||||
// When changing the list switch to custom.
|
||||
$("#log-modules").oninput = e => {
|
||||
dropdown.value = "custom";
|
||||
};
|
||||
}
|
||||
|
||||
function updateLoggingOutputType(profilerOutputType) {
|
||||
gLoggingSettings.loggingOutputType = profilerOutputType;
|
||||
|
||||
if (gLoggingSettings.loggingOutputType === "profiler") {
|
||||
// hide options related to file output for clarity
|
||||
$("#log-file-configuration").hidden = true;
|
||||
} else if (gLoggingSettings.loggingOutputType === "file") {
|
||||
$("#log-file-configuration").hidden = false;
|
||||
}
|
||||
|
||||
Services.prefs.setCharPref(
|
||||
"logging.config.output_type",
|
||||
gLoggingSettings.loggingOutputType
|
||||
);
|
||||
}
|
||||
|
||||
let gInited = false;
|
||||
function init() {
|
||||
if (gInited) {
|
||||
|
@ -77,28 +141,56 @@ function init() {
|
|||
gInited = true;
|
||||
gDashboard.enableLogging = true;
|
||||
|
||||
let setLogButton = document.getElementById("set-log-file-button");
|
||||
populatePresets();
|
||||
|
||||
let setLogButton = $("#set-log-file-button");
|
||||
setLogButton.addEventListener("click", setLogFile);
|
||||
|
||||
let setModulesButton = document.getElementById("set-log-modules-button");
|
||||
let setModulesButton = $("#set-log-modules-button");
|
||||
setModulesButton.addEventListener("click", setLogModules);
|
||||
|
||||
let startLoggingButton = document.getElementById("start-logging-button");
|
||||
startLoggingButton.addEventListener("click", startLogging);
|
||||
let toggleLoggingButton = $("#toggle-logging-button");
|
||||
toggleLoggingButton.addEventListener("click", startStopLogging);
|
||||
|
||||
let stopLoggingButton = document.getElementById("stop-logging-button");
|
||||
stopLoggingButton.addEventListener("click", stopLogging);
|
||||
$$("input[type=radio]").forEach(radio => {
|
||||
radio.onchange = e => {
|
||||
updateLoggingOutputType(e.target.value);
|
||||
};
|
||||
});
|
||||
|
||||
try {
|
||||
let loggingOutputType = Services.prefs.getCharPref(
|
||||
"logging.config.output_type"
|
||||
);
|
||||
if (loggingOutputType.length) {
|
||||
updateLoggingOutputType(loggingOutputType);
|
||||
}
|
||||
} catch {
|
||||
updateLoggingOutputType("profiler");
|
||||
}
|
||||
|
||||
try {
|
||||
let loggingPreset = Services.prefs.getCharPref("logging.config.preset");
|
||||
gLoggingSettings.loggingPreset = loggingPreset;
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
let running = Services.prefs.getBoolPref("logging.config.running");
|
||||
gLoggingSettings.running = running;
|
||||
$("#toggle-logging-button").setAttribute(
|
||||
"data-l10n-id",
|
||||
`about-logging-${gLoggingSettings.running ? "stop" : "start"}-logging`
|
||||
);
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
let file = gDirServ.getFile("TmpD", {});
|
||||
file.append("log.txt");
|
||||
document.getElementById("log-file").value = file.path;
|
||||
$("#log-file").value = file.path;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
populatePresets();
|
||||
|
||||
// Update the value of the log file.
|
||||
updateLogFile();
|
||||
|
||||
|
@ -108,9 +200,8 @@ function init() {
|
|||
// If we can't set the file and the modules at runtime,
|
||||
// the start and stop buttons wouldn't really do anything.
|
||||
if (setLogButton.disabled || setModulesButton.disabled) {
|
||||
document.querySelector("#buttons-disabled").hidden = false;
|
||||
startLoggingButton.disabled = true;
|
||||
stopLoggingButton.disabled = true;
|
||||
$("#buttons-disabled").hidden = false;
|
||||
toggleLoggingButton.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,8 +211,8 @@ function updateLogFile() {
|
|||
// Try to get the environment variable for the log file
|
||||
logPath =
|
||||
Services.env.get("MOZ_LOG_FILE") || Services.env.get("NSPR_LOG_FILE");
|
||||
let currentLogFile = document.getElementById("current-log-file");
|
||||
let setLogFileButton = document.getElementById("set-log-file-button");
|
||||
let currentLogFile = $("#current-log-file");
|
||||
let setLogFileButton = $("#set-log-file-button");
|
||||
|
||||
// If the log file was set from an env var, we disable the ability to set it
|
||||
// at runtime.
|
||||
|
@ -135,15 +226,15 @@ function updateLogFile() {
|
|||
try {
|
||||
let file = gDirServ.getFile("TmpD", {});
|
||||
file.append("log.txt");
|
||||
document.getElementById("log-file").value = file.path;
|
||||
$("#log-file").value = file.path;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
// Fall back to the temp dir
|
||||
currentLogFile.innerText = document.getElementById("log-file").value;
|
||||
currentLogFile.innerText = $("#log-file").value;
|
||||
}
|
||||
|
||||
let openLogFileButton = document.getElementById("open-log-file-button");
|
||||
let openLogFileButton = $("#open-log-file-button");
|
||||
openLogFileButton.disabled = true;
|
||||
|
||||
if (currentLogFile.innerText.length) {
|
||||
|
@ -165,8 +256,8 @@ function updateLogModules() {
|
|||
Services.env.get("MOZ_LOG") ||
|
||||
Services.env.get("MOZ_LOG_MODULES") ||
|
||||
Services.env.get("NSPR_LOG_MODULES");
|
||||
let currentLogModules = document.getElementById("current-log-modules");
|
||||
let setLogModulesButton = document.getElementById("set-log-modules-button");
|
||||
let currentLogModules = $("#current-log-modules");
|
||||
let setLogModulesButton = $("#set-log-modules-button");
|
||||
if (logModules.length) {
|
||||
currentLogModules.innerText = logModules;
|
||||
// If the log modules are set by an environment variable at startup, do not
|
||||
|
@ -220,12 +311,12 @@ function updateLogModules() {
|
|||
}
|
||||
|
||||
function setLogFile() {
|
||||
let setLogButton = document.getElementById("set-log-file-button");
|
||||
let setLogButton = $("#set-log-file-button");
|
||||
if (setLogButton.disabled) {
|
||||
// There's no point trying since it wouldn't work anyway.
|
||||
return;
|
||||
}
|
||||
let logFile = document.getElementById("log-file").value.trim();
|
||||
let logFile = $("#log-file").value.trim();
|
||||
Services.prefs.setCharPref("logging.config.LOG_FILE", logFile);
|
||||
updateLogFile();
|
||||
}
|
||||
|
@ -244,13 +335,13 @@ function clearLogModules() {
|
|||
}
|
||||
|
||||
function setLogModules() {
|
||||
let setLogModulesButton = document.getElementById("set-log-modules-button");
|
||||
let setLogModulesButton = $("#set-log-modules-button");
|
||||
if (setLogModulesButton.disabled) {
|
||||
// The modules were set via env var, so we shouldn't try to change them.
|
||||
return;
|
||||
}
|
||||
|
||||
let modules = document.getElementById("log-modules").value.trim();
|
||||
let modules = $("#log-modules").value.trim();
|
||||
|
||||
// Clear previously set log modules.
|
||||
clearLogModules();
|
||||
|
@ -280,17 +371,76 @@ function setLogModules() {
|
|||
updateLogModules();
|
||||
}
|
||||
|
||||
function isLogging() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref("logging.config.running");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function startStopLogging() {
|
||||
if (isLogging()) {
|
||||
document.l10n.setAttributes(
|
||||
$("#toggle-logging-button"),
|
||||
"about-logging-start-logging"
|
||||
);
|
||||
stopLogging();
|
||||
} else {
|
||||
document.l10n.setAttributes(
|
||||
$("#toggle-logging-button"),
|
||||
"about-logging-stop-logging"
|
||||
);
|
||||
startLogging();
|
||||
}
|
||||
}
|
||||
|
||||
function startLogging() {
|
||||
setLogFile();
|
||||
setLogModules();
|
||||
if (gLoggingSettings.loggingOutputType === "profiler") {
|
||||
if (gLoggingSettings.loggingPreset != "custom") {
|
||||
// Change the preset before starting the profiler, so that the
|
||||
// underlying profiler code picks up the right configuration.
|
||||
const profilerPreset =
|
||||
gLoggingPresets[gLoggingSettings.loggingPreset].profilerPreset;
|
||||
const supportedFeatures = Services.profiler.GetFeatures();
|
||||
ProfilerPopupBackground.changePreset(
|
||||
"aboutlogging",
|
||||
profilerPreset,
|
||||
supportedFeatures
|
||||
);
|
||||
}
|
||||
// Force displaying the profiler button in the navbar if not preset, so
|
||||
// that there is a visual indication profiling is in progress.
|
||||
if (!ProfilerMenuButton.isInNavbar()) {
|
||||
// Ensure the widget is enabled.
|
||||
Services.prefs.setBoolPref(
|
||||
"devtools.performance.popup.feature-flag",
|
||||
true
|
||||
);
|
||||
// Enable the profiler menu button.
|
||||
ProfilerMenuButton.addToNavbar();
|
||||
// Dispatch the change event manually, so that the shortcuts will also be
|
||||
// added.
|
||||
CustomizableUI.dispatchToolboxEvent("customizationchange");
|
||||
}
|
||||
ProfilerPopupBackground.startProfiler("aboutlogging");
|
||||
} else {
|
||||
setLogFile();
|
||||
}
|
||||
Services.prefs.setBoolPref("logging.config.running", true);
|
||||
}
|
||||
|
||||
function stopLogging() {
|
||||
clearLogModules();
|
||||
// clear the log file as well
|
||||
if (gLoggingSettings.loggingOutputType === "profiler") {
|
||||
ProfilerPopupBackground.captureProfile("aboutlogging");
|
||||
} else {
|
||||
Services.prefs.clearUserPref("logging.config.LOG_FILE");
|
||||
updateLogFile();
|
||||
}
|
||||
Services.prefs.setBoolPref("logging.config.running", false);
|
||||
clearLogModules();
|
||||
}
|
||||
|
||||
// We use the pageshow event instead of onload. This is needed because sometimes
|
||||
// the page is loaded via session-restore/bfcache. In such cases we need to call
|
||||
|
|
|
@ -2,6 +2,20 @@
|
|||
# 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/.
|
||||
|
||||
## The following feature name must be treated as a brand.
|
||||
##
|
||||
## They cannot be:
|
||||
## - Transliterated.
|
||||
## - Translated.
|
||||
##
|
||||
## Declension should be avoided where possible, leaving the original
|
||||
## brand unaltered in prominent UI positions.
|
||||
##
|
||||
## For further details, consult:
|
||||
## https://mozilla-l10n.github.io/styleguides/mozilla_general/#brands-copyright-and-trademark
|
||||
|
||||
-profiler-brand-name = Firefox Profiler
|
||||
|
||||
# This is the title of the page
|
||||
about-logging-title = About Logging
|
||||
about-logging-page-title = Logging manager
|
||||
|
@ -22,6 +36,7 @@ about-logging-log-modules-selection = Log module selection
|
|||
about-logging-new-log-modules = New log modules:
|
||||
about-logging-logging-output-selection = Logging output
|
||||
about-logging-logging-to-file = Logging to a file
|
||||
about-logging-logging-to-profiler = Logging to the { -profiler-brand-name }
|
||||
about-logging-no-log-modules = None
|
||||
about-logging-logging-preset-selector-text = Logging preset:
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ div.page-section > div {
|
|||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
div.page-section > div.radio-entry {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
#current-log-modules,
|
||||
#no-log-modules {
|
||||
font-family: monospace;
|
||||
|
|
Загрузка…
Ссылка в новой задаче