Skip to content

Commit

Permalink
feat: add /disks page
Browse files Browse the repository at this point in the history
  • Loading branch information
duyet committed Nov 23, 2023
1 parent 00384d7 commit 4ee4be8
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 34 deletions.
69 changes: 68 additions & 1 deletion app/[name]/clickhouse-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export const queries: Array<QueryConfig> = [
(normalized_query_hash),
())
ORDER BY user_time DESC
LIMIT 200
LIMIT 1000
`,
columns: [
'query',
Expand Down Expand Up @@ -184,6 +184,37 @@ export const queries: Array<QueryConfig> = [
},
relatedCharts: [],
},
{
name: 'expensive-queries-by-memory',
description: 'Most expensive queries by memory finished over last 24 hours',
sql: `
SELECT
query,
user,
count() as cnt,
sum(memory_usage) AS memory,
formatReadableSize(sum(memory_usage)) AS readable_memory,
normalized_query_hash
FROM
clusterAllReplicas(default, system.query_log)
WHERE
(event_time >= (now() - toIntervalDay(1)))
AND query_kind = 'Select'
AND type = 'QueryFinish'
GROUP BY
normalized_query_hash,
query,
user
ORDER BY
memory DESC
LIMIT 1000
`,

columns: ['query', 'user', 'cnt', 'readable_memory'],
columnFormats: {
query: ColumnFormat.CodeToggle,
},
},
{
name: 'merges',
sql: `
Expand Down Expand Up @@ -279,6 +310,42 @@ export const queries: Array<QueryConfig> = [
value: ColumnFormat.Code,
},
},
{
name: 'disks',
sql: `
SELECT name,
path,
unreserved_space,
formatReadableSize(unreserved_space) AS readable_unreserved_space,
free_space,
formatReadableSize(free_space) AS readable_free_space,
total_space,
formatReadableSize(total_space) AS readable_total_space,
toString(round(100.0 * free_space / total_space, 2)) || '%' AS percent_free,
keep_free_space
FROM system.disks
ORDER BY name
`,
columns: [
'name',
'path',
'readable_unreserved_space',
'readable_free_space',
'percent_free',
'readable_total_space',
'keep_free_space',
],
relatedCharts: [
[
'disks-usage',
{
title: 'Disk Usage over last 14 days',
interval: 'toStartOfTenMinutes',
lastHours: 24 * 14,
},
],
],
},
]

export const getQueryConfigByName = (name: string) => {
Expand Down
29 changes: 19 additions & 10 deletions app/[name]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { notFound } from 'next/navigation'

import { fetchData } from '@/lib/clickhouse'
import { DataTable } from '@/components/data-table/data-table'
import { ErrorAlert } from '@/components/error-alert'
import { RelatedCharts } from '@/components/related-charts'

import { getQueryConfigByName, queries } from './clickhouse-queries'
Expand All @@ -26,17 +27,25 @@ export default async function Page({ params: { name } }: PageProps) {
}

// Fetch the data from ClickHouse
const data = await fetchData(config.sql)

return (
<div className="flex flex-col">
<RelatedCharts relatedCharts={config.relatedCharts} />

<div>
<DataTable title={name.replace('-', ' ')} config={config} data={data} />
try {
const data = await fetchData(config.sql)

return (
<div className="flex flex-col">
<RelatedCharts relatedCharts={config.relatedCharts} />

<div>
<DataTable
title={name.replace('-', ' ')}
config={config}
data={data}
/>
</div>
</div>
</div>
)
)
} catch (error) {
return <ErrorAlert title="ClickHouse Error" message={`${error}`} />
}
}

export const generateStaticParams = async () =>
Expand Down
2 changes: 1 addition & 1 deletion app/error.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('<Error />', () => {
// Render
cy.mount(<ErrorPage error={err} reset={reset} />)

cy.get('h2').contains('Something went wrong').should('be.visible')
cy.contains('Something went wrong').should('be.visible')

// Check console.log was called
cy.window().then((win) => {
Expand Down
20 changes: 6 additions & 14 deletions app/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useEffect } from 'react'

import { Button } from '@/components/ui/button'
import { ErrorAlert } from '@/components/error-alert'

export default function Error({
error,
Expand All @@ -17,18 +17,10 @@ export default function Error({
}, [error])

return (
<div>
<h2 className="font-medium">Something went wrong!</h2>
<p className="mb-5 font-light">Checking console for more details.</p>
<Button
variant="outline"
onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}
>
Try again
</Button>
</div>
<ErrorAlert
title="Something went wrong"
message="Checking console for more details."
reset={reset}
/>
)
}
11 changes: 9 additions & 2 deletions app/overview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { unstable_noStore as noStore } from 'next/cache'

import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { ChartAvgMemory } from '@/components/charts/avg-memory'
import ChartMergeCount from '@/components/charts/merge-count'
import { ChartDisksUsage } from '@/components/charts/disks-usage'
import { ChartMergeCount } from '@/components/charts/merge-count'
import { ChartQueryCountByUser } from '@/components/charts/query-count-by-user'
import ChartTopTableSize from '@/components/charts/top-table-size'
import { ChartTopTableSize } from '@/components/charts/top-table-size'
import { IntervalSelect } from '@/components/interval-select'

export const dynamic = 'force-dynamic'
Expand Down Expand Up @@ -45,6 +46,12 @@ export default async function Overview() {
chartClassName="h-72"
/>
<ChartTopTableSize className="w-full p-5" />
<ChartDisksUsage
title="Disks Usage over last 14 days"
className="w-full p-5"
interval="toStartOfTenMinutes"
lastHours={24 * 14}
/>
</div>
</TabsContent>
</Tabs>
Expand Down
41 changes: 41 additions & 0 deletions components/charts/disks-usage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { fetchData } from '@/lib/clickhouse'
import { cn } from '@/lib/utils'
import { ChartCard } from '@/components/chart-card'
import type { ChartProps } from '@/components/charts/chart-props'
import { AreaChart } from '@/components/tremor'

export async function ChartDisksUsage({
title,
interval = 'toStartOfHour',
className,
chartClassName,
lastHours = 24 * 7,
...props
}: ChartProps) {
const data = await fetchData(`
WITH CAST(sumMap(map(metric, value)), 'Map(LowCardinality(String), UInt32)') AS map
SELECT
${interval}(event_time) as event_time,
map['DiskAvailable_default'] as DiskAvailable_default,
formatReadableSize(DiskAvailable_default) as readable_DiskAvailable_default
FROM system.asynchronous_metric_log
WHERE event_time >= (now() - INTERVAL ${lastHours} HOUR)
GROUP BY 1
ORDER BY 1 ASC
`)

return (
<ChartCard title={title} className={className}>
<AreaChart
className={cn('h-52', chartClassName)}
data={data}
index="event_time"
categories={['DiskAvailable_default']}
readableColumns={['readable_DiskAvailable_default']}
{...props}
/>
</ChartCard>
)
}

export default ChartDisksUsage
4 changes: 2 additions & 2 deletions components/charts/merge-count.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ChartCard } from '@/components/chart-card'
import type { ChartProps } from '@/components/charts/chart-props'
import { AreaChart } from '@/components/tremor'

export async function ChartMergeCountSpark({
export async function ChartMergeCount({
title,
interval = 'toStartOfFiveMinutes',
lastHours = 12,
Expand Down Expand Up @@ -38,4 +38,4 @@ export async function ChartMergeCountSpark({
)
}

export default ChartMergeCountSpark
export default ChartMergeCount
4 changes: 2 additions & 2 deletions components/charts/query-count.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ChartCard } from '@/components/chart-card'
import type { ChartProps } from '@/components/charts/chart-props'
import { AreaChart } from '@/components/tremor'

export async function ChartQueryCountSpark({
export async function ChartQueryCount({
title,
interval = 'toStartOfMinute',
className,
Expand Down Expand Up @@ -37,4 +37,4 @@ export async function ChartQueryCountSpark({
)
}

export default ChartQueryCountSpark
export default ChartQueryCount
2 changes: 1 addition & 1 deletion components/count-badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export async function CountBadge({
if (!data || !data.length || !data?.[0]?.['count()']) return null

const count = data[0]['count()'] || data[0]['count'] || 0
if (count === 0) return null
if (count == 0) return null

return (
<Badge className="ml-2" variant="outline">
Expand Down
39 changes: 39 additions & 0 deletions components/error-alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react'

import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { Button } from '@/components/ui/button'

interface ErrorAlertProps {
title?: string
message?: string | React.ReactNode | React.ReactNode[]
reset?: () => void
}

export function ErrorAlert({
title = 'Something went wrong!',
message = 'Checking console for more details.',
reset,
}: ErrorAlertProps) {
return (
<Alert variant="destructive">
<AlertTitle className="text-lg">{title}</AlertTitle>
<AlertDescription>
<div className="mb-5 font-light">
<code>{message}</code>
</div>

{reset ? (
<Button
variant="outline"
onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}
>
Try again
</Button>
) : null}
</AlertDescription>
</Alert>
)
}
13 changes: 12 additions & 1 deletion components/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ const defaultItems = [
{
title: 'Most Expensive Queries',
href: '/expensive-queries',
description: 'Most expensive queries in my ClickHouse',
description: 'Most expensive queries by many factors',
},
{
title: 'Most Expensive Queries by Memory',
href: '/expensive-queries-by-memory',
description: 'Most expensive queries by memory',
},
],
},
Expand Down Expand Up @@ -81,6 +86,12 @@ const defaultItems = [
description:
'The values of merge_tree settings (for all MergeTree tables) which can be viewed in the table `system.merge_tree_settings`',
},
{
title: 'Disks',
href: '/disks',
description:
'The values of disk settings which can be viewed in the table `system.disks`',
},
],
},
]
Expand Down
Loading

0 comments on commit 4ee4be8

Please sign in to comment.