diff options
Diffstat (limited to 'src/zenserver/frontend/html/pages/hub.js')
| -rw-r--r-- | src/zenserver/frontend/html/pages/hub.js | 81 |
1 files changed, 65 insertions, 16 deletions
diff --git a/src/zenserver/frontend/html/pages/hub.js b/src/zenserver/frontend/html/pages/hub.js index 78e3a090c..c6f96d496 100644 --- a/src/zenserver/frontend/html/pages/hub.js +++ b/src/zenserver/frontend/html/pages/hub.js @@ -82,7 +82,7 @@ export class Page extends ZenPage this.set_title("hub"); // Capacity - const stats_section = this.add_section("Capacity"); + const stats_section = this._collapsible_section("Hub Service Stats"); this._stats_grid = stats_section.tag().classify("grid").classify("stats-tiles"); // Modules @@ -203,27 +203,46 @@ export class Page extends ZenPage { const tile = grid.tag().classify("card").classify("stats-tile"); - tile.tag().classify("card-title").text("Active Modules"); + tile.tag().classify("card-title").text("Instances"); const body = tile.tag().classify("tile-metrics"); this._metric(body, Friendly.sep(current), "currently provisioned", true); + this._metric(body, Friendly.sep(max), "high watermark"); + this._metric(body, Friendly.sep(limit), "maximum allowed"); + if (limit > 0) + { + const pct = ((current / limit) * 100).toFixed(0) + "%"; + this._metric(body, pct, "utilization"); + } } + const machine = data.machine || {}; + const limits = data.resource_limits || {}; + if (machine.disk_total_bytes > 0 || machine.memory_total_mib > 0) { - const tile = grid.tag().classify("card").classify("stats-tile"); - tile.tag().classify("card-title").text("Peak Modules"); - const body = tile.tag().classify("tile-metrics"); - this._metric(body, Friendly.sep(max), "high watermark", true); - } + const disk_used = Math.max(0, (machine.disk_total_bytes || 0) - (machine.disk_free_bytes || 0)); + const mem_used = Math.max(0, (machine.memory_total_mib || 0) - (machine.memory_avail_mib || 0)) * 1024 * 1024; + const vmem_used = Math.max(0, (machine.virtual_memory_total_mib || 0) - (machine.virtual_memory_avail_mib || 0)) * 1024 * 1024; + const disk_limit = limits.disk_bytes || 0; + const mem_limit = limits.memory_bytes || 0; + const disk_over = disk_limit > 0 && disk_used > disk_limit; + const mem_over = mem_limit > 0 && mem_used > mem_limit; - { const tile = grid.tag().classify("card").classify("stats-tile"); - tile.tag().classify("card-title").text("Instance Limit"); - const body = tile.tag().classify("tile-metrics"); - this._metric(body, Friendly.sep(limit), "maximum allowed", true); - if (limit > 0) + if (disk_over || mem_over) { tile.inner().setAttribute("data-over", "true"); } + tile.tag().classify("card-title").text("Resources"); + const columns = tile.tag().classify("tile-columns"); + + const left = columns.tag().classify("tile-metrics"); + this._metric(left, Friendly.bytes(disk_used), "disk used", true); + if (disk_limit > 0) { this._metric(left, Friendly.bytes(disk_limit), "disk limit"); } + + const right = columns.tag().classify("tile-metrics"); + this._metric(right, Friendly.bytes(mem_used), "memory used", true); + if (mem_limit > 0) { this._metric(right, Friendly.bytes(mem_limit), "memory limit"); } + if (machine.virtual_memory_total_mib > 0) { - const pct = ((current / limit) * 100).toFixed(0) + "%"; - this._metric(body, pct, "utilization"); + this._metric(right, Friendly.bytes(vmem_used), "vmem used", true); + this._metric(right, Friendly.bytes(machine.virtual_memory_total_mib * 1024 * 1024), "vmem total"); } } } @@ -284,6 +303,14 @@ export class Page extends ZenPage } row.state_text.nodeValue = state; row.port_text.nodeValue = m.port ? String(m.port) : ""; + if (m.state_change_time) + { + const state_label = state.charAt(0).toUpperCase() + state.slice(1); + row.state_since_label.textContent = state_label + " since"; + row.state_age_label.textContent = state_label + " for"; + row.state_since_node.nodeValue = m.state_change_time; + row.state_age_node.nodeValue = Friendly.timespan(Date.now() - new Date(m.state_change_time).getTime()); + } row.btn_open.disabled = state !== "provisioned"; row.btn_hibernate.disabled = !_btn_enabled(state, "hibernate"); row.btn_wake.disabled = !_btn_enabled(state, "wake"); @@ -388,7 +415,7 @@ export class Page extends ZenPage td_action.appendChild(wrap_o); tr.appendChild(td_action); - // Build metrics grid from process_metrics keys. + // Build metrics grid: fixed state-time rows followed by process_metrics keys. // Keys are split into two halves and interleaved so the grid fills // top-to-bottom in the left column before continuing in the right column. const metric_nodes = new Map(); @@ -396,6 +423,28 @@ export class Page extends ZenPage metrics_td.colSpan = 6; const metrics_grid = document.createElement("div"); metrics_grid.className = "module-metrics-grid"; + + const _add_fixed_pair = (label, value_str) => { + const label_el = document.createElement("span"); + label_el.className = "module-metrics-label"; + label_el.textContent = label; + const value_node = document.createTextNode(value_str); + const value_el = document.createElement("span"); + value_el.className = "module-metrics-value"; + value_el.appendChild(value_node); + metrics_grid.appendChild(label_el); + metrics_grid.appendChild(value_el); + return { label_el, value_node }; + }; + + const state_label = m.state ? m.state.charAt(0).toUpperCase() + m.state.slice(1) : "State"; + const state_since_str = m.state_change_time || ""; + const state_age_str = m.state_change_time + ? Friendly.timespan(Date.now() - new Date(m.state_change_time).getTime()) + : ""; + const { label_el: state_since_label, value_node: state_since_node } = _add_fixed_pair(state_label + " since", state_since_str); + const { label_el: state_age_label, value_node: state_age_node } = _add_fixed_pair(state_label + " for", state_age_str); + const keys = Object.keys(m.process_metrics || {}); const half = Math.ceil(keys.length / 2); const add_metric_pair = (key) => { @@ -423,7 +472,7 @@ export class Page extends ZenPage metrics_td.appendChild(metrics_grid); metrics_tr.appendChild(metrics_td); - row = { tr, metrics_tr, idx: td_idx, cb, dot, state_text: state_node, port_text: port_node, btn_expand, btn_open: btn_o, btn_hibernate: btn_h, btn_wake: btn_w, btn_deprov: btn_d, metric_nodes }; + row = { tr, metrics_tr, idx: td_idx, cb, dot, state_text: state_node, port_text: port_node, btn_expand, btn_open: btn_o, btn_hibernate: btn_h, btn_wake: btn_w, btn_deprov: btn_d, metric_nodes, state_since_node, state_age_node, state_since_label, state_age_label }; this._row_cache.set(id, row); } |