Separately format time, json and message of debug stream log.

This commit is contained in:
muzam1l
2022-03-01 21:36:24 +05:30
parent 0a44b5b5d1
commit 5993d2762f
6 changed files with 83 additions and 26 deletions

17
components/Code.tsx Normal file
View File

@@ -0,0 +1,17 @@
import { styled } from "../stitches.config";
const Code = styled("pre", {
m: 0,
wordBreak: "break-all",
fontFamily: '$monospace',
whiteSpace: 'pre-wrap',
variants: {
fluid: {
true: {
width: "100%",
},
},
},
});
export default Code;

View File

@@ -1,9 +1,9 @@
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useSnapshot } from "valtio";
import { Select } from ".";
import state from "../state";
import state, { ILog } from "../state";
import { extractJSON } from "../utils/json";
import LogBox from "./LogBox";
import Text from "./Text";
const DebugStream = () => {
const snap = useSnapshot(state);
@@ -16,7 +16,6 @@ const DebugStream = () => {
const renderNav = () => (
<>
<Text css={{ mx: "$2", fontSize: "inherit" }}>Account: </Text>
<Select
instanceId="debugStreamAccount"
placeholder="Select account"
@@ -24,11 +23,31 @@ const DebugStream = () => {
hideSelectedOptions
value={selectedAccount}
onChange={acc => setSelectedAccount(acc as any)}
css={{ width: "30%" }}
css={{ width: "100%" }}
/>
</>
);
const prepareLog = useCallback((str: any): ILog => {
if (typeof str !== "string") throw Error("Unrecognized debug log stream!");
const match = str.match(/([\s\S]+(?:UTC|ISO|GMT[+|-]\d+))\ ?([\s\S]*)/m);
const [_, time, msg] = match || [];
const jsonData = extractJSON(msg);
const timestamp = time ? new Date(time) : undefined;
const message = !jsonData
? msg
: msg.slice(0, jsonData.start) + msg.slice(jsonData.end + 1);
return {
type: "log",
message,
timestamp,
jsonData: jsonData?.result,
};
}, []);
useEffect(() => {
const account = selectedAccount?.value;
if (!account) {
@@ -52,10 +71,7 @@ const DebugStream = () => {
};
const onMessage = (event: any) => {
if (!event.data) return;
state.debugLogs.push({
type: "log",
message: event.data,
});
state.debugLogs.push(prepareLog(event.data));
};
socket.addEventListener("open", onOpen);
@@ -67,10 +83,11 @@ const DebugStream = () => {
socket.removeEventListener("open", onOpen);
socket.removeEventListener("close", onError);
socket.removeEventListener("message", onMessage);
socket.removeEventListener("error", onError);
socket.close();
};
}, [selectedAccount]);
}, [prepareLog, selectedAccount]);
return (
<LogBox

View File

@@ -4,14 +4,9 @@ import useStayScrolled from "react-stay-scrolled";
import NextLink from "next/link";
import Container from "./Container";
import Box from "./Box";
import Flex from "./Flex";
import LogText from "./LogText";
import { ILog } from "../state";
import Text from "./Text";
import Button from "./Button";
import Heading from "./Heading";
import Link from "./Link";
import { Code, Link, Heading, Button, Text, Flex, Box } from ".";
interface ILogBox {
title: string;
@@ -21,14 +16,7 @@ interface ILogBox {
enhanced?: boolean;
}
const LogBox: React.FC<ILogBox> = ({
title,
clearLog,
logs,
children,
renderNav,
enhanced,
}) => {
const LogBox: React.FC<ILogBox> = ({ title, clearLog, logs, children, renderNav, enhanced }) => {
const logRef = useRef<HTMLPreElement>(null);
const { stayScrolled /*, scrollBottom*/ } = useStayScrolled(logRef);
@@ -55,6 +43,7 @@ const LogBox: React.FC<ILogBox> = ({
}}
>
<Flex
fluid
css={{
height: "48px",
alignItems: "center",
@@ -78,7 +67,15 @@ const LogBox: React.FC<ILogBox> = ({
>
<Notepad size="15px" /> <Text css={{ lineHeight: 1 }}>{title}</Text>
</Heading>
{renderNav?.()}
<Flex
row
align="center"
css={{
width: "50%", // TODO make it max without breaking layout!
}}
>
{renderNav?.()}
</Flex>
<Flex css={{ ml: "auto", gap: "$3", marginRight: "$3" }}>
{clearLog && (
<Button ghost size="xs" onClick={clearLog}>
@@ -117,16 +114,18 @@ const LogBox: React.FC<ILogBox> = ({
backgroundColor: enhanced ? "$backgroundAlt" : undefined,
},
},
p: enhanced ? "$2 $1" : undefined,
p: enhanced ? "$1" : undefined,
}}
>
<LogText variant={log.type}>
{log.timestamp && <Text muted>{log.timestamp.toLocaleTimeString()} </Text>}
{log.message}{" "}
{log.link && (
<NextLink href={log.link} shallow passHref>
<Link as="a">{log.linkText}</Link>
</NextLink>
)}
{log.jsonData && <Code>{JSON.stringify(log.jsonData, null, 2)}</Code>}
</LogText>
</Box>
))}

View File

@@ -10,6 +10,7 @@ export * from "./Tabs";
export * from "./AlertDialog";
export { default as Box } from "./Box";
export { default as Button } from "./Button";
export { default as Code } from "./Code";
export { default as ButtonGroup } from "./ButtonGroup";
export { default as DeployFooter } from "./DeployFooter";
export * from "./Dialog";

View File

@@ -33,6 +33,8 @@ export interface IAccount {
export interface ILog {
type: "error" | "warning" | "log" | "success";
message: string;
jsonData?: any,
timestamp?: Date;
link?: string;
linkText?: string;
}

21
utils/json.ts Normal file
View File

@@ -0,0 +1,21 @@
export const extractJSON = (str?: string) => {
if (!str) return
let firstOpen = 0, firstClose = 0, candidate = '';
firstOpen = str.indexOf('{', firstOpen + 1);
do {
firstClose = str.lastIndexOf('}');
if (firstClose <= firstOpen) {
return;
}
do {
candidate = str.substring(firstOpen, firstClose + 1);
try {
let result = JSON.parse(candidate);
return { result, start: firstOpen < 0 ? 0 : firstOpen, end: firstClose }
}
catch (e) { }
firstClose = str.substring(0, firstClose).lastIndexOf('}');
} while (firstClose > firstOpen);
firstOpen = str.indexOf('{', firstOpen + 1);
} while (firstOpen != -1);
}