Bug 1648373 - Add slow requests indicator r=Honza

Differential Revision: https://phabricator.services.mozilla.com/D81629
This commit is contained in:
Hubert Boma Manilla 2020-06-30 16:54:55 +00:00
Родитель 73be855175
Коммит c6f4a0a285
17 изменённых файлов: 132 добавлений и 7 удалений

Просмотреть файл

@ -2178,6 +2178,9 @@ pref("devtools.netmonitor.har.enableAutoExportToFile", false);
pref("devtools.netmonitor.features.webSockets", true); pref("devtools.netmonitor.features.webSockets", true);
// netmonitor audit
pref("devtools.netmonitor.audits.slow", 500);
// Disable the EventSource Inspector. // Disable the EventSource Inspector.
pref("devtools.netmonitor.features.serverSentEvents", false); pref("devtools.netmonitor.features.serverSentEvents", false);

Просмотреть файл

@ -143,6 +143,7 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
networkInfo.response.remoteAddress = packet.response.remoteAddress; networkInfo.response.remoteAddress = packet.response.remoteAddress;
networkInfo.response.remotePort = packet.response.remotePort; networkInfo.response.remotePort = packet.response.remotePort;
networkInfo.discardResponseBody = packet.response.discardResponseBody; networkInfo.discardResponseBody = packet.response.discardResponseBody;
networkInfo.response.waitingTime = packet.response.waitingTime;
break; break;
case "responseContent": case "responseContent":
networkInfo.response.content = { networkInfo.response.content = {

Просмотреть файл

@ -238,6 +238,7 @@ devtools.jar:
content/netmonitor/src/assets/icons/play.svg (netmonitor/src/assets/icons/play.svg) content/netmonitor/src/assets/icons/play.svg (netmonitor/src/assets/icons/play.svg)
content/netmonitor/src/assets/icons/arrow-up.svg (netmonitor/src/assets/icons/arrow-up.svg) content/netmonitor/src/assets/icons/arrow-up.svg (netmonitor/src/assets/icons/arrow-up.svg)
content/netmonitor/src/assets/icons/shield.svg (netmonitor/src/assets/icons/shield.svg) content/netmonitor/src/assets/icons/shield.svg (netmonitor/src/assets/icons/shield.svg)
content/netmonitor/src/assets/icons/turtle.svg (netmonitor/src/assets/icons/turtle.svg)
content/netmonitor/index.html (netmonitor/index.html) content/netmonitor/index.html (netmonitor/index.html)
content/netmonitor/src/assets/styles/StatusCode.css (netmonitor/src/assets/styles/StatusCode.css) content/netmonitor/src/assets/styles/StatusCode.css (netmonitor/src/assets/styles/StatusCode.css)
content/netmonitor/src/assets/styles/messages.css (netmonitor/src/assets/styles/messages.css) content/netmonitor/src/assets/styles/messages.css (netmonitor/src/assets/styles/messages.css)

Просмотреть файл

@ -1120,6 +1120,11 @@ netmonitor.timings.receive=Receiving:
# in the network details timings tab, with a link to external documentation # in the network details timings tab, with a link to external documentation
netmonitor.timings.learnMore=Learn more about timings netmonitor.timings.learnMore=Learn more about timings
# LOCALIZATION NOTE (netmonitor.audits.slowTooltip): This is the tooltip text displayed
# in the network request list file column, on the slow icon button.
# %1$S is the waiting time %2$S is the slow threshold.
netmonitor.audits.slowTooltip=Slow request: The server response time %1$S, is over the recommended limit of %2$S
# LOCALIZATION NOTE (netmonitor.security.warning.cipher): A tooltip # LOCALIZATION NOTE (netmonitor.security.warning.cipher): A tooltip
# for warning icon that indicates a connection uses insecure cipher suite. # for warning icon that indicates a connection uses insecure cipher suite.
netmonitor.security.warning.cipher=The cipher used for encryption is deprecated and insecure. netmonitor.security.warning.cipher=The cipher used for encryption is deprecated and insecure.

Просмотреть файл

@ -0,0 +1,6 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 7.5" width="12" height="12" fill="context-fill">
<path d="M1.5,4.5c.75,0,1.31.75,1.68,1.49A4.47,4.47,0,0,1,7.5,2.25C10.5,2.25,12,5,12,7.5h-.75V9.38a.37.37,0,0,1-.37.38H9.38A.38.38,0,0,1,9,9.38V8.25H5.25V9.38a.37.37,0,0,1-.37.38H3.38A.37.37,0,0,1,3,9.38V7.5H1.5a1.5,1.5,0,0,1,0-3Z" transform="translate(0 -2.25)"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 591 B

Просмотреть файл

@ -33,6 +33,49 @@
background-image: url(chrome://devtools/skin/images/profiler-stopwatch.svg); background-image: url(chrome://devtools/skin/images/profiler-stopwatch.svg);
} }
.requests-list-slow-button {
width: 12px;
height: 12px;
position: absolute;
right: 0;
transform: translateY(-50%);
top: 50%;
cursor: pointer;
background-image: linear-gradient(to right,transparent, var(--theme-body-background) 43%);
padding-inline-end: 30px;
padding-inline-start: 5px;
}
.request-list-item:not(.selected).odd .requests-list-slow-button {
background-image: linear-gradient(to right,transparent, var(--table-zebra-inline-icons-background) 43%);
}
.request-list-item:not(.selected):hover .requests-list-slow-button,
.request-list-item:not(.selected).odd:hover .requests-list-slow-button {
background-image: linear-gradient(to right,transparent, var(--table-selection-inline-icons-background-hover) 43%);
}
.request-list-item.selected .requests-list-slow-button {
background-image: linear-gradient(to right,transparent, var(--theme-selection-background) 43%);
}
.requests-list-slow-button::before {
content: "";
width: 12px;
height: 16px;
display: inline-block;
background-image: url(chrome://devtools/content/netmonitor/src/assets/icons/turtle.svg);
background-repeat: no-repeat;
background-position-x: right;
padding-inline-end: 14px;
fill: var(--grey-40);
-moz-context-properties: fill;
}
.request-list-item.selected .requests-list-slow-button::before {
fill: currentColor;
}
.requests-list-reload-notice-button { .requests-list-reload-notice-button {
font-size: inherit; font-size: inherit;
min-height: 26px; min-height: 26px;
@ -97,6 +140,10 @@
user-select: none; user-select: none;
} }
.requests-list-column {
position: relative;
}
.requests-list-column > * { .requests-list-column > * {
display: inline-block; display: inline-block;
} }

Просмотреть файл

@ -15,7 +15,9 @@
:root.theme-dark { :root.theme-dark {
--table-splitter-color: var(--grey-70); --table-splitter-color: var(--grey-70);
--table-zebra-background: rgba(255,255,255,0.05); --table-zebra-background: rgba(255,255,255,0.05);
--table-zebra-inline-icons-background: rgb(49, 47, 47);
--table-selection-background-hover: rgba(53, 59, 72, 1); --table-selection-background-hover: rgba(53, 59, 72, 1);
--table-selection-inline-icons-background-hover: rgba(53, 59, 72, 1);
--timing-blocked-color: var(--red-20); --timing-blocked-color: var(--red-20);
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */ --timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */
@ -29,7 +31,9 @@
:root.theme-light { :root.theme-light {
--table-splitter-color: var(--grey-20); --table-splitter-color: var(--grey-20);
--table-zebra-background: rgba(247, 247, 247, 0.8); --table-zebra-background: rgba(247, 247, 247, 0.8);
--table-zebra-inline-icons-background: rgba(247, 247, 247);
--table-selection-background-hover: rgba(209, 232, 255, 0.8); --table-selection-background-hover: rgba(209, 232, 255, 0.8);
--table-selection-inline-icons-background-hover: rgba(209, 232, 255);
--timing-blocked-color: var(--red-70); --timing-blocked-color: var(--red-70);
--timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */ --timing-dns-color: rgba(223, 128, 255, 0.8); /* pink */

Просмотреть файл

@ -8,16 +8,24 @@ const { Component } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories"); const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { L10N } = require("devtools/client/netmonitor/src/utils/l10n"); const { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {
connect,
} = require("devtools/client/shared/redux/visibility-handler-connect");
const { const {
propertiesEqual, propertiesEqual,
} = require("devtools/client/netmonitor/src/utils/request-utils"); } = require("devtools/client/netmonitor/src/utils/request-utils");
const {
getFormattedTime,
} = require("devtools/client/netmonitor/src/utils/format-utils");
const UPDATED_FILE_PROPS = ["urlDetails"]; const UPDATED_FILE_PROPS = ["urlDetails", "waitingTime"];
class RequestListColumnFile extends Component { class RequestListColumnFile extends Component {
static get propTypes() { static get propTypes() {
return { return {
item: PropTypes.object.isRequired, item: PropTypes.object.isRequired,
slowLimit: PropTypes.number,
onWaterfallMouseDown: PropTypes.func,
}; };
} }
@ -31,7 +39,9 @@ class RequestListColumnFile extends Component {
render() { render() {
const { const {
item: { urlDetails }, item: { urlDetails, waitingTime },
slowLimit,
onWaterfallMouseDown,
} = this.props; } = this.props;
const originalFileURL = urlDetails.url; const originalFileURL = urlDetails.url;
@ -50,14 +60,28 @@ class RequestListColumnFile extends Component {
? originalFileURL ? originalFileURL
: ORIGINAL_FILE_URL + "\n\n" + DECODED_FILE_URL; : ORIGINAL_FILE_URL + "\n\n" + DECODED_FILE_URL;
const isSlow = slowLimit > 0 && !!waitingTime && waitingTime > slowLimit;
return dom.td( return dom.td(
{ {
className: "requests-list-column requests-list-file", className: "requests-list-column requests-list-file",
title: fileToolTip, title: fileToolTip,
}, },
requestedFile dom.div({}, requestedFile),
isSlow &&
dom.div({
title: L10N.getFormatStr(
"netmonitor.audits.slowTooltip",
getFormattedTime(waitingTime),
getFormattedTime(slowLimit)
),
onMouseDown: onWaterfallMouseDown,
className: "requests-list-slow-button",
})
); );
} }
} }
module.exports = RequestListColumnFile; module.exports = connect(state => ({
slowLimit: state.ui.slowLimit,
}))(RequestListColumnFile);

Просмотреть файл

@ -152,6 +152,7 @@ const UPDATED_REQ_ITEM_PROPS = [
"requestHeaders", "requestHeaders",
"responseCookies", "responseCookies",
"responseHeaders", "responseHeaders",
"waitingTime",
]; ];
const UPDATED_REQ_PROPS = [ const UPDATED_REQ_PROPS = [
@ -177,7 +178,11 @@ const COLUMN_COMPONENTS = [
ColumnComponent: RequestListColumnDomain, ColumnComponent: RequestListColumnDomain,
props: ["onSecurityIconMouseDown"], props: ["onSecurityIconMouseDown"],
}, },
{ column: "file", ColumnComponent: RequestListColumnFile }, {
column: "file",
ColumnComponent: RequestListColumnFile,
props: ["onWaterfallMouseDown"],
},
{ {
column: "url", column: "url",
ColumnComponent: RequestListColumnUrl, ColumnComponent: RequestListColumnUrl,

Просмотреть файл

@ -419,6 +419,7 @@ class FirefoxDataProvider {
status: networkInfo.response.status, status: networkInfo.response.status,
statusText: networkInfo.response.statusText, statusText: networkInfo.response.statusText,
headersSize: networkInfo.response.headersSize, headersSize: networkInfo.response.headersSize,
waitingTime: networkInfo.response.waitingTime,
}); });
this.emitForTests(TEST_EVENTS.STARTED_RECEIVING_RESPONSE, actor); this.emitForTests(TEST_EVENTS.STARTED_RECEIVING_RESPONSE, actor);
break; break;

Просмотреть файл

@ -226,6 +226,7 @@ const UPDATE_PROPS = [
"blockedReason", "blockedReason",
"blockingExtension", "blockingExtension",
"channelId", "channelId",
"waitingTime",
]; ];
const PANELS = { const PANELS = {

Просмотреть файл

@ -154,6 +154,10 @@ function getFilterState() {
return new FilterTypes(activeFilters); return new FilterTypes(activeFilters);
} }
/**
* Get json data from preferences
*/
function getPref(pref) { function getPref(pref) {
try { try {
return JSON.parse(Services.prefs.getCharPref(pref)); return JSON.parse(Services.prefs.getCharPref(pref));

Просмотреть файл

@ -81,6 +81,7 @@ function UI(initialState = {}) {
"devtools.netmonitor.persistlog" "devtools.netmonitor.persistlog"
), ),
browserCacheDisabled: Services.prefs.getBoolPref("devtools.cache.disabled"), browserCacheDisabled: Services.prefs.getBoolPref("devtools.cache.disabled"),
slowLimit: Services.prefs.getIntPref("devtools.netmonitor.audits.slow"),
statisticsOpen: false, statisticsOpen: false,
waterfallWidth: null, waterfallWidth: null,
networkActionOpen: false, networkActionOpen: false,

Просмотреть файл

@ -328,6 +328,14 @@ function getCleanedPacket(key, packet) {
res.networkInfo.response.transferredSize = res.networkInfo.response.transferredSize =
existingPacket.networkInfo.response.transferredSize; existingPacket.networkInfo.response.transferredSize;
} }
if (
res.networkInfo.response &&
res.networkInfo.response.waitingTime !== undefined
) {
res.networkInfo.response.waitingTime =
existingPacket.networkInfo.response.waitingTime;
}
} }
if (res.updates && Array.isArray(res.updates)) { if (res.updates && Array.isArray(res.updates)) {

Просмотреть файл

@ -51,6 +51,7 @@ rawPackets.set(`GET request`, {
"headersSize": 160, "headersSize": 160,
"remoteAddress": "127.0.0.1", "remoteAddress": "127.0.0.1",
"remotePort": 8888, "remotePort": 8888,
"waitingTime": 2,
"content": { "content": {
"mimeType": "text/html; charset=utf-8" "mimeType": "text/html; charset=utf-8"
}, },
@ -90,6 +91,7 @@ rawPackets.set(`GET request update`, {
"headersSize": 160, "headersSize": 160,
"remoteAddress": "127.0.0.1", "remoteAddress": "127.0.0.1",
"remotePort": 8888, "remotePort": 8888,
"waitingTime": 2,
"content": { "content": {
"mimeType": "text/html; charset=utf-8" "mimeType": "text/html; charset=utf-8"
}, },
@ -133,6 +135,7 @@ rawPackets.set(`XHR GET request`, {
"headersSize": 160, "headersSize": 160,
"remoteAddress": "127.0.0.1", "remoteAddress": "127.0.0.1",
"remotePort": 8888, "remotePort": 8888,
"waitingTime": 1,
"content": { "content": {
"mimeType": "text/html; charset=utf-8" "mimeType": "text/html; charset=utf-8"
}, },
@ -172,6 +175,7 @@ rawPackets.set(`XHR GET request update`, {
"headersSize": 160, "headersSize": 160,
"remoteAddress": "127.0.0.1", "remoteAddress": "127.0.0.1",
"remotePort": 8888, "remotePort": 8888,
"waitingTime": 1,
"content": { "content": {
"mimeType": "text/html; charset=utf-8" "mimeType": "text/html; charset=utf-8"
}, },
@ -215,6 +219,7 @@ rawPackets.set(`XHR POST request`, {
"headersSize": 160, "headersSize": 160,
"remoteAddress": "127.0.0.1", "remoteAddress": "127.0.0.1",
"remotePort": 8888, "remotePort": 8888,
"waitingTime": 1,
"content": { "content": {
"mimeType": "text/html; charset=utf-8" "mimeType": "text/html; charset=utf-8"
}, },
@ -254,6 +259,7 @@ rawPackets.set(`XHR POST request update`, {
"headersSize": 160, "headersSize": 160,
"remoteAddress": "127.0.0.1", "remoteAddress": "127.0.0.1",
"remotePort": 8888, "remotePort": 8888,
"waitingTime": 1,
"content": { "content": {
"mimeType": "text/html; charset=utf-8" "mimeType": "text/html; charset=utf-8"
}, },

Просмотреть файл

@ -410,6 +410,7 @@ const NetworkEventActor = protocol.ActorClassWithSpec(networkEventSpec, {
this._response.status = info.status; this._response.status = info.status;
this._response.statusText = info.statusText; this._response.statusText = info.statusText;
this._response.headersSize = info.headersSize; this._response.headersSize = info.headersSize;
this._response.waitingTime = info.waitingTime;
// Consider as not discarded if info.discardResponseBody is undefined // Consider as not discarded if info.discardResponseBody is undefined
this._discardResponseBody = !!info.discardResponseBody; this._discardResponseBody = !!info.discardResponseBody;

Просмотреть файл

@ -495,6 +495,7 @@ NetworkObserver.prototype = {
status: response.status, status: response.status,
statusText: response.statusText, statusText: response.statusText,
headersSize: 0, headersSize: 0,
waitingTime: 0,
}, },
"", "",
true true
@ -1087,7 +1088,9 @@ NetworkObserver.prototype = {
response.status = statusLineArray.shift(); response.status = statusLineArray.shift();
response.statusText = statusLineArray.join(" "); response.statusText = statusLineArray.join(" ");
response.headersSize = extraStringData.length; response.headersSize = extraStringData.length;
response.waitingTime = this._convertTimeToMs(
this._getWaitTiming(httpActivity.timings)
);
httpActivity.responseStatus = response.status; httpActivity.responseStatus = response.status;
httpActivity.headersSize = response.headersSize; httpActivity.headersSize = response.headersSize;
@ -1443,6 +1446,10 @@ NetworkObserver.prototype = {
return serverTimings; return serverTimings;
}, },
_convertTimeToMs: function(timing) {
return Math.max(Math.round(timing / 1000), -1);
},
_calculateOffsetAndTotalTime: function( _calculateOffsetAndTotalTime: function(
harTimings, harTimings,
secureConnectionStartTime, secureConnectionStartTime,
@ -1452,7 +1459,7 @@ NetworkObserver.prototype = {
) { ) {
let totalTime = 0; let totalTime = 0;
for (const timing in harTimings) { for (const timing in harTimings) {
const time = Math.max(Math.round(harTimings[timing] / 1000), -1); const time = this._convertTimeToMs(harTimings[timing]);
harTimings[timing] = time; harTimings[timing] = time;
if (time > -1 && timing != "connect" && timing != "ssl") { if (time > -1 && timing != "connect" && timing != "ssl") {
totalTime += time; totalTime += time;