Skip to content

Commit

Permalink
Improve/design logs n metrics (#84)
Browse files Browse the repository at this point in the history
* 🎨 Improved design for logs component

improved design for logs and disabled network_io and disk_io for apps

* 🔖 Updated build

* 🔖 Updated build

* 🔖 Build update

* 🔖 Build update

* 🎨 Improved logs

* 🎨 Logs improved
  • Loading branch information
abdheshnayak authored Feb 8, 2024
1 parent 61db8a1 commit d593537
Show file tree
Hide file tree
Showing 18 changed files with 721 additions and 408 deletions.
3 changes: 3 additions & 0 deletions gql-queries-generator/doc/queries.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ query consoleGetProviderSecret($name: String!) {

query consoleGetNodePool($clusterName: String!, $poolName: String!) {
infra_getNodePool(clusterName: $clusterName, poolName: $poolName) {
id
clusterName
createdBy {
userEmail
Expand Down Expand Up @@ -657,6 +658,7 @@ query consoleListNodePools($clusterName: String!, $search: SearchNodepool, $pagi
edges {
cursor
node {
id
clusterName
createdBy {
userEmail
Expand Down Expand Up @@ -3786,6 +3788,7 @@ query authCli_getDevice($name: String!) {
}
clusterName
projectName
environmentName
spec {
activeNamespace
disabled
Expand Down
9 changes: 8 additions & 1 deletion lib/client/hooks/use-debounce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ const useDebounce: IuseDebounce = (action, delay, dep = []) => {
// const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(
() => {
let resp = () => {};
// Update debounced value after delay
const handler = setTimeout(() => {
action();
resp = action();
}, delay);
// Cancel the timeout if value changes (also on delay change or unmount)
// This is how we prevent debounced value from updating if value is changed ...
// .. within the delay period. Timeout gets cleared and restarted.
return () => {
clearTimeout(handler);
if (typeof resp === 'function') {
resp();
return;
}

console.log('resp', resp);
};
},
[delay, ...dep] // Only re-call effect if value or delay changes
Expand Down
2 changes: 2 additions & 0 deletions lib/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,5 @@ export type ExtractArrayType<T> = T extends (infer U)[] ? U : never;
export type LoaderResult<T extends (props: any) => Promise<any>> = Awaited<
ReturnType<T>
>;

export type ISetState<T> = React.Dispatch<React.SetStateAction<T>>;
67 changes: 49 additions & 18 deletions src/apps/console/components/code-view.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,67 @@
import { CopySimple } from '@jengaicons/react';
import hljs from 'highlight.js';
import { useEffect, useRef } from 'react';
import { toast } from '~/components/molecule/toast';
import useClipboard from '~/root/lib/client/hooks/use-clipboard';

interface ICodeView {
data: string;
copy: boolean;
showShellPrompt?: boolean;
language?: string;
title: string;
}
const CodeView = ({ data, copy, showShellPrompt }: ICodeView) => {
const CodeView = ({
data,
copy,
showShellPrompt,
language = 'shell',
title,
}: ICodeView) => {
const { copy: cpy } = useClipboard({
onSuccess() {
toast.success('Text copied to clipboard.');
},
});

const ref = useRef(null);

useEffect(() => {
(async () => {
if (ref.current) {
const hr = hljs.highlight(
data,
{
language,
},
false
);

// @ts-ignore
ref.current.innerHTML = hr.value;
}
})();
}, [data, language]);

return (
<div
onClick={() => {
if (copy) cpy(data);
}}
className="group/sha cursor-pointer bg-surface-basic-active p-lg rounded-lg bodyMd flex flex-row gap-xl items-center"
>
<pre>
<code className="flex flex-row items-center gap-lg flex-1 break-all">
<span className="opacity-60">{showShellPrompt && '$'}</span>
<div className="break-all" style={{ whiteSpace: 'pre-wrap' }}>
{data}
</div>
</code>
</pre>
<span className="invisible group-hover/sha:visible">
<CopySimple size={14} />
</span>
<div className="flex flex-col gap-lg flex-1 min-w-[45%]">
<div className="bodyMd-medium text-text-default">{title}</div>
<div className="bodyMd text-text-strong">
<div
onClick={() => {
if (copy) cpy(data);
}}
className="group/sha cursor-pointer p-lg rounded-md bodyMd flex flex-row gap-xl items-center hljs w-full"
>
<pre className="flex-1">
<code ref={ref}>{data}</code>
</pre>

<span className="invisible group-hover/sha:visible">
<CopySimple size={14} />
</span>
</div>
</div>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,22 @@ import Fuse from 'fuse.js';
import hljs from 'highlight.js';
import React, { ReactNode, memo, useEffect, useRef, useState } from 'react';
import { ViewportList } from 'react-viewport-list';
import * as sock from 'websocket';
import { dayjs } from '~/components/molecule/dayjs';
import {
ISearchInfProps,
useSearch,
} from '~/root/lib/client/helpers/search-filter';
import useClass from '~/root/lib/client/hooks/use-class';
import { socketUrl } from '~/root/lib/configs/base-url.cjs';
import useDebounce from '~/root/lib/client/hooks/use-debounce';
import { generatePlainColor } from './color-generator';
import Pulsable from './pulsable';
import { logsMockData } from '../dummy/data';
import { generatePlainColor } from '../color-generator';
import Pulsable from '../pulsable';
import { logsMockData } from '../../dummy/data';
import { ILog, ISocketMessage, IuseLog, useSocketLogs } from './useSocketLogs';

const hoverClass = `hover:bg-[#ddd]`;
const hoverClassDark = `hover:bg-[#333]`;

type ILog = {
pod_name: string;
container_name: string;
message: string;
timestamp: string;
};
type ILogWithLineNumber = ILog & { lineNumber: number };

type ISocketMessage = ILog;

const padLeadingZeros = (num: number, size: number) => {
let s = `${num}`;
while (s.length < size) s = `0${s}`;
Expand Down Expand Up @@ -568,13 +558,6 @@ const LogBlock = ({
);
};

interface IuseLog {
url?: string;
account: string;
cluster: string;
trackingId: string;
}

export interface IHighlightJsLog {
websocket: IuseLog;
follow?: boolean;
Expand All @@ -598,185 +581,6 @@ export interface IHighlightJsLog {
dark?: boolean;
}

const useSocketLogs = ({ url, account, cluster, trackingId }: IuseLog) => {
const [logs, setLogs] = useState<ISocketMessage[]>([]);
const [error, setError] = useState('');
const [isLoading, setIsLoading] = useState(true);

let wsclient: Promise<sock.w3cwebsocket>;

const [socState, setSocState] = useState<sock.w3cwebsocket | null>(null);
const [subscribed, setSubscribed] = useState(false);

if (typeof window !== 'undefined') {
try {
wsclient = new Promise<sock.w3cwebsocket>((res, rej) => {
let rejected = false;
try {
// eslint-disable-next-line new-cap
const w = new sock.w3cwebsocket(
url || `${socketUrl}/logs`,
'',
'',
{}
);

w.onmessage = (msg) => {
try {
const m: {
timestamp: string;
message: string;
spec: {
podName: string;
containerName: string;
};
type: 'update' | 'error' | 'info';
} = JSON.parse(msg.data as string);

if (m.type === 'error') {
setLogs([]);
console.error(m.message);
return;
}

if (m.type === 'info') {
if (m.message === 'subscribed to logs') {
setSubscribed(true);
}
console.log(m.message);
return;
}

if (m.type === 'update') {
console.log(m.message);
return;
}

if (m.type === 'log') {
setIsLoading(false);
setLogs((s) => [
...s,
{
pod_name: m.spec.podName,
container_name: m.spec.containerName,
message: m.message,
timestamp: m.timestamp,
},
]);
return;
}

console.log(m);
} catch (err) {
console.error(err);
}
};

w.onopen = () => {
res(w);
};

w.onerror = (e) => {
console.error(e);
if (!rejected) {
rejected = true;
rej(e);
}
};

w.onclose = () => {};
} catch (e) {
rej(e);
}
});
} catch (e) {
console.log(e);
}
}

useDebounce(
() => {
(async () => {
try {
if (account === '' || cluster === '' || trackingId === '') {
return () => {};
}

if (logs.length) {
setLogs([]);
}
setIsLoading(true);

const client = await wsclient;

setSocState(client);

client.send(
JSON.stringify({
event: 'subscribe',
data: {
account,
cluster,
trackingId,
},
})
);
} catch (e) {
console.error(e);
setLogs([]);
setError((e as Error).message);
}

return () => {
(async () => {
if (!socState) return;

socState.send(
JSON.stringify({
event: 'unsubscribe',
data: {
account,
cluster,
trackingId,
},
})
);

// client.close();

setLogs([]);
})();
};
})();
},
1000,
[account, cluster, trackingId, url]
);

useEffect(() => {
const sorted = logs.sort((a, b) => {
const resp = a.pod_name.localeCompare(b.pod_name);

if (resp === 0) {
return dayjs(a.timestamp).unix() - dayjs(b.timestamp).unix();
}

return resp;
});

if (JSON.stringify(sorted) !== JSON.stringify(logs)) {
setLogs(sorted);
}
}, [logs]);

return {
logs,
error,
isLoading,
subscribed,
};
};

const LogComp = ({
websocket,
follow = true,
Expand Down Expand Up @@ -837,7 +641,7 @@ const LogComp = ({
<div
className={classNames(className, {
'fixed w-full h-full left-0 top-0 z-[999] bg-black': fullScreen,
relative: !fullScreen,
'relative hljs rounded-md': !fullScreen,
})}
style={{
width: fullScreen ? '100%' : width,
Expand Down
Loading

0 comments on commit d593537

Please sign in to comment.