Skip to content

Commit

Permalink
Tolerate missing metrics, use alternate metric from replica count (#475)
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Edgar <medgar@redhat.com>
  • Loading branch information
MikeEdgar authored Feb 14, 2024
1 parent 63a9fe3 commit cbf691d
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 33 deletions.
2 changes: 1 addition & 1 deletion ui/api/kafka/kpi.promql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ or
sum by (__console_metric_name__, nodeId) (
label_replace(
label_replace(
kafka_cluster_partition_replicascount{namespace="${namespace}",pod=~"${cluster}-.+-\\\\d+",strimzi_io_kind="Kafka"} > 0,
kafka_server_replicamanager_partitioncount{namespace="${namespace}",pod=~"${cluster}-.+-\\\\d+",strimzi_io_kind="Kafka"} > 0,
"nodeId",
"$1",
"pod",
Expand Down
34 changes: 17 additions & 17 deletions ui/api/kafka/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,28 +59,28 @@ export const ClusterResponse = z.object({
export type ClusterDetail = z.infer<typeof ClusterDetailSchema>;

export const ClusterKpisSchema = z.object({
broker_state: z.record(z.number()),
total_topics: z.number(),
total_partitions: z.number(),
underreplicated_topics: z.number(),
broker_state: z.record(z.number()).optional(),
total_topics: z.number().optional(),
total_partitions: z.number().optional(),
underreplicated_topics: z.number().optional(),
replica_count: z.object({
byNode: z.record(z.number()),
total: z.number(),
}),
byNode: z.record(z.number()).optional(),
total: z.number().optional(),
}).optional(),
leader_count: z.object({
byNode: z.record(z.number()),
total: z.number(),
}),
byNode: z.record(z.number()).optional(),
total: z.number().optional(),
}).optional(),
volume_stats_capacity_bytes: z.object({
byNode: z.record(z.number()),
total: z.number(),
}),
byNode: z.record(z.number()).optional(),
total: z.number().optional(),
}).optional(),
volume_stats_used_bytes: z.object({
byNode: z.record(z.number()),
total: z.number(),
}),
byNode: z.record(z.number()).optional(),
total: z.number().optional(),
}).optional(),
});
export type ClusterKpis = z.infer<typeof ClusterKpisSchema>;

export const MetricRangeSchema = z.record(z.string(), z.record(z.number()));
export const MetricRangeSchema = z.record(z.string(), z.record(z.number()).optional());
export type MetricRange = z.infer<typeof MetricRangeSchema>;
14 changes: 9 additions & 5 deletions ui/app/[locale]/kafka/[kafkaId]/nodes/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import {
import { PageSection } from "@/libs/patternfly/react-core";
import { redirect } from "@/navigation";

function nodeMetric(metrics: Record<string, number> | undefined, nodeId: number): number {
return metrics ? (metrics[nodeId.toString()] ?? 0) : 0;
}

export default async function NodesPage({ params }: { params: KafkaParams }) {
const res = await getKafkaClusterKpis(params.kafkaId);
if (!res) {
Expand All @@ -20,11 +24,11 @@ export default async function NodesPage({ params }: { params: KafkaParams }) {
}

const nodes: Node[] = cluster.attributes.nodes.map((node) => {
const status = kpis.broker_state[node.id] === 3 ? "Stable" : "Unstable";
const leaders = kpis.leader_count.byNode[node.id];
const followers = kpis.replica_count.byNode[node.id] - leaders;
const diskCapacity = kpis.volume_stats_capacity_bytes.byNode[node.id];
const diskUsage = kpis.volume_stats_used_bytes.byNode[node.id];
const status = nodeMetric(kpis.broker_state, node.id) === 3 ? "Stable" : "Unstable";
const leaders = nodeMetric(kpis.leader_count?.byNode, node.id);
const followers = nodeMetric(kpis.replica_count?.byNode, node.id) - leaders;
const diskCapacity = nodeMetric(kpis.volume_stats_capacity_bytes?.byNode, node.id);
const diskUsage = nodeMetric(kpis.volume_stats_used_bytes?.byNode, node.id);
return {
id: node.id,
status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import { useFormatter } from "next-intl";
import { useChartWidth } from "./useChartWidth";

type ChartIncomingOutgoingProps = {
incoming: Record<string, TimeSeriesMetrics>;
outgoing: Record<string, TimeSeriesMetrics>;
incoming: Record<string, TimeSeriesMetrics | undefined>;
outgoing: Record<string, TimeSeriesMetrics | undefined>;
};

type Datum = {
Expand All @@ -42,7 +42,7 @@ export function ChartIncomingOutgoing({
const hasMetrics =
Object.keys(incoming).length > 0 && Object.keys(outgoing).length > 0;
if (!hasMetrics) {
return <div>TODO</div>;
return <div><i>Not available</i></div>;
}
// const showDate = shouldShowDate(duration);
const CursorVoronoiContainer = createContainer("voronoi", "cursor");
Expand Down Expand Up @@ -124,7 +124,7 @@ export function ChartIncomingOutgoing({
/>
<ChartGroup>
{Object.entries(incoming).map(([name, entries], idx) => {
const entriesArray = Object.entries(entries);
const entriesArray = Object.entries(entries ?? {});
return (
<ChartArea
key={`incoming-line-${name}}`}
Expand All @@ -140,8 +140,8 @@ export function ChartIncomingOutgoing({
);
})}
{Object.entries(outgoing).map(([name, entries], idx) => {
const entriesArray = Object.entries(entries);
const incomingArray = Object.keys(incoming[name]);
const entriesArray = Object.entries(entries ?? {});
const incomingArray = Object.keys(incoming[name] ?? {});
return (
<ChartArea
key={`outgoing-line-${name}}`}
Expand Down
12 changes: 8 additions & 4 deletions ui/app/[locale]/kafka/[kafkaId]/overview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ async function ConnectedTopicsPartitionsCard({
);
}

function timeSeriesMetrics(ranges: Record<ClusterMetric, MetricRange> | undefined, rangeName: ClusterMetric) : TimeSeriesMetrics[] {
return ranges ? Object.values(ranges[rangeName] ?? {}).map(val => val ?? {}) : [];
}

async function ConnectedClusterChartsCard({
data,
}: {
Expand All @@ -112,10 +116,10 @@ async function ConnectedClusterChartsCard({
<>
<ClusterChartsCard
isLoading={false}
usedDiskSpace={Object.values(res?.ranges["volumeUsed"] || {})}
availableDiskSpace={Object.values(res?.ranges["volumeCapacity"] || {})}
memoryUsage={Object.values(res?.ranges["memory"] || {})}
cpuUsage={Object.values(res?.ranges["cpu"] || {})}
usedDiskSpace={ timeSeriesMetrics(res?.ranges, "volumeUsed") }
availableDiskSpace={ timeSeriesMetrics(res?.ranges, "volumeCapacity") }
memoryUsage={ timeSeriesMetrics(res?.ranges, "memory") }
cpuUsage={ timeSeriesMetrics(res?.ranges, "cpu") }
/>
</>
);
Expand Down

0 comments on commit cbf691d

Please sign in to comment.