2022-06-22 11:20:57 +02:00
|
|
|
<script>
|
|
|
|
import { init } from './utils.js'
|
|
|
|
import { Row, Col, Input, InputGroup, InputGroupText, Icon, Spinner, Card } from 'sveltestrap'
|
2023-05-03 16:41:17 +02:00
|
|
|
import { queryStore, gql, getContextClient } from '@urql/svelte'
|
2022-06-22 11:20:57 +02:00
|
|
|
import TimeSelection from './filters/TimeSelection.svelte'
|
|
|
|
import PlotTable from './PlotTable.svelte'
|
|
|
|
import MetricPlot from './plots/MetricPlot.svelte'
|
|
|
|
import { getContext } from 'svelte'
|
|
|
|
|
|
|
|
export let cluster
|
|
|
|
export let from = null
|
|
|
|
export let to = null
|
|
|
|
|
|
|
|
const { query: initq } = init()
|
|
|
|
|
|
|
|
if (from == null || to == null) {
|
|
|
|
to = new Date(Date.now())
|
|
|
|
from = new Date(to.getTime())
|
|
|
|
from.setMinutes(from.getMinutes() - 30)
|
|
|
|
}
|
|
|
|
|
|
|
|
const clusters = getContext('clusters')
|
|
|
|
const ccconfig = getContext('cc-config')
|
2023-03-31 17:18:16 +02:00
|
|
|
const metricConfig = getContext('metrics')
|
2022-06-22 11:20:57 +02:00
|
|
|
|
|
|
|
let plotHeight = 300
|
|
|
|
let hostnameFilter = ''
|
|
|
|
let selectedMetric = ccconfig.system_view_selectedMetric
|
|
|
|
|
2023-05-12 11:19:37 +02:00
|
|
|
const client = getContextClient();
|
2023-05-10 16:35:21 +02:00
|
|
|
$: nodesQuery = queryStore({
|
2023-05-12 11:19:37 +02:00
|
|
|
client: client,
|
2023-05-03 16:41:17 +02:00
|
|
|
query: gql`query($cluster: String!, $metrics: [String!], $from: Time!, $to: Time!) {
|
2023-05-12 11:19:37 +02:00
|
|
|
nodeMetrics(cluster: $cluster, metrics: $metrics, from: $from, to: $to) {
|
|
|
|
host
|
|
|
|
subCluster
|
|
|
|
metrics {
|
|
|
|
name
|
|
|
|
scope
|
|
|
|
metric {
|
|
|
|
timestep
|
|
|
|
unit { base, prefix }
|
|
|
|
series {
|
|
|
|
statistics { min, avg, max }
|
|
|
|
data
|
|
|
|
}
|
2022-06-22 11:20:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-12 11:19:37 +02:00
|
|
|
}`,
|
|
|
|
variables: {
|
|
|
|
cluster: cluster,
|
|
|
|
metrics: [selectedMetric],
|
|
|
|
from: from.toISOString(),
|
|
|
|
to: to.toISOString()
|
2022-06-22 11:20:57 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2023-03-30 15:21:35 +02:00
|
|
|
let metricUnits = {}
|
|
|
|
$: if ($nodesQuery.data) {
|
|
|
|
let thisCluster = clusters.find(c => c.name == cluster)
|
|
|
|
for (let metric of thisCluster.metricConfig) {
|
|
|
|
if (metric.unit.prefix || metric.unit.base) {
|
|
|
|
metricUnits[metric.name] = '(' + (metric.unit.prefix ? metric.unit.prefix : '') + (metric.unit.base ? metric.unit.base : '') + ')'
|
|
|
|
} else { // If no unit defined: Omit Unit Display
|
|
|
|
metricUnits[metric.name] = ''
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-22 11:20:57 +02:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<Row>
|
|
|
|
{#if $initq.error}
|
|
|
|
<Card body color="danger">{$initq.error.message}</Card>
|
|
|
|
{:else if $initq.fetching}
|
|
|
|
<Spinner/>
|
|
|
|
{:else}
|
|
|
|
<Col>
|
|
|
|
<TimeSelection
|
|
|
|
bind:from={from}
|
|
|
|
bind:to={to} />
|
|
|
|
</Col>
|
|
|
|
<Col>
|
|
|
|
<InputGroup>
|
|
|
|
<InputGroupText><Icon name="graph-up" /></InputGroupText>
|
|
|
|
<InputGroupText>Metric</InputGroupText>
|
|
|
|
<select class="form-select" bind:value={selectedMetric}>
|
|
|
|
{#each clusters.find(c => c.name == cluster).metricConfig as metric}
|
2023-03-30 15:21:35 +02:00
|
|
|
<option value={metric.name}>{metric.name} {metricUnits[metric.name]}</option>
|
2022-06-22 11:20:57 +02:00
|
|
|
{/each}
|
|
|
|
</select>
|
|
|
|
</InputGroup>
|
|
|
|
</Col>
|
|
|
|
<Col>
|
|
|
|
<InputGroup>
|
|
|
|
<InputGroupText><Icon name="hdd" /></InputGroupText>
|
|
|
|
<InputGroupText>Find Node</InputGroupText>
|
|
|
|
<Input placeholder="hostname..." type="text" bind:value={hostnameFilter} />
|
|
|
|
</InputGroup>
|
|
|
|
</Col>
|
|
|
|
{/if}
|
|
|
|
</Row>
|
|
|
|
<br/>
|
|
|
|
<Row>
|
|
|
|
<Col>
|
|
|
|
{#if $nodesQuery.error}
|
|
|
|
<Card body color="danger">{$nodesQuery.error.message}</Card>
|
|
|
|
{:else if $nodesQuery.fetching || $initq.fetching}
|
|
|
|
<Spinner/>
|
|
|
|
{:else}
|
|
|
|
<PlotTable
|
|
|
|
let:item
|
|
|
|
let:width
|
|
|
|
itemsPerRow={ccconfig.plot_view_plotsPerRow}
|
|
|
|
items={$nodesQuery.data.nodeMetrics
|
2023-03-30 15:21:35 +02:00
|
|
|
.filter(h => h.host.includes(hostnameFilter) && h.metrics.some(m => m.name == selectedMetric && m.scope == 'node'))
|
2023-03-31 17:18:16 +02:00
|
|
|
.map(function (h) {
|
|
|
|
let thisConfig = metricConfig(cluster, selectedMetric)
|
|
|
|
let thisSCIndex = thisConfig.subClusters.findIndex(sc => sc.name == h.subCluster)
|
|
|
|
// Metric remove == true
|
|
|
|
if (thisSCIndex >= 0) {
|
|
|
|
if (thisConfig.subClusters[thisSCIndex].remove == true) {
|
|
|
|
return { host: h.host, subCluster: h.subCluster, data: null, removed: true }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Else
|
|
|
|
return { host: h.host, subCluster: h.subCluster, data: h.metrics.find(m => m.name == selectedMetric && m.scope == 'node'), removed: false }
|
|
|
|
})
|
2022-06-22 11:20:57 +02:00
|
|
|
.sort((a, b) => a.host.localeCompare(b.host))}>
|
|
|
|
|
2023-03-31 17:18:16 +02:00
|
|
|
<h4 style="width: 100%; text-align: center;"><a href="/monitoring/node/{cluster}/{item.host}">{item.host} ({item.subCluster})</a></h4>
|
|
|
|
{#if item.removed == false && item.data != null}
|
|
|
|
<MetricPlot
|
|
|
|
width={width}
|
|
|
|
height={plotHeight}
|
|
|
|
timestep={item.data.metric.timestep}
|
|
|
|
series={item.data.metric.series}
|
|
|
|
metric={item.data.name}
|
|
|
|
cluster={clusters.find(c => c.name == cluster)}
|
|
|
|
subCluster={item.subCluster} />
|
|
|
|
{:else if item.removed == true && item.data == null}
|
|
|
|
<Card body color="info">Metric '{ selectedMetric }' disabled for subcluster '{ item.subCluster }'</Card>
|
|
|
|
{:else}
|
|
|
|
<Card body color="warning">Missing Data</Card>
|
|
|
|
{/if}
|
2022-06-22 11:20:57 +02:00
|
|
|
</PlotTable>
|
|
|
|
{/if}
|
|
|
|
</Col>
|
|
|
|
</Row>
|
|
|
|
|