Skip to content

Commit c26221b

Browse files
committed
updating latest run and loki logs to use the new logger component and logs hook
update logs hook to handle interval logs fetching via the REST endpoint adding ansi-colors to handle error lines in the log viewer
1 parent c442d09 commit c26221b

10 files changed

Lines changed: 146 additions & 102 deletions

File tree

package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"@reduxjs/toolkit": "^2.0.1",
4343
"@shadcn/ui": "^0.0.4",
4444
"@tanstack/react-table": "^8.20.5",
45+
"ansi-colors": "^4.1.3",
4546
"axios": "^1.10.0",
4647
"class-variance-authority": "^0.7.0",
4748
"clsx": "^2.1.1",

src/components/custom/DrawerLatestRuns.tsx

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from "lucide-react"
1111
import SheetActionDialog from "@/components/sheet-action-dialog"
1212
import type { jobsTableData } from "@/features/jobsTable/interfaces"
13-
import type { ReactNode } from "react"
13+
import { ReactNode, useMemo } from "react"
1414
import jobsService from "@/services/JobsService"
1515
import { useCallback, useState } from "react"
1616
import moment from "moment"
@@ -24,6 +24,9 @@ import ScrollableList from "@/components/custom/general/ScrollableList"
2424
import { getLokiLogs } from "@/services/components/logsService"
2525
import { Label } from "@/components/ui/label"
2626
import { Loader } from "lucide"
27+
import { useSocketLogs } from "@/lib/socketUtils"
28+
import { MiscNotificationTopics } from "@/models/network"
29+
import { LiveLogViewer } from "@/components/custom/general/LogViewer"
2730

2831
export interface DrawerLatestRunsProps {
2932
JobDetails: jobsTableData
@@ -35,6 +38,9 @@ export default function DrawerLatestRuns({
3538
trigger,
3639
}: DrawerLatestRunsProps) {
3740
const [LogItems, setLogItems] = useState<JobRunLog[]>([])
41+
const [selectedLogItem, setSelectedLogItem] = useState<any | undefined>(
42+
undefined,
43+
)
3844
const [itemsTotal, setItemstotal] = useState(0)
3945
const [inputSchema, setInputSchema] = useState<JobRunsQuerySchema>({
4046
jobId: JobDetails.id,
@@ -43,7 +49,21 @@ export default function DrawerLatestRuns({
4349
})
4450
const [loading, setLoading] = useState(false)
4551
const [showLogs, setShowLogs] = useState(false)
46-
const [logLines, setLogLines] = useState<any[]>([])
52+
53+
const { logs } = useSocketLogs({
54+
actions: [],
55+
format: (stream: any) => {
56+
stream.values.forEach((log: any) => {
57+
log.fullMessage = `${log.timestamp} | ${log.type?.toUpperCase()} | ${log.message}`
58+
})
59+
return stream
60+
},
61+
initialLogsFilter: selectedLogItem?.filterRange,
62+
logInterval: undefined,
63+
mergeOutputStreams: false,
64+
setEndToMidnight: false,
65+
logQuery: `{logId="${selectedLogItem?.log_id}"}`,
66+
})
4767

4868
const resetDrawer = useCallback(() => {
4969
setLogItems([])
@@ -54,7 +74,6 @@ export default function DrawerLatestRuns({
5474
})
5575
setLoading(false)
5676
setShowLogs(false)
57-
setLogLines([])
5877
}, [inputSchema])
5978

6079
const getLatestRuns = useCallback(() => {
@@ -72,6 +91,13 @@ export default function DrawerLatestRuns({
7291
? moment(log.start_time).format("YYYY-MM-DD HH-mm")
7392
: moment(log.start_time).fromNow()
7493
log.start_time_title = `Start time : ${moment(log.start_time).format("YYYY-MM-DD HH-mm-ss")}`
94+
log.offsettedStartedTime = log.offsettedEndTime = new Date(
95+
log.end_time.getTime(),
96+
)
97+
log.filterRange = {
98+
from: new Date(log.start_time.getTime()),
99+
to: new Date(log.end_time.getTime()),
100+
}
75101
})
76102
return data
77103
})
@@ -95,16 +121,8 @@ export default function DrawerLatestRuns({
95121

96122
const openAndFetchLogs = useCallback((LogItem: JobRunLog) => {
97123
if (LogItem && LogItem.end_time) {
98-
const offsetStartTime = new Date(LogItem.start_time.getTime())
99-
const offsetEndTime = new Date(LogItem.end_time.getTime())
124+
setSelectedLogItem(LogItem)
100125
setShowLogs(true)
101-
return getLokiLogs(
102-
`{logId="${LogItem.log_id}"}`,
103-
offsetStartTime,
104-
offsetEndTime,
105-
).then(data => {
106-
setLogLines(data)
107-
})
108126
}
109127
}, [])
110128

@@ -139,12 +157,10 @@ export default function DrawerLatestRuns({
139157
>
140158
<ScrollableList
141159
originalList={LogItems}
142-
loadMore={(inputSchema.offset ?? 0) <= itemsTotal}
160+
loadMore={!loading && (inputSchema.offset ?? 0) <= itemsTotal}
143161
loadMoreAction={getMoreRuns}
144162
className="px-[1px] py-[2px] min-w-[280px]"
145-
onItemClick={(item: JobRunLog, index: number) => {
146-
openAndFetchLogs(item)
147-
}}
163+
onItemClick={openAndFetchLogs}
148164
itemClassName={(item: any) => {
149165
return cn(
150166
"focus:rounded-lg outline-none focus:ring-2 focus:ring-opacity-50 focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-opacity-50 hover:ring-2 hover:ring-opacity-50 hover:rounded-lg focus:ring-blue-500 focus-visible:ring-blue-500 hover:ring-blue-500",
@@ -234,25 +250,15 @@ export default function DrawerLatestRuns({
234250
icon={LoaderPinwheelIcon}
235251
className="h-full"
236252
>
237-
{logLines?.[0] && (
238-
<ScrollArea className="pb-2 flex flex-col gap-0.5 h-full">
239-
{logLines[0]?.values.map((log: any, index: number) => {
240-
return (
241-
<div
242-
key={index}
243-
className={"flex flex-row items-center gap-2 mb-2"}
244-
>
245-
<Label className="min-w-[170px] whitespace-nowrap">
246-
{log.timestamp}
247-
</Label>
248-
<Badge variant={"defaultTeal"}>{log.type}</Badge>
249-
<Label className="leading-5">{log.message}</Label>
250-
</div>
251-
)
252-
})}
253-
</ScrollArea>
253+
{logs?.[0] && (
254+
<LiveLogViewer
255+
initialLogs={logs[0]?.values.map((e: any) => e.fullMessage)}
256+
wrapLines={false}
257+
scrollToLine={1}
258+
extraLines={4}
259+
/>
254260
)}
255-
{!logLines?.[0] && !loading && (
261+
{!logs?.[0] && !loading && (
256262
<div className="w-full h-full flex flex-col gap-4 items-center justify-center">
257263
<LogsIcon className="w-16 h-16 text-destructive" />
258264
<div className="text-muted-foreground text-md">

src/components/custom/DrawerLokiLogs.tsx

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Label } from "@/components/ui/label"
22
import SheetActionDialog from "@/components/sheet-action-dialog"
33
import type { ReactNode } from "react"
4+
import { useEffect } from "react"
45
import { useState } from "react"
56
import { Badge } from "@/components/ui/badge"
67
import { ScrollArea } from "@/components/ui/scroll-area"
@@ -14,6 +15,9 @@ import { LoaderPinwheelIcon, LogsIcon } from "lucide-react"
1415
import { getLokiLogs } from "@/services/components/logsService"
1516
import TabCarousel from "@/components/custom/general/TabCarousel"
1617
import Spinner from "@/components/ui/spinner"
18+
import { useSocketLogs } from "@/lib/socketUtils"
19+
import { MiscNotificationTopics } from "@/models/network"
20+
import { LiveLogViewer } from "@/components/custom/general/LogViewer"
1721

1822
export interface DrawerLokiLogsProps {
1923
start?: Date
@@ -23,7 +27,6 @@ export interface DrawerLokiLogsProps {
2327
}
2428

2529
export default function DrawerLokiLogs(props: DrawerLokiLogsProps) {
26-
const [logs, setLogs] = useState([])
2730
const [watch, setWatch] = useState<CheckedState>(true)
2831
const [dialogOpen, setDialogOpen] = useState<CheckedState>(false)
2932
const [period, setPeriod] = useState<DateRange | undefined>({
@@ -33,41 +36,32 @@ export default function DrawerLokiLogs(props: DrawerLokiLogsProps) {
3336
const [activeTab, setActiveTab] = useState<string>("")
3437
const [loading, setLoading] = useState(false)
3538

36-
useInterval(
37-
() => {
38-
getLogs()
39+
const { logs } = useSocketLogs({
40+
actions: [],
41+
format: (stream: any) => {
42+
stream.values.forEach((log: any) => {
43+
log.fullMessage = `${log.timestamp} | ${log.type?.toUpperCase()} | ${log.message}`
44+
})
45+
return stream
3946
},
40-
dialogOpen && watch ? 10000 : null,
41-
)
42-
43-
const getLogs = () => {
44-
return getLokiLogs(`{job="${props.jobName}"}`, period?.from, period?.to, {
45-
setEndToMidnight: true,
46-
}).then(parsedLogs => {
47-
setLogs(parsedLogs ?? [])
48-
if (!activeTab) setActiveTab(parsedLogs[0]?.uniqueId)
49-
return
50-
})
51-
}
47+
initialLogsFilter: period,
48+
logInterval: dialogOpen && watch ? 10000 : undefined,
49+
mergeOutputStreams: false,
50+
logQuery: `{job="${props.jobName}"}`,
51+
})
5252

5353
const fetchLogs = (open?: boolean) => {
5454
setDialogOpen(!!open)
55-
if (open) {
56-
setLoading(true)
57-
getLogs().then(() => {
58-
setLoading(false)
59-
})
60-
}
6155
}
6256

6357
const updatePeriod = (period: DateRange | undefined) => {
6458
setPeriod(period)
65-
setLoading(true)
66-
getLogs().then(() => {
67-
setLoading(false)
68-
})
6959
}
7060

61+
useEffect(() => {
62+
if (!activeTab) setActiveTab(logs[0]?.uniqueId)
63+
}, [logs])
64+
7165
return (
7266
<SheetActionDialog
7367
side={"right"}
@@ -79,6 +73,7 @@ export default function DrawerLokiLogs(props: DrawerLokiLogsProps) {
7973
}
8074
onOpenChange={open => fetchLogs(open)}
8175
modal={true}
76+
innerContainerClassName="pb-2"
8277
>
8378
<div className={"flex flex-row items-center gap-2 my-2 h-100"}>
8479
<div className="flex flex-row items-center gap-2 border rounded-md p-2 bg-sidebar">
@@ -141,28 +136,12 @@ export default function DrawerLokiLogs(props: DrawerLokiLogsProps) {
141136
className="h-[inherit]"
142137
title={stream.title}
143138
>
144-
<ScrollArea className="pb-2 flex flex-col gap-0.5 h-full">
145-
<div
146-
className={
147-
"rounded-md h-full p-1 overflow-clip bg-sidebar"
148-
}
149-
>
150-
{stream.values.map((log: any, index: number) => {
151-
return (
152-
<div
153-
key={index}
154-
className={"flex flex-row items-center gap-2 mb-2"}
155-
>
156-
<Label className="min-w-[170px] whitespace-nowrap">
157-
{log.timestamp}
158-
</Label>
159-
<Badge variant={"defaultTeal"}>{log.type}</Badge>
160-
<Label className="leading-5">{log.message}</Label>
161-
</div>
162-
)
163-
})}
164-
</div>
165-
</ScrollArea>
139+
<LiveLogViewer
140+
initialLogs={stream.values.map((e: any) => e.fullMessage)}
141+
wrapLines={false}
142+
scrollToLine={1}
143+
extraLines={4}
144+
/>
166145
</TabsContent>
167146
)
168147
})}

src/components/custom/general/LogViewer.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import type React from "react"
22
import { useEffect, useState } from "react"
3+
import type { LazyLogProps } from "@melloware/react-logviewer"
34
import { LazyLog, ScrollFollow } from "@melloware/react-logviewer"
5+
import { colorLog } from "@/utils/generalUtils"
46

5-
interface LiveLogViewerProps {
7+
interface LiveLogViewerProps extends LazyLogProps {
68
initialLogs: string[]
79
height?: number | string
810
width?: number | string
911
follow?: boolean
1012
newLogs?: string[]
13+
coloring?: boolean
1114
}
1215

1316
export const LiveLogViewer: React.FC<LiveLogViewerProps> = ({
@@ -16,20 +19,21 @@ export const LiveLogViewer: React.FC<LiveLogViewerProps> = ({
1619
width = "100%",
1720
follow = true,
1821
newLogs,
22+
coloring,
1923
...lazyProps
2024
}) => {
2125
const [buffer, setBuffer] = useState<string[]>(() => [...initialLogs])
2226

2327
useEffect(() => {
2428
if (initialLogs.length) {
25-
setBuffer(prev => [...initialLogs, ...(prev ?? [])])
29+
setBuffer(prev => colorLog(initialLogs))
2630
}
2731
}, [initialLogs])
2832

2933
useEffect(() => {
3034
if (newLogs && newLogs.length > 0) {
3135
setBuffer(prev => {
32-
return [...prev, ...newLogs]
36+
return [...prev, ...colorLog(newLogs)]
3337
})
3438
}
3539
}, [newLogs])

src/features/system/eventLog.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export function EventLog() {
1616
fullMessage: `${data.logs.timestamp} | ${data.logs.level?.toUpperCase()} | ${data.logs.message}`,
1717
}),
1818
initialLogsFilter: period,
19+
mergeOutputStreams: true,
1920
})
2021

2122
const onPeriodFilterChange = useCallback((period?: DateRange) => {

0 commit comments

Comments
 (0)