Skip to content

Commit

Permalink
new-log-viewer: Formalize config parameters and add management utilit…
Browse files Browse the repository at this point in the history
…ies. (#51)
  • Loading branch information
Henry8192 authored Aug 16, 2024
1 parent 0804897 commit 8f33b22
Show file tree
Hide file tree
Showing 4 changed files with 351 additions and 24 deletions.
127 changes: 127 additions & 0 deletions new-log-viewer/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,132 @@ import {
updateWindowUrlHashParams,
UrlContext,
} from "../contexts/UrlContextProvider";
import {
CONFIG_KEY,
LOCAL_STORAGE_KEY,
THEME_NAME,
} from "../typings/config";
import {
getConfig,
setConfig,
} from "../utils/config";


const formFields = [
{
initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).formatString,
label: LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING,
name: LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING,
type: "text",
},
{
initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).logLevelKey,
label: LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY,
name: LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY,
type: "text",
},
{
initialValue: getConfig(CONFIG_KEY.DECODER_OPTIONS).timestampKey,
label: LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY,
name: LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY,
type: "text",
},
{
initialValue: getConfig(CONFIG_KEY.THEME),
label: LOCAL_STORAGE_KEY.THEME,
name: LOCAL_STORAGE_KEY.THEME,
type: "text",
},
{
initialValue: getConfig(CONFIG_KEY.PAGE_SIZE),
label: LOCAL_STORAGE_KEY.PAGE_SIZE,
name: LOCAL_STORAGE_KEY.PAGE_SIZE,
type: "number",
},
];

/**
* Renders a form for testing config utilities.
*
* @return
*/
const ConfigForm = () => {
const handleConfigFormReset = (ev: React.FormEvent) => {
ev.preventDefault();
window.localStorage.clear();
window.location.reload();
};

const handleConfigFormSubmit = (ev: React.FormEvent) => {
ev.preventDefault();
const formData = new FormData(ev.target as HTMLFormElement);

const formatString = formData.get(LOCAL_STORAGE_KEY.DECODER_OPTIONS_FORMAT_STRING);
const logLevelKey = formData.get(LOCAL_STORAGE_KEY.DECODER_OPTIONS_LOG_LEVEL_KEY);
const timestampKey = formData.get(LOCAL_STORAGE_KEY.DECODER_OPTIONS_TIMESTAMP_KEY);
const theme = formData.get(LOCAL_STORAGE_KEY.THEME);
const pageSize = formData.get(LOCAL_STORAGE_KEY.PAGE_SIZE);
let error = null;
if (
"string" === typeof formatString &&
"string" === typeof logLevelKey &&
"string" === typeof timestampKey
) {
error ||= setConfig({
key: CONFIG_KEY.DECODER_OPTIONS,
value: {formatString, logLevelKey, timestampKey},
});
}
if ("string" === typeof theme) {
error ||= setConfig({
key: CONFIG_KEY.THEME,
value: theme as THEME_NAME,
});
}
if ("string" === typeof pageSize) {
error ||= setConfig({
key: CONFIG_KEY.PAGE_SIZE,
value: Number(pageSize),
});
}
if (null !== error) {
// eslint-disable-next-line no-alert
window.alert(error);
} else {
window.location.reload();
}
};

return (
<form
onReset={handleConfigFormReset}
onSubmit={handleConfigFormSubmit}
>
<table>
<tbody>
{formFields.map((field, index) => (
<tr key={index}>
<td>
{field.label}
</td>
<td>
<input
defaultValue={field.initialValue}
name={field.name}
size={100}
type={field.type}/>
</td>
</tr>
))}
</tbody>
</table>
<div>
<button type={"submit"}>Apply</button>
<button type={"reset"}>Clear localStorage</button>
</div>
</form>
);
};

/**
* Renders the major layout of the log viewer.
Expand Down Expand Up @@ -52,6 +177,8 @@ const Layout = () => {
Copy link to last log
</button>

<ConfigForm/>

{logData.split("\n").map((line, index) => (
<p key={index}>
{`<${index + 1}>`}
Expand Down
42 changes: 18 additions & 24 deletions new-log-viewer/src/contexts/StateContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, {
} from "react";

import {Nullable} from "../typings/common";
import {CONFIG_KEY} from "../typings/config";
import {
BeginLineNumToLogEventNumMap,
CURSOR_CODE,
Expand All @@ -18,6 +19,7 @@ import {
WORKER_RESP_CODE,
WorkerReq,
} from "../typings/worker";
import {getConfig} from "../utils/config";
import {
clamp,
getChunkNum,
Expand Down Expand Up @@ -52,8 +54,6 @@ const STATE_DEFAULT = Object.freeze({
pageNum: null,
});

const PAGE_SIZE = 10_000;

interface StateContextProviderProps {
children: React.ReactNode
}
Expand Down Expand Up @@ -158,15 +158,9 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
mainWorkerRef.current.onmessage = handleMainWorkerResp;
mainWorkerPostReq(WORKER_REQ_CODE.LOAD_FILE, {
fileSrc: fileSrc,
pageSize: PAGE_SIZE,
pageSize: getConfig(CONFIG_KEY.PAGE_SIZE),
cursor: cursor,
decoderOptions: {
// TODO: these shall come from config provider
formatString: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%process.thread.name] %log.level" +
" %message%n",
logLevelKey: "log.level",
timestampKey: "@timestamp",
},
decoderOptions: getConfig(CONFIG_KEY.DECODER_OPTIONS),
});
}, [
handleMainWorkerResp,
Expand All @@ -184,7 +178,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
return;
}

numPagesRef.current = getChunkNum(numEvents, PAGE_SIZE);
numPagesRef.current = getChunkNum(numEvents, getConfig(CONFIG_KEY.PAGE_SIZE));
}, [numEvents]);

// On `logEventNum` update, clamp it then switch page if necessary or simply update the URL.
Expand All @@ -193,7 +187,12 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
return;
}

const newPageNum = clamp(getChunkNum(logEventNum, PAGE_SIZE), 1, numPagesRef.current);
const newPageNum = clamp(
getChunkNum(logEventNum, getConfig(CONFIG_KEY.PAGE_SIZE)),
1,
numPagesRef.current
);

if (newPageNum === pageNumRef.current) {
// Don't need to switch pages so just update `logEventNum` in the URL.
updateLogEventNumInUrl(numEvents, logEventNumRef.current);
Expand All @@ -204,13 +203,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
// `WORKER_REQ_CODE.LOAD_PAGE` requests) .
mainWorkerPostReq(WORKER_REQ_CODE.LOAD_PAGE, {
cursor: {code: CURSOR_CODE.PAGE_NUM, args: {pageNum: newPageNum}},
decoderOptions: {
// TODO: these shall come from config provider
formatString: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%process.thread.name] %log.level" +
" %message%n",
logLevelKey: "log.level",
timestampKey: "@timestamp",
},
decoderOptions: getConfig(CONFIG_KEY.DECODER_OPTIONS),
});
}

Expand All @@ -232,7 +225,11 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
// Set which page to load since the user specified a specific `logEventNum`.
// NOTE: Since we don't know how many pages the log file contains, we only clamp the
// minimum of the page number.
const newPageNum = Math.max(getChunkNum(logEventNumRef.current, PAGE_SIZE), 1);
const newPageNum = Math.max(
getChunkNum(logEventNumRef.current, getConfig(CONFIG_KEY.PAGE_SIZE)),
1
);

cursor = {code: CURSOR_CODE.PAGE_NUM, args: {pageNum: newPageNum}};
}
loadFile(filePath, cursor);
Expand All @@ -259,7 +256,4 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {


export default StateContextProvider;
export {
PAGE_SIZE,
StateContext,
};
export {StateContext};
47 changes: 47 additions & 0 deletions new-log-viewer/src/typings/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {JsonlDecoderOptionsType} from "./decoders";


enum THEME_NAME {
SYSTEM = "system",
DARK = "dark",
LIGHT = "light",
}

enum CONFIG_KEY {
DECODER_OPTIONS = "decoderOptions",
THEME = "theme",
PAGE_SIZE = "pageSize",
}

/* eslint-disable @typescript-eslint/prefer-literal-enum-member */
enum LOCAL_STORAGE_KEY {
DECODER_OPTIONS_FORMAT_STRING = `${CONFIG_KEY.DECODER_OPTIONS}/formatString`,
DECODER_OPTIONS_LOG_LEVEL_KEY = `${CONFIG_KEY.DECODER_OPTIONS}/logLevelKey`,
DECODER_OPTIONS_TIMESTAMP_KEY = `${CONFIG_KEY.DECODER_OPTIONS}/timestampKey`,
THEME = CONFIG_KEY.THEME,
PAGE_SIZE = CONFIG_KEY.PAGE_SIZE,
}
/* eslint-enable @typescript-eslint/prefer-literal-enum-member */

type ConfigMap = {
[CONFIG_KEY.DECODER_OPTIONS]: JsonlDecoderOptionsType,
[CONFIG_KEY.THEME]: THEME_NAME,
[CONFIG_KEY.PAGE_SIZE]: number,
};

type ConfigUpdate = {
[T in keyof ConfigMap]: {
key: T;
value: ConfigMap[T];
}
}[keyof ConfigMap];

export {
CONFIG_KEY,
LOCAL_STORAGE_KEY,
THEME_NAME,
};
export type {
ConfigMap,
ConfigUpdate,
};
Loading

0 comments on commit 8f33b22

Please sign in to comment.