refactor(ui): server metrics page uses global time range
Drop the page-local DS Select window picker. Drive from() / to() off
useGlobalFilters().timeRange so the dashboard tracks the same TopBar range
as Exchanges / Dashboard / Runtime. Bucket size auto-scales via
stepSecondsFor(windowSeconds) (10 s for ≤30 min → 1 h for >48 h). Query
hooks now take ServerMetricsRange = { from: Date; to: Date } instead of a
windowSeconds number, so they support arbitrary absolute or rolling ranges
the TopBar may supply (not just "now − N"). Toolbar collapses to just the
server-instance badges.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,7 @@ The UI has 4 main tabs: **Exchanges**, **Dashboard**, **Runtime**, **Deployments
|
|||||||
|
|
||||||
**Admin pages** (ADMIN-only, under `/admin/`):
|
**Admin pages** (ADMIN-only, under `/admin/`):
|
||||||
- **Sensitive Keys** (`ui/src/pages/Admin/SensitiveKeysPage.tsx`) — global sensitive key masking config. Shows agent built-in defaults as outlined Badge reference, editable Tag pills for custom keys, amber-highlighted push-to-agents toggle. Keys add to (not replace) agent defaults. Per-app sensitive key additions managed via `ApplicationConfigController` API. Note: `AppConfigDetailPage.tsx` exists but is not routed in `router.tsx`.
|
- **Sensitive Keys** (`ui/src/pages/Admin/SensitiveKeysPage.tsx`) — global sensitive key masking config. Shows agent built-in defaults as outlined Badge reference, editable Tag pills for custom keys, amber-highlighted push-to-agents toggle. Keys add to (not replace) agent defaults. Per-app sensitive key additions managed via `ApplicationConfigController` API. Note: `AppConfigDetailPage.tsx` exists but is not routed in `router.tsx`.
|
||||||
- **Server Metrics** (`ui/src/pages/Admin/ServerMetricsAdminPage.tsx`) — dashboard over the `server_metrics` ClickHouse table. Visibility matches Database/ClickHouse pages: gated on `capabilities.infrastructureEndpoints` in `buildAdminTreeNodes`; backend is `@ConditionalOnProperty(infrastructureendpoints) + @PreAuthorize('hasRole(ADMIN)')`. Uses the generic `/api/v1/admin/server-metrics/{catalog,instances,query}` API via `ui/src/api/queries/admin/serverMetrics.ts` hooks (`useServerMetricsCatalog`, `useServerMetricsInstances`, `useServerMetricsSeries`). Toolbar: server-instance badges + DS `Select` window picker (15 min / 1 h / 6 h / 24 h / 7 d). Sections: Server health (agents/ingestion/auth), JVM (memory/CPU/GC/threads), HTTP & DB pools, Alerting (conditional on catalog), Deployments (conditional on catalog). Each panel is a `ThemedChart` with `Line`/`Area` children from the design system; multi-series responses are flattened into overlap rows by bucket timestamp. Alerting and Deployments rows are hidden when their metrics aren't in the catalog (zero-deploy / alerting-disabled installs).
|
- **Server Metrics** (`ui/src/pages/Admin/ServerMetricsAdminPage.tsx`) — dashboard over the `server_metrics` ClickHouse table. Visibility matches Database/ClickHouse pages: gated on `capabilities.infrastructureEndpoints` in `buildAdminTreeNodes`; backend is `@ConditionalOnProperty(infrastructureendpoints) + @PreAuthorize('hasRole(ADMIN)')`. Uses the generic `/api/v1/admin/server-metrics/{catalog,instances,query}` API via `ui/src/api/queries/admin/serverMetrics.ts` hooks (`useServerMetricsCatalog`, `useServerMetricsInstances`, `useServerMetricsSeries`), all three of which take a `ServerMetricsRange = { from: Date; to: Date }`. Time range is driven by the global TopBar picker via `useGlobalFilters()` — no page-local selector; bucket size auto-scales through `stepSecondsFor(windowSeconds)` (10 s up to 1 h buckets). Toolbar is just server-instance badges. Sections: Server health (agents/ingestion/auth), JVM (memory/CPU/GC/threads), HTTP & DB pools, Alerting (conditional on catalog), Deployments (conditional on catalog). Each panel is a `ThemedChart` with `Line`/`Area` children from the design system; multi-series responses are flattened into overlap rows by bucket timestamp. Alerting and Deployments rows are hidden when their metrics aren't in the catalog (zero-deploy / alerting-disabled installs).
|
||||||
|
|
||||||
## Key UI Files
|
## Key UI Files
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ This is the reference for anyone building a server-health dashboard on top of th
|
|||||||
|
|
||||||
## Built-in admin dashboard
|
## Built-in admin dashboard
|
||||||
|
|
||||||
The server ships a ready-to-use dashboard at **`/admin/server-metrics`** in the web UI. It renders the 17 panels listed below using `ThemedChart` from the design system, with a time-range selector (15 min / 1 h / 6 h / 24 h / 7 d) and live auto-refresh. Visibility mirrors the Database and ClickHouse admin pages:
|
The server ships a ready-to-use dashboard at **`/admin/server-metrics`** in the web UI. It renders the 17 panels listed below using `ThemedChart` from the design system. The window is driven by the app-wide time-range control in the TopBar (same one used by Exchanges, Dashboard, and Runtime), so every panel automatically reflects the range you've selected globally. Visibility mirrors the Database and ClickHouse admin pages:
|
||||||
|
|
||||||
- Requires the `ADMIN` role.
|
- Requires the `ADMIN` role.
|
||||||
- Hidden when `cameleer.server.security.infrastructureendpoints=false` (both the backend endpoints and the sidebar entry disappear).
|
- Hidden when `cameleer.server.security.infrastructureendpoints=false` (both the backend endpoints and the sidebar entry disappear).
|
||||||
@@ -519,3 +519,4 @@ Below are 17 panels, each expressed as a single `POST /api/v1/admin/server-metri
|
|||||||
- 2026-04-23 — initial write. Write-only backend.
|
- 2026-04-23 — initial write. Write-only backend.
|
||||||
- 2026-04-23 — added generic REST API (`/api/v1/admin/server-metrics/{catalog,instances,query}`) so dashboards don't need direct ClickHouse access. All 17 suggested panels now expressed as single-endpoint queries.
|
- 2026-04-23 — added generic REST API (`/api/v1/admin/server-metrics/{catalog,instances,query}`) so dashboards don't need direct ClickHouse access. All 17 suggested panels now expressed as single-endpoint queries.
|
||||||
- 2026-04-24 — shipped the built-in `/admin/server-metrics` UI dashboard. Gated by `infrastructureendpoints` + ADMIN, identical visibility to `/admin/{database,clickhouse}`. Source: `ui/src/pages/Admin/ServerMetricsAdminPage.tsx`.
|
- 2026-04-24 — shipped the built-in `/admin/server-metrics` UI dashboard. Gated by `infrastructureendpoints` + ADMIN, identical visibility to `/admin/{database,clickhouse}`. Source: `ui/src/pages/Admin/ServerMetricsAdminPage.tsx`.
|
||||||
|
- 2026-04-24 — dashboard now uses the global time-range control (`useGlobalFilters`) instead of a page-local picker. Bucket size auto-scales with the selected window (10 s → 1 h). Query hooks now take a `ServerMetricsRange = { from: Date; to: Date }` instead of a `windowSeconds` number so they work for any absolute or rolling range the TopBar supplies.
|
||||||
|
|||||||
@@ -49,30 +49,47 @@ export interface ServerMetricQueryRequest {
|
|||||||
serverInstanceIds?: string[] | null;
|
serverInstanceIds?: string[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Range helper ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time range driving every hook below. Callers pass the window they want
|
||||||
|
* to render; the hooks never invent their own "now" — that's the job of
|
||||||
|
* the global time-range control.
|
||||||
|
*/
|
||||||
|
export interface ServerMetricsRange {
|
||||||
|
from: Date;
|
||||||
|
to: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeRange(range: ServerMetricsRange) {
|
||||||
|
return {
|
||||||
|
from: range.from.toISOString(),
|
||||||
|
to: range.to.toISOString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// ── Query Hooks ────────────────────────────────────────────────────────
|
// ── Query Hooks ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export function useServerMetricsCatalog(windowSeconds = 3600) {
|
export function useServerMetricsCatalog(range: ServerMetricsRange) {
|
||||||
const refetchInterval = useRefreshInterval(60_000);
|
const refetchInterval = useRefreshInterval(60_000);
|
||||||
|
const { from, to } = serializeRange(range);
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['admin', 'server-metrics', 'catalog', windowSeconds],
|
queryKey: ['admin', 'server-metrics', 'catalog', from, to],
|
||||||
queryFn: async () => {
|
queryFn: () => {
|
||||||
const to = new Date();
|
const params = new URLSearchParams({ from, to });
|
||||||
const from = new Date(to.getTime() - windowSeconds * 1000);
|
|
||||||
const params = new URLSearchParams({ from: from.toISOString(), to: to.toISOString() });
|
|
||||||
return adminFetch<ServerMetricCatalogEntry[]>(`/server-metrics/catalog?${params}`);
|
return adminFetch<ServerMetricCatalogEntry[]>(`/server-metrics/catalog?${params}`);
|
||||||
},
|
},
|
||||||
refetchInterval,
|
refetchInterval,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useServerMetricsInstances(windowSeconds = 3600) {
|
export function useServerMetricsInstances(range: ServerMetricsRange) {
|
||||||
const refetchInterval = useRefreshInterval(60_000);
|
const refetchInterval = useRefreshInterval(60_000);
|
||||||
|
const { from, to } = serializeRange(range);
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['admin', 'server-metrics', 'instances', windowSeconds],
|
queryKey: ['admin', 'server-metrics', 'instances', from, to],
|
||||||
queryFn: async () => {
|
queryFn: () => {
|
||||||
const to = new Date();
|
const params = new URLSearchParams({ from, to });
|
||||||
const from = new Date(to.getTime() - windowSeconds * 1000);
|
|
||||||
const params = new URLSearchParams({ from: from.toISOString(), to: to.toISOString() });
|
|
||||||
return adminFetch<ServerInstanceInfo[]>(`/server-metrics/instances?${params}`);
|
return adminFetch<ServerInstanceInfo[]>(`/server-metrics/instances?${params}`);
|
||||||
},
|
},
|
||||||
refetchInterval,
|
refetchInterval,
|
||||||
@@ -80,28 +97,23 @@ export function useServerMetricsInstances(windowSeconds = 3600) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run a time-series query against the server_metrics table.
|
* Generic time-series query against the server_metrics table.
|
||||||
*
|
*
|
||||||
* The window [from, to) is supplied in seconds of "now minus N" so the panel
|
* The caller owns the window — passing the globally-selected range keeps
|
||||||
* refreshes automatically at the polling interval without the caller
|
* every panel aligned with the app-wide time control and allows inspection
|
||||||
* recomputing timestamps.
|
* of historical windows, not just "last N seconds from now".
|
||||||
*/
|
*/
|
||||||
export function useServerMetricsSeries(
|
export function useServerMetricsSeries(
|
||||||
request: Omit<ServerMetricQueryRequest, 'from' | 'to'>,
|
request: Omit<ServerMetricQueryRequest, 'from' | 'to'>,
|
||||||
windowSeconds: number,
|
range: ServerMetricsRange,
|
||||||
opts?: { enabled?: boolean },
|
opts?: { enabled?: boolean },
|
||||||
) {
|
) {
|
||||||
const refetchInterval = useRefreshInterval(30_000);
|
const refetchInterval = useRefreshInterval(30_000);
|
||||||
|
const { from, to } = serializeRange(range);
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['admin', 'server-metrics', 'query', request, windowSeconds],
|
queryKey: ['admin', 'server-metrics', 'query', request, from, to],
|
||||||
queryFn: async () => {
|
queryFn: () => {
|
||||||
const to = new Date();
|
const body: ServerMetricQueryRequest = { ...request, from, to };
|
||||||
const from = new Date(to.getTime() - windowSeconds * 1000);
|
|
||||||
const body: ServerMetricQueryRequest = {
|
|
||||||
...request,
|
|
||||||
from: from.toISOString(),
|
|
||||||
to: to.toISOString(),
|
|
||||||
};
|
|
||||||
return adminFetch<ServerMetricQueryResponse>('/server-metrics/query', {
|
return adminFetch<ServerMetricQueryResponse>('/server-metrics/query', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useMemo, useState } from 'react';
|
import { useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
ThemedChart, Area, Line, CHART_COLORS,
|
ThemedChart, Area, Line, CHART_COLORS,
|
||||||
Badge, EmptyState, Spinner, Select,
|
Badge, EmptyState, Spinner, useGlobalFilters,
|
||||||
} from '@cameleer/design-system';
|
} from '@cameleer/design-system';
|
||||||
import {
|
import {
|
||||||
useServerMetricsCatalog,
|
useServerMetricsCatalog,
|
||||||
@@ -9,19 +9,28 @@ import {
|
|||||||
useServerMetricsSeries,
|
useServerMetricsSeries,
|
||||||
type ServerMetricQueryResponse,
|
type ServerMetricQueryResponse,
|
||||||
type ServerMetricSeries,
|
type ServerMetricSeries,
|
||||||
|
type ServerMetricsRange,
|
||||||
} from '../../api/queries/admin/serverMetrics';
|
} from '../../api/queries/admin/serverMetrics';
|
||||||
import chartCardStyles from '../../styles/chart-card.module.css';
|
import chartCardStyles from '../../styles/chart-card.module.css';
|
||||||
import styles from './ServerMetricsAdminPage.module.css';
|
import styles from './ServerMetricsAdminPage.module.css';
|
||||||
|
|
||||||
// ── Window options ─────────────────────────────────────────────────────
|
// ── Step picker ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const WINDOWS: { label: string; seconds: number; step: number }[] = [
|
/**
|
||||||
{ label: 'Last 15 min', seconds: 15 * 60, step: 60 },
|
* Choose a bucket width that keeps the rendered series readable regardless
|
||||||
{ label: 'Last 1 h', seconds: 60 * 60, step: 60 },
|
* of the window size the global time-range control hands us.
|
||||||
{ label: 'Last 6 h', seconds: 6 * 60 * 60, step: 300 },
|
*
|
||||||
{ label: 'Last 24 h', seconds: 24 * 60 * 60, step: 300 },
|
* Targets roughly 30–120 points per series — any denser and the chart
|
||||||
{ label: 'Last 7 d', seconds: 7 * 24 * 60 * 60, step: 3600 },
|
* becomes a blur; any sparser and short windows look empty. Clamped to the
|
||||||
];
|
* [10, 3600] range the backend accepts.
|
||||||
|
*/
|
||||||
|
function stepSecondsFor(windowSeconds: number): number {
|
||||||
|
if (windowSeconds <= 30 * 60) return 10; // ≤ 30 min → 10 s buckets
|
||||||
|
if (windowSeconds <= 2 * 60 * 60) return 60; // ≤ 2 h → 1 min
|
||||||
|
if (windowSeconds <= 12 * 60 * 60) return 300; // ≤ 12 h → 5 min
|
||||||
|
if (windowSeconds <= 48 * 60 * 60) return 900; // ≤ 48 h → 15 min
|
||||||
|
return 3600; // longer → 1 h
|
||||||
|
}
|
||||||
|
|
||||||
// ── Panel component ────────────────────────────────────────────────────
|
// ── Panel component ────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -36,7 +45,7 @@ interface PanelProps {
|
|||||||
mode?: 'raw' | 'delta';
|
mode?: 'raw' | 'delta';
|
||||||
yLabel?: string;
|
yLabel?: string;
|
||||||
asArea?: boolean;
|
asArea?: boolean;
|
||||||
windowSeconds: number;
|
range: ServerMetricsRange;
|
||||||
stepSeconds: number;
|
stepSeconds: number;
|
||||||
formatValue?: (v: number) => string;
|
formatValue?: (v: number) => string;
|
||||||
}
|
}
|
||||||
@@ -44,11 +53,11 @@ interface PanelProps {
|
|||||||
function Panel({
|
function Panel({
|
||||||
title, subtitle, metric, statistic, groupByTags, filterTags,
|
title, subtitle, metric, statistic, groupByTags, filterTags,
|
||||||
aggregation, mode = 'raw', yLabel, asArea = false,
|
aggregation, mode = 'raw', yLabel, asArea = false,
|
||||||
windowSeconds, stepSeconds, formatValue,
|
range, stepSeconds, formatValue,
|
||||||
}: PanelProps) {
|
}: PanelProps) {
|
||||||
const { data, isLoading, isError, error } = useServerMetricsSeries(
|
const { data, isLoading, isError, error } = useServerMetricsSeries(
|
||||||
{ metric, statistic, groupByTags, filterTags, aggregation, mode, stepSeconds },
|
{ metric, statistic, groupByTags, filterTags, aggregation, mode, stepSeconds },
|
||||||
windowSeconds,
|
range,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -157,20 +166,28 @@ function formatPct(frac: number): string {
|
|||||||
// ── Page ───────────────────────────────────────────────────────────────
|
// ── Page ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export default function ServerMetricsAdminPage() {
|
export default function ServerMetricsAdminPage() {
|
||||||
const [windowIdx, setWindowIdx] = useState(1); // default: last 1 h
|
// Drive the entire page from the global time-range control in the TopBar.
|
||||||
const windowOpt = WINDOWS[windowIdx];
|
const { timeRange } = useGlobalFilters();
|
||||||
const windowSeconds = windowOpt.seconds;
|
const range: ServerMetricsRange = useMemo(
|
||||||
const stepSeconds = windowOpt.step;
|
() => ({ from: timeRange.start, to: timeRange.end }),
|
||||||
|
[timeRange.start, timeRange.end],
|
||||||
|
);
|
||||||
|
const windowSeconds = Math.max(
|
||||||
|
1,
|
||||||
|
Math.round((range.to.getTime() - range.from.getTime()) / 1000),
|
||||||
|
);
|
||||||
|
const stepSeconds = stepSecondsFor(windowSeconds);
|
||||||
|
|
||||||
const { data: catalog } = useServerMetricsCatalog(windowSeconds);
|
const { data: catalog } = useServerMetricsCatalog(range);
|
||||||
const { data: instances } = useServerMetricsInstances(windowSeconds);
|
const { data: instances } = useServerMetricsInstances(range);
|
||||||
|
|
||||||
const has = (metricName: string) =>
|
const has = (metricName: string) =>
|
||||||
(catalog ?? []).some((c) => c.metricName === metricName);
|
(catalog ?? []).some((c) => c.metricName === metricName);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.page}>
|
<div className={styles.page}>
|
||||||
{/* Toolbar */}
|
{/* Toolbar — just server-instance badges. Time range is driven by
|
||||||
|
the global time-range control in the TopBar. */}
|
||||||
<div className={styles.toolbar}>
|
<div className={styles.toolbar}>
|
||||||
<div className={styles.instanceStrip}>
|
<div className={styles.instanceStrip}>
|
||||||
{(instances ?? []).slice(0, 8).map((i) => (
|
{(instances ?? []).slice(0, 8).map((i) => (
|
||||||
@@ -183,11 +200,6 @@ export default function ServerMetricsAdminPage() {
|
|||||||
<Badge label="no samples in window" variant="outlined" />
|
<Badge label="no samples in window" variant="outlined" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Select
|
|
||||||
value={String(windowIdx)}
|
|
||||||
onChange={(e) => setWindowIdx(Number(e.target.value))}
|
|
||||||
options={WINDOWS.map((w, i) => ({ value: String(i), label: w.label }))}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Row 1: Server health */}
|
{/* Row 1: Server health */}
|
||||||
@@ -205,7 +217,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
groupByTags={['state']}
|
groupByTags={['state']}
|
||||||
aggregation="avg"
|
aggregation="avg"
|
||||||
asArea
|
asArea
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
<Panel
|
<Panel
|
||||||
@@ -215,7 +227,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="value"
|
statistic="value"
|
||||||
groupByTags={['type']}
|
groupByTags={['type']}
|
||||||
aggregation="avg"
|
aggregation="avg"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -227,7 +239,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="count"
|
statistic="count"
|
||||||
groupByTags={['reason']}
|
groupByTags={['reason']}
|
||||||
mode="delta"
|
mode="delta"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
<Panel
|
<Panel
|
||||||
@@ -237,7 +249,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="count"
|
statistic="count"
|
||||||
groupByTags={['reason']}
|
groupByTags={['reason']}
|
||||||
mode="delta"
|
mode="delta"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -260,7 +272,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
asArea
|
asArea
|
||||||
yLabel="MB"
|
yLabel="MB"
|
||||||
formatValue={formatMB}
|
formatValue={formatMB}
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
<Panel
|
<Panel
|
||||||
@@ -272,7 +284,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
asArea
|
asArea
|
||||||
yLabel="%"
|
yLabel="%"
|
||||||
formatValue={formatPct}
|
formatValue={formatPct}
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
<Panel
|
<Panel
|
||||||
@@ -282,7 +294,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="max"
|
statistic="max"
|
||||||
groupByTags={['cause']}
|
groupByTags={['cause']}
|
||||||
aggregation="max"
|
aggregation="max"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -293,7 +305,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
metric="jvm.threads.live"
|
metric="jvm.threads.live"
|
||||||
statistic="value"
|
statistic="value"
|
||||||
aggregation="avg"
|
aggregation="avg"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
<Panel
|
<Panel
|
||||||
@@ -305,7 +317,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
aggregation="sum"
|
aggregation="sum"
|
||||||
yLabel="MB"
|
yLabel="MB"
|
||||||
formatValue={formatMB}
|
formatValue={formatMB}
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -327,7 +339,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
filterTags={{ outcome: 'SUCCESS' }}
|
filterTags={{ outcome: 'SUCCESS' }}
|
||||||
aggregation="avg"
|
aggregation="avg"
|
||||||
yLabel="s"
|
yLabel="s"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
<Panel
|
<Panel
|
||||||
@@ -337,7 +349,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="count"
|
statistic="count"
|
||||||
mode="delta"
|
mode="delta"
|
||||||
aggregation="sum"
|
aggregation="sum"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
<Panel
|
<Panel
|
||||||
@@ -347,7 +359,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="value"
|
statistic="value"
|
||||||
groupByTags={['pool']}
|
groupByTags={['pool']}
|
||||||
aggregation="avg"
|
aggregation="avg"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -359,7 +371,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="count"
|
statistic="count"
|
||||||
groupByTags={['pool']}
|
groupByTags={['pool']}
|
||||||
mode="delta"
|
mode="delta"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
<Panel
|
<Panel
|
||||||
@@ -369,7 +381,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="count"
|
statistic="count"
|
||||||
groupByTags={['level']}
|
groupByTags={['level']}
|
||||||
mode="delta"
|
mode="delta"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -394,7 +406,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
groupByTags={['state']}
|
groupByTags={['state']}
|
||||||
aggregation="avg"
|
aggregation="avg"
|
||||||
asArea
|
asArea
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -406,7 +418,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="count"
|
statistic="count"
|
||||||
groupByTags={['kind']}
|
groupByTags={['kind']}
|
||||||
mode="delta"
|
mode="delta"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -418,7 +430,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="max"
|
statistic="max"
|
||||||
aggregation="max"
|
aggregation="max"
|
||||||
yLabel="s"
|
yLabel="s"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -442,7 +454,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="count"
|
statistic="count"
|
||||||
groupByTags={['status']}
|
groupByTags={['status']}
|
||||||
mode="delta"
|
mode="delta"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -454,7 +466,7 @@ export default function ServerMetricsAdminPage() {
|
|||||||
statistic="mean"
|
statistic="mean"
|
||||||
aggregation="avg"
|
aggregation="avg"
|
||||||
yLabel="s"
|
yLabel="s"
|
||||||
windowSeconds={windowSeconds}
|
range={range}
|
||||||
stepSeconds={stepSeconds}
|
stepSeconds={stepSeconds}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user