mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-12 19:50:04 +05:00
webui v165: a Debug page
The API timings went into the phone status sheet in v162; a page of their own reads better and works in the wide layout too. /debug, in the rail and in the phone's More sheet: the web UI build and the core version with its round trip, a Reload button, requests in flight, the last sendChat round trip, the five slowest and the twenty last requests, the event stream (bytes, last event, reconnections), and a reset. The status sheet keeps the version label and its Reload button only.
This commit is contained in:
parent
4e3530cc20
commit
410359b4fa
110
webui-src/app/debug/debug.js
Normal file
110
webui-src/app/debug/debug.js
Normal file
@ -0,0 +1,110 @@
|
||||
const m = require('mithril');
|
||||
const rs = require('rswebui');
|
||||
|
||||
// A page for what is otherwise invisible from a phone: which build this is,
|
||||
// what the core answers, and what the API is doing from this browser --
|
||||
// requests in flight, the round trip of the last chat message, the slowest
|
||||
// calls, the health of the event stream. Numbers, not a console.
|
||||
|
||||
const Debug = () => {
|
||||
let timer = null;
|
||||
let coreVersion = null;
|
||||
let coreVersionAt = 0;
|
||||
|
||||
const ago = (t) => (t ? Math.round((Date.now() - t) / 1000) + ' s ago' : 'never');
|
||||
const short = (p) => String(p || '').replace(/^\/rs/, '');
|
||||
|
||||
const loadCoreVersion = () => {
|
||||
const startedAt = performance.now();
|
||||
rs.rsJsonApiRequest('/rsJsonApi/version', {}, (data, success) => {
|
||||
coreVersionAt = Math.round(performance.now() - startedAt);
|
||||
coreVersion = success && data ? data : null;
|
||||
m.redraw();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
oninit: () => {
|
||||
loadCoreVersion();
|
||||
// The counters move on their own; redraw once a second while here.
|
||||
timer = setInterval(() => m.redraw(), 1000);
|
||||
},
|
||||
onremove: () => {
|
||||
if (timer) clearInterval(timer);
|
||||
},
|
||||
view: (vnode) => {
|
||||
const s = rs.apiStats;
|
||||
const version = vnode.attrs.version || '';
|
||||
const core = coreVersion
|
||||
? `${coreVersion.major}.${coreVersion.minor}.${coreVersion.mini}${coreVersion.extra || ''} (${coreVersion.human || ''})`
|
||||
: 'unknown';
|
||||
|
||||
return m('.debug-page', [
|
||||
m('h2', 'Debug'),
|
||||
|
||||
m('.debug-section', [
|
||||
m('h3', 'Build'),
|
||||
m('.debug-grid', [
|
||||
m('span', 'Web UI'), m('strong', version),
|
||||
m('span', 'Core'), m('strong', core),
|
||||
m('span', 'Core round trip'), m('strong', coreVersion ? coreVersionAt + ' ms' : '-'),
|
||||
m('span', 'Page loaded'), m('strong', ago(s.startedAt)),
|
||||
m('span', 'Viewport'), m('strong', `${window.innerWidth} x ${window.innerHeight} px`),
|
||||
]),
|
||||
m('.debug-actions', [
|
||||
// The page keeps the code it loaded until reloaded, and a phone
|
||||
// browser hides that action away: a new build shows only after this.
|
||||
m('button', { onclick: () => window.location.reload(true) }, [m('i.fas.fa-sync-alt'), ' Reload the web UI']),
|
||||
m('button', { onclick: loadCoreVersion }, [m('i.fas.fa-stopwatch'), ' Ping the core']),
|
||||
]),
|
||||
]),
|
||||
|
||||
m('.debug-section', [
|
||||
m('h3', 'API from this browser'),
|
||||
m('.debug-grid', [
|
||||
m('span', 'Requests in flight'), m('strong', s.pending),
|
||||
m('span', 'Requests since load'), m('strong', s.total),
|
||||
m('span', 'Last sendChat'), m('strong', s.lastSend ? `${s.lastSend.ms} ms, ${ago(s.lastSend.at)}` : 'none yet'),
|
||||
]),
|
||||
m('h4', 'Slowest requests'),
|
||||
s.slowest.length === 0
|
||||
? m('p.debug-empty', 'Nothing yet.')
|
||||
: m('table.debug-table', [
|
||||
m('thead', m('tr', [m('th', 'Request'), m('th', 'Time'), m('th', 'When')])),
|
||||
m('tbody', s.slowest.map((e) => m('tr', [
|
||||
m('td', short(e.path)),
|
||||
m('td', e.ms + ' ms'),
|
||||
m('td', ago(e.at)),
|
||||
]))),
|
||||
]),
|
||||
m('h4', 'Last requests'),
|
||||
s.recent.length === 0
|
||||
? m('p.debug-empty', 'Nothing yet.')
|
||||
: m('table.debug-table', [
|
||||
m('thead', m('tr', [m('th', 'Request'), m('th', 'Time'), m('th', 'When')])),
|
||||
m('tbody', s.recent.map((e) => m('tr', [
|
||||
m('td', short(e.path)),
|
||||
m('td', e.ms + ' ms'),
|
||||
m('td', ago(e.at)),
|
||||
]))),
|
||||
]),
|
||||
m('.debug-actions', [
|
||||
m('button', { onclick: () => rs.resetApiStats() }, [m('i.fas.fa-eraser'), ' Reset counters']),
|
||||
]),
|
||||
]),
|
||||
|
||||
m('.debug-section', [
|
||||
m('h3', 'Event stream'),
|
||||
m('.debug-grid', [
|
||||
m('span', 'Received'), m('strong', rs.formatBytes(s.eventsBytes)),
|
||||
m('span', 'Last event'), m('strong', ago(s.lastEventAt)),
|
||||
m('span', 'Reconnections'), m('strong', s.eventsRestarts),
|
||||
]),
|
||||
m('p.debug-hint', 'The stream carries every event of the core over one long request; it holds one of the six connections a browser keeps to a host, the others queue the requests above.'),
|
||||
]),
|
||||
]);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Debug;
|
||||
@ -1,7 +1,7 @@
|
||||
const m = require('mithril');
|
||||
|
||||
// Bumped at every change of the web UI (two places used to carry it).
|
||||
const WEBUI_VERSION = 'v164';
|
||||
const WEBUI_VERSION = 'v165';
|
||||
|
||||
const login = require('login');
|
||||
const rs = require('rswebui');
|
||||
@ -16,6 +16,7 @@ const forums = require('forums/forums');
|
||||
const boards = require('boards/boards');
|
||||
const config = require('config/config_resolver');
|
||||
const statistics = require('statistics/statistics');
|
||||
const debug = require('debug/debug');
|
||||
const statusbar = require('statusbar');
|
||||
const networkState = require('network/network_state');
|
||||
const peopleState = require('people/people_state');
|
||||
@ -46,6 +47,7 @@ const navIcon = {
|
||||
boards: 'i.fas.fa-globe.sidenav-icon',
|
||||
config: 'i.fas.fa-cogs.sidenav-icon',
|
||||
statistics: 'i.fas.fa-chart-pie.sidenav-icon',
|
||||
debug: 'i.fas.fa-bug.sidenav-icon',
|
||||
};
|
||||
|
||||
const navbar = () => {
|
||||
@ -201,6 +203,7 @@ const mobileMoreLinks = {
|
||||
boards: '/boards/MyBoards',
|
||||
config: '/config/network',
|
||||
statistics: '/statistics',
|
||||
debug: '/debug',
|
||||
};
|
||||
|
||||
const MobileStatus = () => {
|
||||
@ -264,23 +267,6 @@ const MobileStatus = () => {
|
||||
m('small', statusbar.formatBytes(state.totalOut)),
|
||||
]),
|
||||
]),
|
||||
// Where the seconds go, seen from this phone. A request slow on its
|
||||
// own points at the core; many pending at once points at the
|
||||
// browser's six sockets, one of them held by the event stream.
|
||||
(() => {
|
||||
const s = rs.apiStats;
|
||||
const ago = (t) => (t ? Math.round((Date.now() - t) / 1000) + 's ago' : 'never');
|
||||
const short = (p) => String(p || '').replace(/^\/rs/, '');
|
||||
return m('.mobile-status-sheet__diag', [
|
||||
m('h4', 'API from this browser'),
|
||||
m('div', `pending ${s.pending} · total ${s.total} · up ${Math.round((Date.now() - s.startedAt) / 1000)}s`),
|
||||
m('div', s.lastSend
|
||||
? `last sendChat ${s.lastSend.ms} ms (${ago(s.lastSend.at)})`
|
||||
: 'no sendChat yet'),
|
||||
m('div', `events: ${statusbar.formatBytes(s.eventsBytes)}, last ${ago(s.lastEventAt)}, restarts ${s.eventsRestarts}`),
|
||||
s.slowest.length > 0 && m('div', 'slowest: ' + s.slowest.map((e) => `${short(e.path)} ${e.ms}ms`).join(', ')),
|
||||
]);
|
||||
})(),
|
||||
m('.mobile-status-sheet__version', [
|
||||
'WebUI ' + WEBUI_VERSION,
|
||||
// The page keeps the code it loaded until it is reloaded, and a
|
||||
@ -381,6 +367,7 @@ const Layout = () => {
|
||||
boards: '/boards/MyBoards',
|
||||
statistics: '/statistics',
|
||||
config: '/config/network',
|
||||
debug: '/debug',
|
||||
},
|
||||
}),
|
||||
m(
|
||||
@ -474,6 +461,9 @@ m.route(document.getElementById('main'), '/', {
|
||||
'/statistics': {
|
||||
render: () => m(Layout, m(statistics)),
|
||||
},
|
||||
'/debug': {
|
||||
render: () => m(Layout, m(debug, { version: WEBUI_VERSION })),
|
||||
},
|
||||
});
|
||||
|
||||
// v51 architectural fix: ensure event queue starts on direct route refresh
|
||||
|
||||
@ -106,6 +106,8 @@ const apiStats = {
|
||||
lastSend: null,
|
||||
// The five slowest requests since load, newest first on a tie.
|
||||
slowest: [],
|
||||
// The last twenty requests, newest first.
|
||||
recent: [],
|
||||
// Event stream: bytes received since (re)connection, last event time,
|
||||
// number of reconnections.
|
||||
eventsBytes: 0,
|
||||
@ -121,6 +123,16 @@ function recordRequestTime(path, ms) {
|
||||
apiStats.slowest.push(entry);
|
||||
apiStats.slowest.sort((a, b) => b.ms - a.ms);
|
||||
if (apiStats.slowest.length > 5) apiStats.slowest.length = 5;
|
||||
apiStats.recent.unshift(entry);
|
||||
if (apiStats.recent.length > 20) apiStats.recent.length = 20;
|
||||
}
|
||||
|
||||
function resetApiStats() {
|
||||
apiStats.total = 0;
|
||||
apiStats.lastSend = null;
|
||||
apiStats.slowest = [];
|
||||
apiStats.recent = [];
|
||||
apiStats.eventsRestarts = 0;
|
||||
}
|
||||
|
||||
const connectionState = {
|
||||
@ -577,6 +589,7 @@ module.exports = {
|
||||
idToHex: hexId,
|
||||
connectionState,
|
||||
apiStats,
|
||||
resetApiStats,
|
||||
setKeys,
|
||||
setBackgroundTask,
|
||||
logon,
|
||||
|
||||
@ -616,28 +616,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* API diagnostics in the phone status sheet (main.js MobileStatus): request
|
||||
* timings seen from this browser, so a slow phone can be measured without a
|
||||
* console. */
|
||||
.mobile-status-sheet__diag {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
background: rgba(15, 23, 42, 0.06);
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.4;
|
||||
color: #334155;
|
||||
word-break: break-word;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 0.25rem;
|
||||
font-size: 0.7rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: #64748b;
|
||||
}
|
||||
}
|
||||
|
||||
/* Version label in the phone header, and the reload button beside the
|
||||
* version in the status sheet (main.js MobileStatus). */
|
||||
.mobile-app-header__version {
|
||||
|
||||
86
webui-src/app/scss/pages/_debug.scss
Normal file
86
webui-src/app/scss/pages/_debug.scss
Normal file
@ -0,0 +1,86 @@
|
||||
// The debug page (debug/debug.js): build, API timings, event stream.
|
||||
.debug-page {
|
||||
padding: 1.25rem;
|
||||
max-width: 720px;
|
||||
|
||||
h2 {
|
||||
margin: 0 0 1rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0 0 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0.75rem 0 0.25rem;
|
||||
font-size: 0.8rem;
|
||||
color: #475569;
|
||||
}
|
||||
}
|
||||
|
||||
.debug-section {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.75rem 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.debug-grid {
|
||||
display: grid;
|
||||
grid-template-columns: max-content 1fr;
|
||||
gap: 0.25rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
color: #334155;
|
||||
|
||||
strong {
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.debug-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.75rem;
|
||||
|
||||
button {
|
||||
border: 1px solid #cbd5e1;
|
||||
background: #f8fafc;
|
||||
color: #334155;
|
||||
border-radius: 0.375rem;
|
||||
padding: 0.4rem 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.debug-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.85rem;
|
||||
|
||||
th, td {
|
||||
text-align: left;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.debug-empty, .debug-hint {
|
||||
font-size: 0.8rem;
|
||||
color: #64748b;
|
||||
margin: 0.25rem 0 0;
|
||||
}
|
||||
@ -10,3 +10,4 @@
|
||||
@forward "board";
|
||||
@forward "config";
|
||||
@forward "statistics";
|
||||
@forward "debug";
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user