From 49bd9a46c807cb6ecdec59c5f450de1c1e33c3fe Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:48:14 -0400 Subject: [PATCH 01/27] query log structure demo (won't work) --- .../src/contexts/StateContextProvider.tsx | 4 ++ new-log-viewer/src/services/LogFileManager.ts | 54 +++++++++++++++++++ new-log-viewer/src/services/MainWorker.ts | 13 +++++ new-log-viewer/src/typings/worker.ts | 24 +++++++-- 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index c6e07803..7e7a3851 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -184,6 +184,10 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { updateLogEventNumInUrl(lastLogEventNum, logEventNumRef.current); break; } + case WORKER_RESP_CODE.QUERY_RESULT: + // eslint-disable-next-line no-warning-comments + // TODO: Handle query results + break; default: console.error(`Unexpected ev.data: ${JSON.stringify(ev.data)}`); break; diff --git a/new-log-viewer/src/services/LogFileManager.ts b/new-log-viewer/src/services/LogFileManager.ts index 2ceded83..318215f6 100644 --- a/new-log-viewer/src/services/LogFileManager.ts +++ b/new-log-viewer/src/services/LogFileManager.ts @@ -230,6 +230,60 @@ class LogFileManager { }; } + queryLog (searchString: string, isRegex: boolean, matchCase: boolean): { + [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; }[] + } { + const results: { [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; }[] } = {}; + const regex = isRegex ? + new RegExp(searchString, matchCase ? + "g" : + "gi") : + null; + const searchStr = matchCase ? + searchString : + searchString.toLowerCase(); + + for (let i = 0; i < this.#numEvents; i++) { + const logEvent = this.#decoder.decode(i, i + 1); + if (logEvent && 0 < logEvent.length) { + const [message, , , logEventNum] = logEvent[0]; + const msg = matchCase ? + message : + message.toLowerCase(); + let match; + const matches: { logEventNum: number; message: string; matchRange: [number, number]; }[] = []; + + if (regex) { + while (null !== (match = regex.exec(msg))) { + matches.push({ + logEventNum, + message, + matchRange: [match.index, + match.index + match[0].length], + }); + } + } else { + let index = msg.indexOf(searchStr); + while (-1 !== index) { + matches.push({ + logEventNum, + message, + matchRange: [index, + index + searchStr.length], + }); + index = msg.indexOf(searchStr, index + searchStr.length); + } + } + + if (0 < matches.length) { + results[i + 1] = matches; + } + } + } + + return results; + } + /** * Gets the range of log event numbers for the page containing the given cursor. * diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index a04d134c..4a258606 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -92,6 +92,19 @@ onmessage = async (ev: MessageEvent) => { LOG_FILE_MANAGER.loadPage(args.cursor) ); break; + case WORKER_REQ_CODE.QUERY_LOG: + if (null === LOG_FILE_MANAGER) { + throw new Error("Log file manager hasn't been initialized"); + } + postResp( + WORKER_RESP_CODE.QUERY_RESULT, + LOG_FILE_MANAGER.queryLog( + args.searchString, + args.isRegex, + args.matchCase + ) + ); + break; default: console.error(`Unexpected ev.data: ${JSON.stringify(ev.data)}`); break; diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index 82b186c0..449013e7 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -41,13 +41,15 @@ enum WORKER_REQ_CODE { EXPORT_LOG = "exportLog", LOAD_FILE = "loadFile", LOAD_PAGE = "loadPage", + QUERY_LOG = "queryLog", } enum WORKER_RESP_CODE { CHUNK_DATA = "chunkData", LOG_FILE_INFO = "fileInfo", - PAGE_DATA = "pageData", NOTIFICATION = "notification", + PAGE_DATA = "pageData", + QUERY_RESULT = "queryResult", } type WorkerReqMap = { @@ -64,6 +66,11 @@ type WorkerReqMap = { cursor: CursorType, decoderOptions?: DecoderOptionsType }, + [WORKER_REQ_CODE.QUERY_LOG]: { + searchString: string, + isRegex: boolean, + matchCase: boolean, + } }; type WorkerRespMap = { @@ -74,15 +81,22 @@ type WorkerRespMap = { fileName: string, numEvents: number, }, + [WORKER_RESP_CODE.NOTIFICATION]: { + logLevel: LOG_LEVEL, + message: string + }, [WORKER_RESP_CODE.PAGE_DATA]: { logs: string, beginLineNumToLogEventNum: BeginLineNumToLogEventNumMap, cursorLineNum: number }, - [WORKER_RESP_CODE.NOTIFICATION]: { - logLevel: LOG_LEVEL, - message: string - }, + [WORKER_RESP_CODE.QUERY_RESULT]: { + [lineNum: number]: { + logEventNum: number; + message: string; + matchRange: [number, number]; + }; + } }; type WorkerReq = T extends keyof WorkerReqMap ? From 5b48fd3a800e027cba1a48c2fafb6b55c08b53c9 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:14:49 -0400 Subject: [PATCH 02/27] clean up queryLog --- new-log-viewer/src/services/LogFileManager.ts | 116 ++++++++++-------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/new-log-viewer/src/services/LogFileManager.ts b/new-log-viewer/src/services/LogFileManager.ts index 318215f6..c01a0b03 100644 --- a/new-log-viewer/src/services/LogFileManager.ts +++ b/new-log-viewer/src/services/LogFileManager.ts @@ -19,6 +19,8 @@ import ClpIrDecoder from "./decoders/ClpIrDecoder"; import JsonlDecoder from "./decoders/JsonlDecoder"; +const SEARCH_CHUNK_SIZE = 1000; + /** * Loads a file from a given source. * @@ -230,59 +232,75 @@ class LogFileManager { }; } - queryLog (searchString: string, isRegex: boolean, matchCase: boolean): { - [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; }[] - } { - const results: { [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; }[] } = {}; - const regex = isRegex ? - new RegExp(searchString, matchCase ? - "g" : - "gi") : - null; - const searchStr = matchCase ? + /** + * Searches for log events based on the given search string. + * + * @param searchString The search string. + * @param isRegex Whether the search string is a regular expression. + * @param matchCase Whether the search is case-sensitive. + * @return An object containing the search results. + */ + queryLog = (searchString: string, isRegex: boolean, matchCase: boolean): { + [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; } + } => { + // If the search string is empty, or there are no logs, return + if ("" === searchString) { + return {}; + } else if (0 === this.#numEvents) { + return {}; + } + + // Construct search RegExp + const regexPattern = isRegex ? searchString : - searchString.toLowerCase(); - - for (let i = 0; i < this.#numEvents; i++) { - const logEvent = this.#decoder.decode(i, i + 1); - if (logEvent && 0 < logEvent.length) { - const [message, , , logEventNum] = logEvent[0]; - const msg = matchCase ? - message : - message.toLowerCase(); - let match; - const matches: { logEventNum: number; message: string; matchRange: [number, number]; }[] = []; - - if (regex) { - while (null !== (match = regex.exec(msg))) { - matches.push({ - logEventNum, - message, - matchRange: [match.index, - match.index + match[0].length], - }); - } - } else { - let index = msg.indexOf(searchStr); - while (-1 !== index) { - matches.push({ - logEventNum, - message, - matchRange: [index, - index + searchStr.length], - }); - index = msg.indexOf(searchStr, index + searchStr.length); - } - } - - if (0 < matches.length) { - results[i + 1] = matches; - } - } + searchString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const regexFlags = matchCase ? + "" : + "i"; + const searchRegex = new RegExp(regexPattern, regexFlags); + + const results: { + [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; } + } = {}; + + let beginSearchIdx = 0; + + while (beginSearchIdx < this.#numEvents) { + const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); + this.searchChunk(beginSearchIdx, endSearchIdx, searchRegex, results); + beginSearchIdx = endSearchIdx; } return results; - } + }; + + /** + * Searches for log events in the given range. + * + * @param beginSearchIdx The beginning index of the search range. + * @param endSearchIdx The end index of the search range. + * @param searchRegex The regular expression to search + * @return + */ + searchChunk = (beginSearchIdx: number, endSearchIdx: number, searchRegex: RegExp, results: { + [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; } + }) => { + for (let eventIdx = beginSearchIdx; eventIdx < endSearchIdx; eventIdx++) { + const contentString = this.#decoder.decode(eventIdx, eventIdx + 1)?.[0]?.[0] || ""; + + const match = contentString.match(searchRegex); + if (match) { + const logEventNum = eventIdx + 1; + const lineNum = eventIdx + 1; + results[lineNum].push({ + logEventNum, + message: contentString, + matchRange: [match.index, + (match.index + match[0].length)], + }); + } + } + }; /** * Gets the range of log event numbers for the page containing the given cursor. From 7a777ee700ed94cbff8f1b35cda1b386e7218bcc Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:49:14 -0400 Subject: [PATCH 03/27] various changes --- new-log-viewer/src/services/LogFileManager.ts | 77 +++++++++++-------- new-log-viewer/src/services/MainWorker.ts | 21 +++-- new-log-viewer/src/typings/worker.ts | 16 ++-- new-log-viewer/src/utils/time.ts | 9 +++ 4 files changed, 78 insertions(+), 45 deletions(-) create mode 100644 new-log-viewer/src/utils/time.ts diff --git a/new-log-viewer/src/services/LogFileManager.ts b/new-log-viewer/src/services/LogFileManager.ts index c01a0b03..f794aa88 100644 --- a/new-log-viewer/src/services/LogFileManager.ts +++ b/new-log-viewer/src/services/LogFileManager.ts @@ -1,3 +1,5 @@ +/* eslint-disable max-lines */ +// TODO: either increase max-lines or refactor the code import { Decoder, DecoderOptionsType, @@ -6,6 +8,7 @@ import { import {MAX_V8_STRING_LENGTH} from "../typings/js"; import { BeginLineNumToLogEventNumMap, + ChunkResults, CURSOR_CODE, CursorType, FileSrcType, @@ -13,6 +16,7 @@ import { import {EXPORT_LOGS_CHUNK_SIZE} from "../utils/config"; import {getUint8ArrayFrom} from "../utils/http"; import {getChunkNum} from "../utils/math"; +import {defer} from "../utils/time"; import {formatSizeInBytes} from "../utils/units"; import {getBasenameFromUrlOrDefault} from "../utils/url"; import ClpIrDecoder from "./decoders/ClpIrDecoder"; @@ -51,14 +55,16 @@ const loadFile = async (fileSrc: FileSrcType) * Class to manage the retrieval and decoding of a given log file. */ class LogFileManager { + readonly #fileName: string; + + readonly #numEvents: number = 0; + readonly #pageSize: number; - readonly #fileName: string; + #queryId: number = 0; #decoder: Decoder; - #numEvents: number = 0; - /** * Private constructor for LogFileManager. This is not intended to be invoked publicly. * Instead, use LogFileManager.create() to create a new instance of the class. @@ -155,6 +161,10 @@ class LogFileManager { this.#decoder.setDecoderOptions(options); } + incrementQueryId () { + this.#queryId++; + } + /** * Loads log events in the range * [`beginLogEventIdx`, `beginLogEventIdx + EXPORT_LOGS_CHUNK_SIZE`), or all remaining log @@ -240,14 +250,14 @@ class LogFileManager { * @param matchCase Whether the search is case-sensitive. * @return An object containing the search results. */ - queryLog = (searchString: string, isRegex: boolean, matchCase: boolean): { - [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; } - } => { + startQuery (searchString: string, isRegex: boolean, matchCase: boolean): void { + this.incrementQueryId(); + // If the search string is empty, or there are no logs, return if ("" === searchString) { - return {}; + return; } else if (0 === this.#numEvents) { - return {}; + return; } // Construct search RegExp @@ -258,49 +268,52 @@ class LogFileManager { "" : "i"; const searchRegex = new RegExp(regexPattern, regexFlags); - - const results: { - [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; } - } = {}; - - let beginSearchIdx = 0; - - while (beginSearchIdx < this.#numEvents) { - const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); - this.searchChunk(beginSearchIdx, endSearchIdx, searchRegex, results); - beginSearchIdx = endSearchIdx; - } - - return results; - }; + this.#searchChunk(this.#queryId, 0, searchRegex); + } /** * Searches for log events in the given range. * + * @param queryId * @param beginSearchIdx The beginning index of the search range. - * @param endSearchIdx The end index of the search range. * @param searchRegex The regular expression to search * @return */ - searchChunk = (beginSearchIdx: number, endSearchIdx: number, searchRegex: RegExp, results: { - [lineNum: number]: { logEventNum: number; message: string; matchRange: [number, number]; } - }) => { + #searchChunk (queryId: number, beginSearchIdx: number, searchRegex: RegExp): ChunkResults | null { + if (queryId !== this.#queryId) { + return null; + } + + const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); + const results: ChunkResults = {}; + for (let eventIdx = beginSearchIdx; eventIdx < endSearchIdx; eventIdx++) { const contentString = this.#decoder.decode(eventIdx, eventIdx + 1)?.[0]?.[0] || ""; const match = contentString.match(searchRegex); - if (match) { + if (match && match.index) { const logEventNum = eventIdx + 1; - const lineNum = eventIdx + 1; - results[lineNum].push({ - logEventNum, + const pageNum = Math.ceil(logEventNum / this.#pageSize); + if (!results[pageNum]) { + results[pageNum] = []; + } + results[pageNum].push({ + logEventNum: logEventNum, message: contentString, matchRange: [match.index, (match.index + match[0].length)], }); } } - }; + + if (endSearchIdx < this.#numEvents) { + defer(() => { + this.#searchChunk(queryId, endSearchIdx, searchRegex); + }); + } + + return results; + } /** * Gets the range of log event numbers for the page containing the given cursor. diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index 4a258606..4182c6f6 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -36,6 +36,16 @@ const postResp = ( postMessage({code, args}); }; + +// FIXME: pass this to the constructor / factory function of LogFileManager or the LogFileManager.search(onQueryResult) method? +/** + * + * @param queryResult + */ +const handleQueryResult = (queryResult: string[]) => { + postResp(WORKER_RESP_CODE.QUERY_RESULT, queryResult); +}; + // eslint-disable-next-line no-warning-comments // TODO: Break this function up into smaller functions. // eslint-disable-next-line max-lines-per-function,max-statements @@ -96,13 +106,10 @@ onmessage = async (ev: MessageEvent) => { if (null === LOG_FILE_MANAGER) { throw new Error("Log file manager hasn't been initialized"); } - postResp( - WORKER_RESP_CODE.QUERY_RESULT, - LOG_FILE_MANAGER.queryLog( - args.searchString, - args.isRegex, - args.matchCase - ) + LOG_FILE_MANAGER.startQuery( + args.searchString, + args.isRegex, + args.isCaseSensitive ); break; default: diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index 449013e7..8ed12d35 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -67,12 +67,19 @@ type WorkerReqMap = { decoderOptions?: DecoderOptionsType }, [WORKER_REQ_CODE.QUERY_LOG]: { + isCaseSensitive: boolean, searchString: string, isRegex: boolean, - matchCase: boolean, } }; +type ChunkResultType = { + logEventNum: number; + message: string; + matchRange: [number, number]; +}; +type ChunkResults = Record; + type WorkerRespMap = { [WORKER_RESP_CODE.CHUNK_DATA]: { logs: string @@ -91,11 +98,7 @@ type WorkerRespMap = { cursorLineNum: number }, [WORKER_RESP_CODE.QUERY_RESULT]: { - [lineNum: number]: { - logEventNum: number; - message: string; - matchRange: [number, number]; - }; + chunkResults: ChunkResults, } }; @@ -122,6 +125,7 @@ export { }; export type { BeginLineNumToLogEventNumMap, + ChunkResults, CursorType, FileSrcType, MainWorkerReqMessage, diff --git a/new-log-viewer/src/utils/time.ts b/new-log-viewer/src/utils/time.ts new file mode 100644 index 00000000..ce7a6694 --- /dev/null +++ b/new-log-viewer/src/utils/time.ts @@ -0,0 +1,9 @@ +/** + * + * @param callback + */ +const defer = (callback: ()=>void) => { + setTimeout(callback, 0); +}; + +export {defer}; From fdd761a86d82ae4f6aee4c28fbb73b07116ff3dd Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:33:28 -0400 Subject: [PATCH 04/27] finish draft of query log --- .../src/contexts/StateContextProvider.tsx | 14 ++++++++++--- new-log-viewer/src/services/LogFileManager.ts | 21 +++++++++++++------ new-log-viewer/src/services/MainWorker.ts | 12 ++++++----- new-log-viewer/src/typings/worker.ts | 6 ++---- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index 7e7a3851..c05b9835 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -14,6 +14,7 @@ import {CONFIG_KEY} from "../typings/config"; import {SEARCH_PARAM_NAMES} from "../typings/url"; import { BeginLineNumToLogEventNumMap, + ChunkResults, CURSOR_CODE, CursorType, FileSrcType, @@ -157,6 +158,8 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { const logExportManagerRef = useRef(null); const mainWorkerRef = useRef(null); + const queryResults: ChunkResults = {}; + const handleMainWorkerResp = useCallback((ev: MessageEvent) => { const {code, args} = ev.data; console.log(`[MainWorker -> Renderer] code=${code}`); @@ -184,9 +187,14 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { updateLogEventNumInUrl(lastLogEventNum, logEventNumRef.current); break; } - case WORKER_RESP_CODE.QUERY_RESULT: - // eslint-disable-next-line no-warning-comments - // TODO: Handle query results + case WORKER_RESP_CODE.CHUNK_RESULT: + for (const [pageNumStr, results] of Object.entries(args)) { + const pageNum = parseInt(pageNumStr, 10); + if (!queryResults[pageNum]) { + queryResults[pageNum] = []; + } + queryResults[pageNum].push(...results); + } break; default: console.error(`Unexpected ev.data: ${JSON.stringify(ev.data)}`); diff --git a/new-log-viewer/src/services/LogFileManager.ts b/new-log-viewer/src/services/LogFileManager.ts index f794aa88..7546d2dd 100644 --- a/new-log-viewer/src/services/LogFileManager.ts +++ b/new-log-viewer/src/services/LogFileManager.ts @@ -63,6 +63,8 @@ class LogFileManager { #queryId: number = 0; + readonly #chunkResultsHandler: (chunkResults: ChunkResults) => void; + #decoder: Decoder; /** @@ -72,15 +74,19 @@ class LogFileManager { * @param decoder * @param fileName * @param pageSize Page size for setting up pagination. + * @param queryResultHandler + * @param chunkResultsHandler */ constructor ( decoder: Decoder, fileName: string, pageSize: number, + chunkResultsHandler: (chunkResults: ChunkResults) => void, ) { + this.#decoder = decoder; this.#fileName = fileName; this.#pageSize = pageSize; - this.#decoder = decoder; + this.#chunkResultsHandler = chunkResultsHandler; // Build index for the entire file const buildIdxResult = decoder.buildIdx(0, LOG_EVENT_FILE_END_IDX); @@ -107,17 +113,20 @@ class LogFileManager { * File object. * @param pageSize Page size for setting up pagination. * @param decoderOptions Initial decoder options. + * @param queryResultHandler + * @param chunkResultsHandler * @return A Promise that resolves to the created LogFileManager instance. */ static async create ( fileSrc: FileSrcType, pageSize: number, - decoderOptions: DecoderOptionsType + decoderOptions: DecoderOptionsType, + chunkResultsHandler: (chunkResults: ChunkResults) => void, ): Promise { const {fileName, fileData} = await loadFile(fileSrc); const decoder = await LogFileManager.#initDecoder(fileName, fileData, decoderOptions); - return new LogFileManager(decoder, fileName, pageSize); + return new LogFileManager(decoder, fileName, pageSize, chunkResultsHandler); } /** @@ -279,9 +288,9 @@ class LogFileManager { * @param searchRegex The regular expression to search * @return */ - #searchChunk (queryId: number, beginSearchIdx: number, searchRegex: RegExp): ChunkResults | null { + #searchChunk (queryId: number, beginSearchIdx: number, searchRegex: RegExp): void { if (queryId !== this.#queryId) { - return null; + return; } const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); @@ -312,7 +321,7 @@ class LogFileManager { }); } - return results; + this.#chunkResultsHandler(results); } /** diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index 4182c6f6..0c4c3a7b 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -4,6 +4,7 @@ import dayjsUtc from "dayjs/plugin/utc"; import {LOG_LEVEL} from "../typings/logs"; import { + ChunkResults, MainWorkerReqMessage, WORKER_REQ_CODE, WORKER_RESP_CODE, @@ -37,13 +38,13 @@ const postResp = ( }; -// FIXME: pass this to the constructor / factory function of LogFileManager or the LogFileManager.search(onQueryResult) method? /** + * Post a response of a query chunk. * - * @param queryResult + * @param chunkResults */ -const handleQueryResult = (queryResult: string[]) => { - postResp(WORKER_RESP_CODE.QUERY_RESULT, queryResult); +const handleChunkResult = (chunkResults: ChunkResults) => { + postResp(WORKER_RESP_CODE.CHUNK_RESULT, chunkResults); }; // eslint-disable-next-line no-warning-comments @@ -77,7 +78,8 @@ onmessage = async (ev: MessageEvent) => { LOG_FILE_MANAGER = await LogFileManager.create( args.fileSrc, args.pageSize, - args.decoderOptions + args.decoderOptions, + handleChunkResult ); postResp(WORKER_RESP_CODE.LOG_FILE_INFO, { diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index 8ed12d35..c9c902d3 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -49,7 +49,7 @@ enum WORKER_RESP_CODE { LOG_FILE_INFO = "fileInfo", NOTIFICATION = "notification", PAGE_DATA = "pageData", - QUERY_RESULT = "queryResult", + CHUNK_RESULT = "chunkResult", } type WorkerReqMap = { @@ -97,9 +97,7 @@ type WorkerRespMap = { beginLineNumToLogEventNum: BeginLineNumToLogEventNumMap, cursorLineNum: number }, - [WORKER_RESP_CODE.QUERY_RESULT]: { - chunkResults: ChunkResults, - } + [WORKER_RESP_CODE.CHUNK_RESULT]: ChunkResults, }; type WorkerReq = T extends keyof WorkerReqMap ? From 5e4571a9ac502c6e9c6cc3880e5ce6f6e8b194a8 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:37:17 -0400 Subject: [PATCH 05/27] queryResults should useRef --- new-log-viewer/src/contexts/StateContextProvider.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index c05b9835..571ffec5 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -158,7 +158,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { const logExportManagerRef = useRef(null); const mainWorkerRef = useRef(null); - const queryResults: ChunkResults = {}; + const queryResults = useRef({}); const handleMainWorkerResp = useCallback((ev: MessageEvent) => { const {code, args} = ev.data; @@ -190,10 +190,10 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { case WORKER_RESP_CODE.CHUNK_RESULT: for (const [pageNumStr, results] of Object.entries(args)) { const pageNum = parseInt(pageNumStr, 10); - if (!queryResults[pageNum]) { - queryResults[pageNum] = []; + if (!queryResults.current[pageNum]) { + queryResults.current[pageNum] = []; } - queryResults[pageNum].push(...results); + queryResults.current[pageNum].push(...results); } break; default: From 6be07e9ac8f16b4710f9c48956a64a5bca5526f0 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:41:20 -0400 Subject: [PATCH 06/27] add test query icon to menubar --- new-log-viewer/src/components/MenuBar/index.tsx | 8 +++++++- .../src/contexts/StateContextProvider.tsx | 17 +++++++++++++++++ new-log-viewer/src/typings/worker.ts | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/new-log-viewer/src/components/MenuBar/index.tsx b/new-log-viewer/src/components/MenuBar/index.tsx index e2a21487..34010f5a 100644 --- a/new-log-viewer/src/components/MenuBar/index.tsx +++ b/new-log-viewer/src/components/MenuBar/index.tsx @@ -12,6 +12,7 @@ import { import DescriptionIcon from "@mui/icons-material/Description"; import FileOpenIcon from "@mui/icons-material/FileOpen"; +import SearchIcon from "@mui/icons-material/Search"; import SettingsIcon from "@mui/icons-material/Settings"; import {StateContext} from "../../contexts/StateContextProvider"; @@ -31,7 +32,7 @@ import "./index.css"; * @return */ const MenuBar = () => { - const {fileName, loadFile} = useContext(StateContext); + const {fileName, loadFile, queryLogs} = useContext(StateContext); const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false); @@ -78,6 +79,11 @@ const MenuBar = () => { + queryLogs} + > + + void, loadFile: (fileSrc: FileSrcType, cursor: CursorType) => void, loadPage: (newPageNum: number) => void, + queryLogs: () => void, } const StateContext = createContext({} as StateContextType); @@ -70,6 +71,7 @@ const STATE_DEFAULT: Readonly = Object.freeze({ exportLogs: () => null, loadFile: () => null, loadPage: () => null, + queryLogs: () => null, }); interface StateContextProviderProps { @@ -188,6 +190,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { break; } case WORKER_RESP_CODE.CHUNK_RESULT: + console.log(`[MainWorker -> Renderer] CHUNK_RESULT: ${JSON.stringify(args)}`); for (const [pageNumStr, results] of Object.entries(args)) { const pageNum = parseInt(pageNumStr, 10); if (!queryResults.current[pageNum]) { @@ -202,6 +205,19 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { } }, []); + const queryLogs = useCallback(() => { + if (null === mainWorkerRef.current) { + console.error("Unexpected null mainWorkerRef.current"); + + return; + } + workerPostReq(mainWorkerRef.current, WORKER_REQ_CODE.QUERY_LOG, { + searchString: "scheduling", + isRegex: false, + isCaseSensitive: false, + }); + }, []); + const exportLogs = useCallback(() => { if (null === mainWorkerRef.current) { console.error("Unexpected null mainWorkerRef.current"); @@ -347,6 +363,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { exportLogs: exportLogs, loadFile: loadFile, loadPage: loadPage, + queryLogs: queryLogs, }} > {children} diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index c9c902d3..babd135b 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -67,9 +67,9 @@ type WorkerReqMap = { decoderOptions?: DecoderOptionsType }, [WORKER_REQ_CODE.QUERY_LOG]: { - isCaseSensitive: boolean, searchString: string, isRegex: boolean, + isCaseSensitive: boolean, } }; From 908ee7aa2fcd5dd21c11078edb40132543ded659 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:47:29 -0400 Subject: [PATCH 07/27] fix query log button, query logs now appear properly in console --- new-log-viewer/src/components/MenuBar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-log-viewer/src/components/MenuBar/index.tsx b/new-log-viewer/src/components/MenuBar/index.tsx index 34010f5a..a85f941b 100644 --- a/new-log-viewer/src/components/MenuBar/index.tsx +++ b/new-log-viewer/src/components/MenuBar/index.tsx @@ -80,7 +80,7 @@ const MenuBar = () => { queryLogs} + onClick={queryLogs} > From da20db49e009c4efa0b4af34e301b0df49c44245 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Sun, 6 Oct 2024 12:06:53 -0400 Subject: [PATCH 08/27] remove console logs, rename handleChunkResult to chunkResultsHandler to match naming, clean up jsdoc --- new-log-viewer/src/contexts/StateContextProvider.tsx | 3 +-- new-log-viewer/src/services/LogFileManager.ts | 4 +--- new-log-viewer/src/services/MainWorker.ts | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index aa29e799..a0beff40 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -190,7 +190,6 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { break; } case WORKER_RESP_CODE.CHUNK_RESULT: - console.log(`[MainWorker -> Renderer] CHUNK_RESULT: ${JSON.stringify(args)}`); for (const [pageNumStr, results] of Object.entries(args)) { const pageNum = parseInt(pageNumStr, 10); if (!queryResults.current[pageNum]) { @@ -212,7 +211,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { return; } workerPostReq(mainWorkerRef.current, WORKER_REQ_CODE.QUERY_LOG, { - searchString: "scheduling", + searchString: "scheduled", isRegex: false, isCaseSensitive: false, }); diff --git a/new-log-viewer/src/services/LogFileManager.ts b/new-log-viewer/src/services/LogFileManager.ts index 7546d2dd..fc4688c3 100644 --- a/new-log-viewer/src/services/LogFileManager.ts +++ b/new-log-viewer/src/services/LogFileManager.ts @@ -74,7 +74,6 @@ class LogFileManager { * @param decoder * @param fileName * @param pageSize Page size for setting up pagination. - * @param queryResultHandler * @param chunkResultsHandler */ constructor ( @@ -113,7 +112,6 @@ class LogFileManager { * File object. * @param pageSize Page size for setting up pagination. * @param decoderOptions Initial decoder options. - * @param queryResultHandler * @param chunkResultsHandler * @return A Promise that resolves to the created LogFileManager instance. */ @@ -298,7 +296,7 @@ class LogFileManager { for (let eventIdx = beginSearchIdx; eventIdx < endSearchIdx; eventIdx++) { const contentString = this.#decoder.decode(eventIdx, eventIdx + 1)?.[0]?.[0] || ""; - + console.log(`Searching: ${contentString}`); const match = contentString.match(searchRegex); if (match && match.index) { const logEventNum = eventIdx + 1; diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index 0c4c3a7b..bcb42915 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -43,7 +43,7 @@ const postResp = ( * * @param chunkResults */ -const handleChunkResult = (chunkResults: ChunkResults) => { +const chunkResultsHandler = (chunkResults: ChunkResults) => { postResp(WORKER_RESP_CODE.CHUNK_RESULT, chunkResults); }; @@ -79,7 +79,7 @@ onmessage = async (ev: MessageEvent) => { args.fileSrc, args.pageSize, args.decoderOptions, - handleChunkResult + chunkResultsHandler ); postResp(WORKER_RESP_CODE.LOG_FILE_INFO, { From 5bf7df13d6b882f8f23eaf344a713de8ffb4d7a7 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Sun, 6 Oct 2024 12:09:32 -0400 Subject: [PATCH 09/27] remove console logs in debugging --- new-log-viewer/src/services/LogFileManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/new-log-viewer/src/services/LogFileManager.ts b/new-log-viewer/src/services/LogFileManager.ts index fc4688c3..97b79a4d 100644 --- a/new-log-viewer/src/services/LogFileManager.ts +++ b/new-log-viewer/src/services/LogFileManager.ts @@ -296,7 +296,6 @@ class LogFileManager { for (let eventIdx = beginSearchIdx; eventIdx < endSearchIdx; eventIdx++) { const contentString = this.#decoder.decode(eventIdx, eventIdx + 1)?.[0]?.[0] || ""; - console.log(`Searching: ${contentString}`); const match = contentString.match(searchRegex); if (match && match.index) { const logEventNum = eventIdx + 1; From 9a3cca9ff19b538c6789a1a70dbef227fc8c89a7 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:29:49 -0400 Subject: [PATCH 10/27] address suggested changes in pr --- new-log-viewer/src/services/LogFileManager.ts | 4 ++-- new-log-viewer/src/services/MainWorker.ts | 7 +++++++ new-log-viewer/src/typings/worker.ts | 6 +++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/new-log-viewer/src/services/LogFileManager.ts b/new-log-viewer/src/services/LogFileManager.ts index 97b79a4d..cf96a134 100644 --- a/new-log-viewer/src/services/LogFileManager.ts +++ b/new-log-viewer/src/services/LogFileManager.ts @@ -23,7 +23,7 @@ import ClpIrDecoder from "./decoders/ClpIrDecoder"; import JsonlDecoder from "./decoders/JsonlDecoder"; -const SEARCH_CHUNK_SIZE = 1000; +const SEARCH_CHUNK_SIZE = 10000; /** * Loads a file from a given source. @@ -297,7 +297,7 @@ class LogFileManager { for (let eventIdx = beginSearchIdx; eventIdx < endSearchIdx; eventIdx++) { const contentString = this.#decoder.decode(eventIdx, eventIdx + 1)?.[0]?.[0] || ""; const match = contentString.match(searchRegex); - if (match && match.index) { + if (match && "number" === typeof match.index) { const logEventNum = eventIdx + 1; const pageNum = Math.ceil(logEventNum / this.#pageSize); if (!results[pageNum]) { diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index bcb42915..10c4a5a3 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -108,6 +108,13 @@ onmessage = async (ev: MessageEvent) => { if (null === LOG_FILE_MANAGER) { throw new Error("Log file manager hasn't been initialized"); } + if ( + "string" !== typeof args.searchString || + "boolean" !== typeof args.isRegex || + "boolean" !== typeof args.isCaseSensitive + ) { + throw new Error("Invalid arguments for QUERY_LOG"); + } LOG_FILE_MANAGER.startQuery( args.searchString, args.isRegex, diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index babd135b..67a6cbe6 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -70,7 +70,7 @@ type WorkerReqMap = { searchString: string, isRegex: boolean, isCaseSensitive: boolean, - } + }, }; type ChunkResultType = { @@ -90,12 +90,12 @@ type WorkerRespMap = { }, [WORKER_RESP_CODE.NOTIFICATION]: { logLevel: LOG_LEVEL, - message: string + message: string, }, [WORKER_RESP_CODE.PAGE_DATA]: { logs: string, beginLineNumToLogEventNum: BeginLineNumToLogEventNumMap, - cursorLineNum: number + cursorLineNum: number, }, [WORKER_RESP_CODE.CHUNK_RESULT]: ChunkResults, }; From 8aa0c14756b6afd2010906e7460f90d468c8d4ff Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:02:25 -0400 Subject: [PATCH 11/27] add parameters for queryLogs() --- new-log-viewer/src/components/MenuBar/index.tsx | 6 +++++- .../src/contexts/StateContextProvider.tsx | 17 +++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/new-log-viewer/src/components/MenuBar/index.tsx b/new-log-viewer/src/components/MenuBar/index.tsx index a85f941b..f95f6324 100644 --- a/new-log-viewer/src/components/MenuBar/index.tsx +++ b/new-log-viewer/src/components/MenuBar/index.tsx @@ -36,6 +36,10 @@ const MenuBar = () => { const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false); + const handleSearchButtonClick = () => { + queryLogs("scheduled", false, false); + }; + const handleOpenFileButtonClick = () => { openFile((file) => { loadFile(file, {code: CURSOR_CODE.LAST_EVENT, args: null}); @@ -80,7 +84,7 @@ const MenuBar = () => { diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index a0beff40..f7aa9254 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -52,7 +52,7 @@ interface StateContextType { exportLogs: () => void, loadFile: (fileSrc: FileSrcType, cursor: CursorType) => void, loadPage: (newPageNum: number) => void, - queryLogs: () => void, + queryLogs: (searchString: string, isRegex: boolean, isCaseSensitive: boolean) => void, } const StateContext = createContext({} as StateContextType); @@ -140,7 +140,7 @@ const workerPostReq = ( * @param props.children * @return */ -// eslint-disable-next-line max-lines-per-function +// eslint-disable-next-line max-lines-per-function,max-statements const StateContextProvider = ({children}: StateContextProviderProps) => { const {filePath, logEventNum} = useContext(UrlContext); @@ -190,6 +190,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { break; } case WORKER_RESP_CODE.CHUNK_RESULT: + console.log(`[MainWorker -> Renderer] CHUNK_RESULT: ${JSON.stringify(args)}`); for (const [pageNumStr, results] of Object.entries(args)) { const pageNum = parseInt(pageNumStr, 10); if (!queryResults.current[pageNum]) { @@ -204,16 +205,20 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { } }, []); - const queryLogs = useCallback(() => { + const queryLogs = useCallback(( + searchString: string, + isRegex: boolean, + isCaseSensitive: boolean + ) => { if (null === mainWorkerRef.current) { console.error("Unexpected null mainWorkerRef.current"); return; } workerPostReq(mainWorkerRef.current, WORKER_REQ_CODE.QUERY_LOG, { - searchString: "scheduled", - isRegex: false, - isCaseSensitive: false, + searchString: searchString, + isRegex: isRegex, + isCaseSensitive: isCaseSensitive, }); }, []); From 38fe8e198701e1401f7caff74c14e6526bcd5934 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:39:22 -0400 Subject: [PATCH 12/27] address part of the suggestions in code review --- .../src/components/MenuBar/index.tsx | 4 +-- .../src/contexts/StateContextProvider.tsx | 31 +++++++++++-------- new-log-viewer/src/services/LogFileManager.ts | 30 ++++++++---------- new-log-viewer/src/services/MainWorker.ts | 6 ++-- new-log-viewer/src/typings/worker.ts | 8 ++--- 5 files changed, 40 insertions(+), 39 deletions(-) diff --git a/new-log-viewer/src/components/MenuBar/index.tsx b/new-log-viewer/src/components/MenuBar/index.tsx index f95f6324..6340839a 100644 --- a/new-log-viewer/src/components/MenuBar/index.tsx +++ b/new-log-viewer/src/components/MenuBar/index.tsx @@ -32,12 +32,12 @@ import "./index.css"; * @return */ const MenuBar = () => { - const {fileName, loadFile, queryLogs} = useContext(StateContext); + const {fileName, loadFile, startQuery} = useContext(StateContext); const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false); const handleSearchButtonClick = () => { - queryLogs("scheduled", false, false); + startQuery("scheduled", false, false); }; const handleOpenFileButtonClick = () => { diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index f7aa9254..81abdb8d 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -52,7 +52,7 @@ interface StateContextType { exportLogs: () => void, loadFile: (fileSrc: FileSrcType, cursor: CursorType) => void, loadPage: (newPageNum: number) => void, - queryLogs: (searchString: string, isRegex: boolean, isCaseSensitive: boolean) => void, + startQuery: (searchString: string, isRegex: boolean, isCaseSensitive: boolean) => void, } const StateContext = createContext({} as StateContextType); @@ -71,7 +71,7 @@ const STATE_DEFAULT: Readonly = Object.freeze({ exportLogs: () => null, loadFile: () => null, loadPage: () => null, - queryLogs: () => null, + startQuery: () => null, }); interface StateContextProviderProps { @@ -160,7 +160,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { const logExportManagerRef = useRef(null); const mainWorkerRef = useRef(null); - const queryResults = useRef({}); + const [queryResults, setQueryResults] = useState({}); const handleMainWorkerResp = useCallback((ev: MessageEvent) => { const {code, args} = ev.data; @@ -191,13 +191,18 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { } case WORKER_RESP_CODE.CHUNK_RESULT: console.log(`[MainWorker -> Renderer] CHUNK_RESULT: ${JSON.stringify(args)}`); - for (const [pageNumStr, results] of Object.entries(args)) { - const pageNum = parseInt(pageNumStr, 10); - if (!queryResults.current[pageNum]) { - queryResults.current[pageNum] = []; - } - queryResults.current[pageNum].push(...results); - } + setQueryResults((prevQueryResults) => { + const newQueryResults = {...prevQueryResults}; + Object.entries(args).forEach(([pageNumStr, results]) => { + const pageNum = parseInt(pageNumStr, 10); + if (!newQueryResults[pageNum]) { + newQueryResults[pageNum] = []; + } + newQueryResults[pageNum].push(...results); + }); + + return newQueryResults; + }); break; default: console.error(`Unexpected ev.data: ${JSON.stringify(ev.data)}`); @@ -205,7 +210,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { } }, []); - const queryLogs = useCallback(( + const startQuery = useCallback(( searchString: string, isRegex: boolean, isCaseSensitive: boolean @@ -215,7 +220,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { return; } - workerPostReq(mainWorkerRef.current, WORKER_REQ_CODE.QUERY_LOG, { + workerPostReq(mainWorkerRef.current, WORKER_REQ_CODE.START_QUERY, { searchString: searchString, isRegex: isRegex, isCaseSensitive: isCaseSensitive, @@ -367,7 +372,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { exportLogs: exportLogs, loadFile: loadFile, loadPage: loadPage, - queryLogs: queryLogs, + startQuery: startQuery, }} > {children} diff --git a/new-log-viewer/src/services/LogFileManager.ts b/new-log-viewer/src/services/LogFileManager.ts index cf96a134..6d4ac113 100644 --- a/new-log-viewer/src/services/LogFileManager.ts +++ b/new-log-viewer/src/services/LogFileManager.ts @@ -63,7 +63,7 @@ class LogFileManager { #queryId: number = 0; - readonly #chunkResultsHandler: (chunkResults: ChunkResults) => void; + readonly #onQueryResults: (chunkResults: ChunkResults) => void; #decoder: Decoder; @@ -74,18 +74,18 @@ class LogFileManager { * @param decoder * @param fileName * @param pageSize Page size for setting up pagination. - * @param chunkResultsHandler + * @param onQueryResults */ constructor ( decoder: Decoder, fileName: string, pageSize: number, - chunkResultsHandler: (chunkResults: ChunkResults) => void, + onQueryResults: (chunkResults: ChunkResults) => void, ) { this.#decoder = decoder; this.#fileName = fileName; this.#pageSize = pageSize; - this.#chunkResultsHandler = chunkResultsHandler; + this.#onQueryResults = onQueryResults; // Build index for the entire file const buildIdxResult = decoder.buildIdx(0, LOG_EVENT_FILE_END_IDX); @@ -112,19 +112,19 @@ class LogFileManager { * File object. * @param pageSize Page size for setting up pagination. * @param decoderOptions Initial decoder options. - * @param chunkResultsHandler + * @param onQueryResults * @return A Promise that resolves to the created LogFileManager instance. */ static async create ( fileSrc: FileSrcType, pageSize: number, decoderOptions: DecoderOptionsType, - chunkResultsHandler: (chunkResults: ChunkResults) => void, + onQueryResults: (chunkResults: ChunkResults) => void, ): Promise { const {fileName, fileData} = await loadFile(fileSrc); const decoder = await LogFileManager.#initDecoder(fileName, fileData, decoderOptions); - return new LogFileManager(decoder, fileName, pageSize, chunkResultsHandler); + return new LogFileManager(decoder, fileName, pageSize, onQueryResults); } /** @@ -168,10 +168,6 @@ class LogFileManager { this.#decoder.setDecoderOptions(options); } - incrementQueryId () { - this.#queryId++; - } - /** * Loads log events in the range * [`beginLogEventIdx`, `beginLogEventIdx + EXPORT_LOGS_CHUNK_SIZE`), or all remaining log @@ -258,7 +254,7 @@ class LogFileManager { * @return An object containing the search results. */ startQuery (searchString: string, isRegex: boolean, matchCase: boolean): void { - this.incrementQueryId(); + this.#queryId++; // If the search string is empty, or there are no logs, return if ("" === searchString) { @@ -275,18 +271,18 @@ class LogFileManager { "" : "i"; const searchRegex = new RegExp(regexPattern, regexFlags); - this.#searchChunk(this.#queryId, 0, searchRegex); + this.#searchChunkAndScheduleNext(this.#queryId, 0, searchRegex); } /** - * Searches for log events in the given range. + * Searches for log events in the given range, then schedules itself to search the next chunk. * * @param queryId * @param beginSearchIdx The beginning index of the search range. * @param searchRegex The regular expression to search * @return */ - #searchChunk (queryId: number, beginSearchIdx: number, searchRegex: RegExp): void { + #searchChunkAndScheduleNext (queryId: number, beginSearchIdx: number, searchRegex: RegExp): void { if (queryId !== this.#queryId) { return; } @@ -314,11 +310,11 @@ class LogFileManager { if (endSearchIdx < this.#numEvents) { defer(() => { - this.#searchChunk(queryId, endSearchIdx, searchRegex); + this.#searchChunkAndScheduleNext(queryId, endSearchIdx, searchRegex); }); } - this.#chunkResultsHandler(results); + this.#onQueryResults(results); } /** diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index 10c4a5a3..8c6d3dd8 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -43,7 +43,7 @@ const postResp = ( * * @param chunkResults */ -const chunkResultsHandler = (chunkResults: ChunkResults) => { +const onQueryResults = (chunkResults: ChunkResults) => { postResp(WORKER_RESP_CODE.CHUNK_RESULT, chunkResults); }; @@ -79,7 +79,7 @@ onmessage = async (ev: MessageEvent) => { args.fileSrc, args.pageSize, args.decoderOptions, - chunkResultsHandler + onQueryResults ); postResp(WORKER_RESP_CODE.LOG_FILE_INFO, { @@ -104,7 +104,7 @@ onmessage = async (ev: MessageEvent) => { LOG_FILE_MANAGER.loadPage(args.cursor) ); break; - case WORKER_REQ_CODE.QUERY_LOG: + case WORKER_REQ_CODE.START_QUERY: if (null === LOG_FILE_MANAGER) { throw new Error("Log file manager hasn't been initialized"); } diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index 67a6cbe6..bf025689 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -41,7 +41,7 @@ enum WORKER_REQ_CODE { EXPORT_LOG = "exportLog", LOAD_FILE = "loadFile", LOAD_PAGE = "loadPage", - QUERY_LOG = "queryLog", + START_QUERY = "startQuery", } enum WORKER_RESP_CODE { @@ -66,7 +66,7 @@ type WorkerReqMap = { cursor: CursorType, decoderOptions?: DecoderOptionsType }, - [WORKER_REQ_CODE.QUERY_LOG]: { + [WORKER_REQ_CODE.START_QUERY]: { searchString: string, isRegex: boolean, isCaseSensitive: boolean, @@ -74,8 +74,8 @@ type WorkerReqMap = { }; type ChunkResultType = { - logEventNum: number; - message: string; + logEventNum: number, + message: string, matchRange: [number, number]; }; type ChunkResults = Record; From fb14c88c22db8b14a4e6b9131907864946ba4890 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Wed, 9 Oct 2024 13:53:09 -0400 Subject: [PATCH 13/27] minor fixes --- new-log-viewer/src/typings/worker.ts | 4 +++- new-log-viewer/src/utils/time.ts | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index bf025689..ae15d380 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -73,10 +73,12 @@ type WorkerReqMap = { }, }; +type TextRange = [number, number]; + type ChunkResultType = { logEventNum: number, message: string, - matchRange: [number, number]; + matchRange: TextRange; }; type ChunkResults = Record; diff --git a/new-log-viewer/src/utils/time.ts b/new-log-viewer/src/utils/time.ts index ce7a6694..d3619fa5 100644 --- a/new-log-viewer/src/utils/time.ts +++ b/new-log-viewer/src/utils/time.ts @@ -1,9 +1,10 @@ /** * * @param callback + * @param callbackFn */ -const defer = (callback: ()=>void) => { - setTimeout(callback, 0); +const defer = (callbackFn: () => void) => { + setTimeout(callbackFn, 0); }; export {defer}; From 128687982bcc8c7cfa7cbd991155cb89b6ce1210 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:31:26 -0400 Subject: [PATCH 14/27] address suggestions from review after merge --- .../src/contexts/StateContextProvider.tsx | 14 +++++++------- .../src/services/LogFileManager/index.ts | 10 +++++----- new-log-viewer/src/typings/worker.ts | 7 ++++--- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index 7cd4d0ba..e10467d2 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -1,4 +1,4 @@ -/* eslint max-lines: ["error", 450] */ +/* eslint max-lines: ["error", 500] */ import React, { createContext, useCallback, @@ -278,14 +278,14 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { } case WORKER_RESP_CODE.CHUNK_RESULT: console.log(`[MainWorker -> Renderer] CHUNK_RESULT: ${JSON.stringify(args)}`); - setQueryResults((prevQueryResults) => { - const newQueryResults = {...prevQueryResults}; + setQueryResults(() => { + const newQueryResults = {...queryResults}; Object.entries(args).forEach(([pageNumStr, results]) => { - const pageNum = parseInt(pageNumStr, 10); - if (!newQueryResults[pageNum]) { - newQueryResults[pageNum] = []; + const chunkPageNum = parseInt(pageNumStr, 10); + if (!newQueryResults[chunkPageNum]) { + newQueryResults[chunkPageNum] = []; } - newQueryResults[pageNum].push(...results); + newQueryResults[chunkPageNum].push(...results); }); return newQueryResults; diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index fa083d25..6afb4e58 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -1,3 +1,4 @@ +/* eslint max-lines: ["error", 400] */ import { Decoder, DecoderOptionsType, @@ -17,7 +18,7 @@ import { } from "../../typings/worker"; import {EXPORT_LOGS_CHUNK_SIZE} from "../../utils/config"; import {getChunkNum} from "../../utils/math"; -import {defer} from "../utils/time"; +import {defer} from "../../utils/time"; import {formatSizeInBytes} from "../../utils/units"; import ClpIrDecoder from "../decoders/ClpIrDecoder"; import JsonlDecoder from "../decoders/JsonlDecoder"; @@ -28,6 +29,7 @@ import { loadFile, } from "./utils"; + const SEARCH_CHUNK_SIZE = 10000; /** @@ -263,7 +265,6 @@ class LogFileManager { * @param searchString The search string. * @param isRegex Whether the search string is a regular expression. * @param matchCase Whether the search is case-sensitive. - * @return An object containing the search results. */ startQuery (searchString: string, isRegex: boolean, matchCase: boolean): void { this.#queryId++; @@ -291,8 +292,7 @@ class LogFileManager { * * @param queryId * @param beginSearchIdx The beginning index of the search range. - * @param searchRegex The regular expression to search - * @return + * @param searchRegex The regular expression to search. */ #searchChunkAndScheduleNext (queryId: number, beginSearchIdx: number, searchRegex: RegExp): void { if (queryId !== this.#queryId) { @@ -303,7 +303,7 @@ class LogFileManager { const results: ChunkResults = {}; for (let eventIdx = beginSearchIdx; eventIdx < endSearchIdx; eventIdx++) { - const contentString = this.#decoder.decode(eventIdx, eventIdx + 1)?.[0]?.[0] || ""; + const contentString = this.#decoder.decodeRange(eventIdx, eventIdx + 1, false)?.[0]?.[0] || ""; const match = contentString.match(searchRegex); if (match && "number" === typeof match.index) { const logEventNum = eventIdx + 1; diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index 47c7a676..63caaffe 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -107,11 +107,12 @@ type WorkerReqMap = { type TextRange = [number, number]; -type ChunkResultType = { +interface ChunkResultType { logEventNum: number, message: string, - matchRange: TextRange; -}; + matchRange: TextRange, +} + type ChunkResults = Record; type WorkerRespMap = { From 7ed8bafd723d60a140b749d5edc350558476ac7a Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:10:16 -0400 Subject: [PATCH 15/27] use Map instead of Object for query results --- .../src/contexts/StateContextProvider.tsx | 16 +++++------ .../src/services/LogFileManager/index.ts | 27 +++++++++---------- new-log-viewer/src/services/MainWorker.ts | 8 +++--- new-log-viewer/src/typings/worker.ts | 16 +++++------ 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index 30e9bb85..6ce0dd89 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -15,12 +15,12 @@ import {LogLevelFilter} from "../typings/logs"; import {SEARCH_PARAM_NAMES} from "../typings/url"; import { BeginLineNumToLogEventNumMap, - ChunkResults, CURSOR_CODE, CursorType, EVENT_POSITION_ON_PAGE, FileSrcType, MainWorkerRespMessage, + QueryResults, WORKER_REQ_CODE, WORKER_RESP_CODE, WorkerReq, @@ -77,6 +77,7 @@ const STATE_DEFAULT: Readonly = Object.freeze({ numPages: 0, onDiskFileSizeInBytes: 0, pageNum: 0, + queryResults: new Map(), exportLogs: () => null, loadFile: () => null, @@ -248,7 +249,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { const logExportManagerRef = useRef(null); const mainWorkerRef = useRef(null); - const [queryResults, setQueryResults] = useState({}); + const [queryResults, setQueryResults] = useState(new Map()); const handleMainWorkerResp = useCallback((ev: MessageEvent) => { const {code, args} = ev.data; @@ -281,16 +282,15 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { }); break; } - case WORKER_RESP_CODE.CHUNK_RESULT: + case WORKER_RESP_CODE.QUERY_RESULT: console.log(`[MainWorker -> Renderer] CHUNK_RESULT: ${JSON.stringify(args)}`); setQueryResults(() => { const newQueryResults = {...queryResults}; - Object.entries(args).forEach(([pageNumStr, results]) => { - const chunkPageNum = parseInt(pageNumStr, 10); - if (!newQueryResults[chunkPageNum]) { - newQueryResults[chunkPageNum] = []; + args.forEach((results, queryPageNum) => { + if (false === newQueryResults.has(queryPageNum)) { + newQueryResults.set(queryPageNum, []); } - newQueryResults[chunkPageNum].push(...results); + newQueryResults.get(queryPageNum)?.push(...results); }); return newQueryResults; diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index db21120d..7c04d7a1 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -7,12 +7,12 @@ import {MAX_V8_STRING_LENGTH} from "../../typings/js"; import {LogLevelFilter} from "../../typings/logs"; import { BeginLineNumToLogEventNumMap, - ChunkResults, CURSOR_CODE, CursorData, CursorType, EMPTY_PAGE_RESP, FileSrcType, + QueryResults, WORKER_RESP_CODE, WorkerResp, } from "../../typings/worker"; @@ -46,7 +46,7 @@ class LogFileManager { readonly #onDiskFileSizeInBytes: number; - readonly #onQueryResults: (chunkResults: ChunkResults) => void; + readonly #onQueryResults: (queryResults: QueryResults) => void; #decoder: Decoder; @@ -65,7 +65,7 @@ class LogFileManager { fileName: string, onDiskFileSizeInBytes: number, pageSize: number, - onQueryResults: (chunkResults: ChunkResults) => void, + onQueryResults: (queryResults: QueryResults) => void, ) { this.#decoder = decoder; this.#fileName = fileName; @@ -109,7 +109,7 @@ class LogFileManager { fileSrc: FileSrcType, pageSize: number, decoderOptions: DecoderOptionsType, - onQueryResults: (chunkResults: ChunkResults) => void, + onQueryResults: (queryResults: QueryResults) => void, ): Promise { const {fileName, fileData} = await loadFile(fileSrc); const decoder = await LogFileManager.#initDecoder(fileName, fileData, decoderOptions); @@ -309,25 +309,24 @@ class LogFileManager { } const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); - const results: ChunkResults = {}; + const results: QueryResults = new Map(); + const decodedEvents = this.#decoder.decodeRange(beginSearchIdx, endSearchIdx, true); - for (let eventIdx = beginSearchIdx; eventIdx < endSearchIdx; eventIdx++) { - const contentString = this.#decoder.decodeRange(eventIdx, eventIdx + 1, false)?.[0]?.[0] || ""; - const match = contentString.match(searchRegex); + decodedEvents?.forEach(([message, , , logEventNum]) => { + const match = message.match(searchRegex); if (match && "number" === typeof match.index) { - const logEventNum = eventIdx + 1; const pageNum = Math.ceil(logEventNum / this.#pageSize); - if (!results[pageNum]) { - results[pageNum] = []; + if (false === results.has(pageNum)) { + results.set(pageNum, []); } - results[pageNum].push({ + results.get(pageNum)?.push({ logEventNum: logEventNum, - message: contentString, + message: message, matchRange: [match.index, (match.index + match[0].length)], }); } - } + }); if (endSearchIdx < this.#numEvents) { defer(() => { diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index a9530821..82da6c08 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -4,8 +4,8 @@ import dayjsUtc from "dayjs/plugin/utc"; import {LOG_LEVEL} from "../typings/logs"; import { - ChunkResults, MainWorkerReqMessage, + QueryResults, WORKER_REQ_CODE, WORKER_RESP_CODE, WorkerResp, @@ -41,10 +41,10 @@ const postResp = ( /** * Post a response of a query chunk. * - * @param chunkResults + * @param queryResults */ -const onQueryResults = (chunkResults: ChunkResults) => { - postResp(WORKER_RESP_CODE.CHUNK_RESULT, chunkResults); +const onQueryResults = (queryResults: QueryResults) => { + postResp(WORKER_RESP_CODE.QUERY_RESULT, queryResults); }; // eslint-disable-next-line no-warning-comments diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index 187ea8fb..23719c92 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -80,7 +80,7 @@ enum WORKER_RESP_CODE { LOG_FILE_INFO = "fileInfo", NOTIFICATION = "notification", PAGE_DATA = "pageData", - CHUNK_RESULT = "chunkResult", + QUERY_RESULT = "queryResult", } type WorkerReqMap = { @@ -107,13 +107,13 @@ type WorkerReqMap = { type TextRange = [number, number]; -interface ChunkResultType { - logEventNum: number, - message: string, - matchRange: TextRange, +interface QueryResultsType { + logEventNum: number; + message: string; + matchRange: TextRange; } -type ChunkResults = Record; +type QueryResults = Map; type WorkerRespMap = { [WORKER_RESP_CODE.CHUNK_DATA]: { @@ -136,7 +136,7 @@ type WorkerRespMap = { numPages: number, pageNum: number, }, - [WORKER_RESP_CODE.CHUNK_RESULT]: ChunkResults, + [WORKER_RESP_CODE.QUERY_RESULT]: QueryResults, }; type WorkerReq = T extends keyof WorkerReqMap ? @@ -177,12 +177,12 @@ export { }; export type { BeginLineNumToLogEventNumMap, - ChunkResults, CursorData, CursorType, FileSrcType, MainWorkerReqMessage, MainWorkerRespMessage, + QueryResults, WorkerReq, WorkerResp, }; From 46fe49f6263f34c036c1dc3df10ac1e4bac2c84a Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:09:46 -0400 Subject: [PATCH 16/27] fix queryResults not showing issue --- new-log-viewer/src/components/MenuBar/index.tsx | 13 ++++++++++++- .../src/contexts/StateContextProvider.tsx | 15 +++++++-------- .../src/services/LogFileManager/index.ts | 5 +++-- new-log-viewer/src/services/MainWorker.ts | 2 +- new-log-viewer/src/typings/worker.ts | 2 +- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/new-log-viewer/src/components/MenuBar/index.tsx b/new-log-viewer/src/components/MenuBar/index.tsx index aac5c979..46654183 100644 --- a/new-log-viewer/src/components/MenuBar/index.tsx +++ b/new-log-viewer/src/components/MenuBar/index.tsx @@ -9,6 +9,7 @@ import { } from "@mui/joy"; import FolderOpenIcon from "@mui/icons-material/FolderOpen"; +import SearchIcon from "@mui/icons-material/Search"; import {StateContext} from "../../contexts/StateContextProvider"; import {CURSOR_CODE} from "../../typings/worker"; @@ -25,7 +26,7 @@ import "./index.css"; * @return */ const MenuBar = () => { - const {fileName, loadFile} = useContext(StateContext); + const {fileName, loadFile, startQuery} = useContext(StateContext); const handleOpenFile = () => { openFile((file) => { @@ -33,6 +34,10 @@ const MenuBar = () => { }); }; + const handleQueryClick = () => { + startQuery("ERROR", false, false); + }; + return ( <> @@ -71,6 +76,12 @@ const MenuBar = () => { + + + ); diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index 6ce0dd89..42b10f1c 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -283,17 +283,16 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { break; } case WORKER_RESP_CODE.QUERY_RESULT: - console.log(`[MainWorker -> Renderer] CHUNK_RESULT: ${JSON.stringify(args)}`); - setQueryResults(() => { - const newQueryResults = {...queryResults}; - args.forEach((results, queryPageNum) => { - if (false === newQueryResults.has(queryPageNum)) { - newQueryResults.set(queryPageNum, []); + setQueryResults((v) => { + args.results.forEach((results, queryPageNum) => { + if (false === v.has(queryPageNum)) { + v.set(queryPageNum, []); } - newQueryResults.get(queryPageNum)?.push(...results); + v.get(queryPageNum)?.push(...results); }); + console.log(v); - return newQueryResults; + return v; }); break; default: diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index 7c04d7a1..46ec5f90 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -307,10 +307,10 @@ class LogFileManager { if (queryId !== this.#queryId) { return; } - + console.log("in #searchChunkAndScheduleNext"); const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); const results: QueryResults = new Map(); - const decodedEvents = this.#decoder.decodeRange(beginSearchIdx, endSearchIdx, true); + const decodedEvents = this.#decoder.decodeRange(beginSearchIdx, endSearchIdx, null !== this.#decoder.getFilteredLogEventMap()); decodedEvents?.forEach(([message, , , logEventNum]) => { const match = message.match(searchRegex); @@ -327,6 +327,7 @@ class LogFileManager { }); } }); + console.log(decodedEvents, results); if (endSearchIdx < this.#numEvents) { defer(() => { diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index 82da6c08..2c209853 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -44,7 +44,7 @@ const postResp = ( * @param queryResults */ const onQueryResults = (queryResults: QueryResults) => { - postResp(WORKER_RESP_CODE.QUERY_RESULT, queryResults); + postResp(WORKER_RESP_CODE.QUERY_RESULT, {results: queryResults}); }; // eslint-disable-next-line no-warning-comments diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index 23719c92..487965f4 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -136,7 +136,7 @@ type WorkerRespMap = { numPages: number, pageNum: number, }, - [WORKER_RESP_CODE.QUERY_RESULT]: QueryResults, + [WORKER_RESP_CODE.QUERY_RESULT]: { results: QueryResults }, }; type WorkerReq = T extends keyof WorkerReqMap ? From 9706bd084b62041fca8314d6b82eee484924d610 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:44:14 -0400 Subject: [PATCH 17/27] provide queryResults in StateContextProvider.tsx --- .../src/contexts/StateContextProvider.tsx | 8 +++++--- .../src/services/LogFileManager/index.ts | 18 +++++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index 42b10f1c..3f0ea5f4 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -56,6 +56,7 @@ interface StateContextType { numPages: number, onDiskFileSizeInBytes: number, pageNum: number, + queryResults: QueryResults, exportLogs: () => void, loadFile: (fileSrc: FileSrcType, cursor: CursorType) => void, @@ -230,6 +231,8 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { const {filePath, logEventNum} = useContext(UrlContext); // States + const [exportProgress, setExportProgress] = + useState>(STATE_DEFAULT.exportProgress); const [fileName, setFileName] = useState(STATE_DEFAULT.fileName); const [logData, setLogData] = useState(STATE_DEFAULT.logData); const [numEvents, setNumEvents] = useState(STATE_DEFAULT.numEvents); @@ -237,10 +240,9 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { const [onDiskFileSizeInBytes, setOnDiskFileSizeInBytes] = useState(STATE_DEFAULT.onDiskFileSizeInBytes); const [pageNum, setPageNum] = useState(STATE_DEFAULT.pageNum); + const [queryResults, setQueryResults] = useState(STATE_DEFAULT.queryResults); const beginLineNumToLogEventNumRef = useRef(STATE_DEFAULT.beginLineNumToLogEventNum); - const [exportProgress, setExportProgress] = - useState>(STATE_DEFAULT.exportProgress); // Refs const logEventNumRef = useRef(logEventNum); @@ -249,7 +251,6 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { const logExportManagerRef = useRef(null); const mainWorkerRef = useRef(null); - const [queryResults, setQueryResults] = useState(new Map()); const handleMainWorkerResp = useCallback((ev: MessageEvent) => { const {code, args} = ev.data; @@ -473,6 +474,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { numPages: numPages, onDiskFileSizeInBytes: onDiskFileSizeInBytes, pageNum: pageNum, + queryResults: queryResults, exportLogs: exportLogs, loadFile: loadFile, diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index 46ec5f90..22632ef4 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -54,19 +54,24 @@ class LogFileManager { * Private constructor for LogFileManager. This is not intended to be invoked publicly. * Instead, use LogFileManager.create() to create a new instance of the class. * + * @param decoder.decoder * @param decoder * @param fileName * @param onDiskFileSizeInBytes * @param onQueryResults * @param pageSize Page size for setting up pagination. + * @param decoder.fileName + * @param decoder.onDiskFileSizeInBytes + * @param decoder.pageSize + * @param decoder.onQueryResults */ - constructor ( + constructor ({decoder, fileName, onDiskFileSizeInBytes, pageSize, onQueryResults}: { decoder: Decoder, fileName: string, onDiskFileSizeInBytes: number, pageSize: number, onQueryResults: (queryResults: QueryResults) => void, - ) { + }) { this.#decoder = decoder; this.#fileName = fileName; this.#pageSize = pageSize; @@ -114,7 +119,14 @@ class LogFileManager { const {fileName, fileData} = await loadFile(fileSrc); const decoder = await LogFileManager.#initDecoder(fileName, fileData, decoderOptions); - return new LogFileManager(decoder, fileName, fileData.length, pageSize, onQueryResults); + return new LogFileManager({ + decoder: decoder, + fileName: fileName, + onDiskFileSizeInBytes: fileData.length, + pageSize: pageSize, + + onQueryResults: onQueryResults, + }); } /** From 8e91e83f066857f774e46811068ad9a3b8e371b0 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:26:12 -0400 Subject: [PATCH 18/27] fix lint errors --- .../src/services/LogFileManager/index.ts | 24 ++++++++++++------- new-log-viewer/src/utils/time.ts | 4 ++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index 22632ef4..3ad17a6e 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -58,8 +58,8 @@ class LogFileManager { * @param decoder * @param fileName * @param onDiskFileSizeInBytes - * @param onQueryResults * @param pageSize Page size for setting up pagination. + * @param onQueryResults * @param decoder.fileName * @param decoder.onDiskFileSizeInBytes * @param decoder.pageSize @@ -283,11 +283,11 @@ class LogFileManager { /** * Searches for log events based on the given search string. * - * @param searchString The search string. - * @param isRegex Whether the search string is a regular expression. - * @param matchCase Whether the search is case-sensitive. + * @param searchString + * @param isRegex + * @param isCaseSensitive */ - startQuery (searchString: string, isRegex: boolean, matchCase: boolean): void { + startQuery (searchString: string, isRegex: boolean, isCaseSensitive: boolean): void { this.#queryId++; // If the search string is empty, or there are no logs, return @@ -301,7 +301,7 @@ class LogFileManager { const regexPattern = isRegex ? searchString : searchString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); - const regexFlags = matchCase ? + const regexFlags = isCaseSensitive ? "" : "i"; const searchRegex = new RegExp(regexPattern, regexFlags); @@ -315,14 +315,22 @@ class LogFileManager { * @param beginSearchIdx The beginning index of the search range. * @param searchRegex The regular expression to search. */ - #searchChunkAndScheduleNext (queryId: number, beginSearchIdx: number, searchRegex: RegExp): void { + #searchChunkAndScheduleNext ( + queryId: number, + beginSearchIdx: number, + searchRegex: RegExp + ): void { if (queryId !== this.#queryId) { return; } console.log("in #searchChunkAndScheduleNext"); const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); const results: QueryResults = new Map(); - const decodedEvents = this.#decoder.decodeRange(beginSearchIdx, endSearchIdx, null !== this.#decoder.getFilteredLogEventMap()); + const decodedEvents = this.#decoder.decodeRange( + beginSearchIdx, + endSearchIdx, + null !== this.#decoder.getFilteredLogEventMap() + ); decodedEvents?.forEach(([message, , , logEventNum]) => { const match = message.match(searchRegex); diff --git a/new-log-viewer/src/utils/time.ts b/new-log-viewer/src/utils/time.ts index d3619fa5..27312a29 100644 --- a/new-log-viewer/src/utils/time.ts +++ b/new-log-viewer/src/utils/time.ts @@ -1,7 +1,7 @@ /** + * Defers the execution of a callback function until the call stack is clear. * - * @param callback - * @param callbackFn + * @param callbackFn The callback function to be deferred. */ const defer = (callbackFn: () => void) => { setTimeout(callbackFn, 0); From 8f60afc761e934f75013d257e25061a476a69d04 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:32:39 -0400 Subject: [PATCH 19/27] fix lint docstring --- .../src/services/LogFileManager/index.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index 3ad17a6e..91dd6885 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -54,16 +54,12 @@ class LogFileManager { * Private constructor for LogFileManager. This is not intended to be invoked publicly. * Instead, use LogFileManager.create() to create a new instance of the class. * - * @param decoder.decoder - * @param decoder - * @param fileName - * @param onDiskFileSizeInBytes - * @param pageSize Page size for setting up pagination. - * @param onQueryResults - * @param decoder.fileName - * @param decoder.onDiskFileSizeInBytes - * @param decoder.pageSize - * @param decoder.onQueryResults + * @param params + * @param params.decoder + * @param params.fileName + * @param params.onDiskFileSizeInBytes + * @param params.pageSize Page size for setting up pagination. + * @param params.onQueryResults The callback function to handle query results. */ constructor ({decoder, fileName, onDiskFileSizeInBytes, pageSize, onQueryResults}: { decoder: Decoder, From 3de7f80518277c24419c3f44add9c9f1b0b53837 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:50:36 -0400 Subject: [PATCH 20/27] Apply suggestions from code review Co-authored-by: Junhao Liao --- new-log-viewer/src/services/LogFileManager/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index 91dd6885..9b8a8507 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -287,9 +287,7 @@ class LogFileManager { this.#queryId++; // If the search string is empty, or there are no logs, return - if ("" === searchString) { - return; - } else if (0 === this.#numEvents) { + if ("" === searchString || 0 === this.#numEvents) { return; } @@ -301,6 +299,7 @@ class LogFileManager { "" : "i"; const searchRegex = new RegExp(regexPattern, regexFlags); + this.#searchChunkAndScheduleNext(this.#queryId, 0, searchRegex); } @@ -317,9 +316,9 @@ class LogFileManager { searchRegex: RegExp ): void { if (queryId !== this.#queryId) { + // Return directly if this search task no longer corresponds to the latest query in the LogFileManager. return; } - console.log("in #searchChunkAndScheduleNext"); const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); const results: QueryResults = new Map(); const decodedEvents = this.#decoder.decodeRange( @@ -343,7 +342,6 @@ class LogFileManager { }); } }); - console.log(decodedEvents, results); if (endSearchIdx < this.#numEvents) { defer(() => { From 3c6c53dc731644b14bfc6c102839a4870076779a Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:05:21 -0400 Subject: [PATCH 21/27] Apply suggestions from code review Co-authored-by: Junhao Liao --- new-log-viewer/src/contexts/StateContextProvider.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index 3f0ea5f4..b6306b0c 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -251,7 +251,6 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { const logExportManagerRef = useRef(null); const mainWorkerRef = useRef(null); - const handleMainWorkerResp = useCallback((ev: MessageEvent) => { const {code, args} = ev.data; console.log(`[MainWorker -> Renderer] code=${code}`); @@ -285,13 +284,12 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { } case WORKER_RESP_CODE.QUERY_RESULT: setQueryResults((v) => { - args.results.forEach((results, queryPageNum) => { + args.results.forEach((resultsPerPage, queryPageNum) => { if (false === v.has(queryPageNum)) { v.set(queryPageNum, []); } - v.get(queryPageNum)?.push(...results); + v.get(queryPageNum)?.push(...resultsPerPage); }); - console.log(v); return v; }); From e04f1691782302feedd2dc9ebbc925d08062e6c8 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:18:22 -0400 Subject: [PATCH 22/27] address rest of the comments --- new-log-viewer/src/index.tsx | 1 + .../src/services/LogFileManager/index.ts | 15 +++++++-------- new-log-viewer/src/utils/config.ts | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/new-log-viewer/src/index.tsx b/new-log-viewer/src/index.tsx index 4409e0de..04bcd05a 100644 --- a/new-log-viewer/src/index.tsx +++ b/new-log-viewer/src/index.tsx @@ -13,3 +13,4 @@ root.render( ); +export {SEARCH_CHUNK_SIZE} from "./utils/config"; diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index 9b8a8507..f41cb578 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -16,7 +16,10 @@ import { WORKER_RESP_CODE, WorkerResp, } from "../../typings/worker"; -import {EXPORT_LOGS_CHUNK_SIZE} from "../../utils/config"; +import { + EXPORT_LOGS_CHUNK_SIZE, + SEARCH_CHUNK_SIZE, +} from "../../utils/config"; import {getChunkNum} from "../../utils/math"; import {defer} from "../../utils/time"; import {formatSizeInBytes} from "../../utils/units"; @@ -30,8 +33,6 @@ import { } from "./utils"; -const SEARCH_CHUNK_SIZE = 10000; - /** * Class to manage the retrieval and decoding of a given log file. */ @@ -284,8 +285,6 @@ class LogFileManager { * @param isCaseSensitive */ startQuery (searchString: string, isRegex: boolean, isCaseSensitive: boolean): void { - this.#queryId++; - // If the search string is empty, or there are no logs, return if ("" === searchString || 0 === this.#numEvents) { return; @@ -300,7 +299,7 @@ class LogFileManager { "i"; const searchRegex = new RegExp(regexPattern, regexFlags); - this.#searchChunkAndScheduleNext(this.#queryId, 0, searchRegex); + this.#searchChunkAndScheduleNext(this.#queryId++, 0, searchRegex); } /** @@ -343,13 +342,13 @@ class LogFileManager { } }); + this.#onQueryResults(results); + if (endSearchIdx < this.#numEvents) { defer(() => { this.#searchChunkAndScheduleNext(queryId, endSearchIdx, searchRegex); }); } - - this.#onQueryResults(results); } /** diff --git a/new-log-viewer/src/utils/config.ts b/new-log-viewer/src/utils/config.ts index 3dd16001..9234333c 100644 --- a/new-log-viewer/src/utils/config.ts +++ b/new-log-viewer/src/utils/config.ts @@ -9,8 +9,9 @@ import { import {DecoderOptionsType} from "../typings/decoders"; -const MAX_PAGE_SIZE = 1_000_000; const EXPORT_LOGS_CHUNK_SIZE = 10_000; +const MAX_PAGE_SIZE = 1_000_000; +const SEARCH_CHUNK_SIZE = 10000; /** * The default configuration values. @@ -154,6 +155,7 @@ export { CONFIG_DEFAULT, EXPORT_LOGS_CHUNK_SIZE, getConfig, + SEARCH_CHUNK_SIZE, setConfig, testConfig, }; From e3913d5df47fb132d39aed5df2f40f1f699525d1 Mon Sep 17 00:00:00 2001 From: Henry <50559854+Henry8192@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:10:53 -0400 Subject: [PATCH 23/27] fix lint comment warning --- new-log-viewer/src/services/LogFileManager/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index f41cb578..66152076 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -315,7 +315,7 @@ class LogFileManager { searchRegex: RegExp ): void { if (queryId !== this.#queryId) { - // Return directly if this search task no longer corresponds to the latest query in the LogFileManager. + // Current task no longer corresponds to the latest query in the LogFileManager. return; } const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); From b7326070847abe32855dd1212e369dbaacf4f479 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:22:41 -0400 Subject: [PATCH 24/27] Update new-log-viewer/src/utils/config.ts Co-authored-by: Junhao Liao --- new-log-viewer/src/utils/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-log-viewer/src/utils/config.ts b/new-log-viewer/src/utils/config.ts index 9234333c..cbf20fd3 100644 --- a/new-log-viewer/src/utils/config.ts +++ b/new-log-viewer/src/utils/config.ts @@ -11,7 +11,7 @@ import {DecoderOptionsType} from "../typings/decoders"; const EXPORT_LOGS_CHUNK_SIZE = 10_000; const MAX_PAGE_SIZE = 1_000_000; -const SEARCH_CHUNK_SIZE = 10000; +const SEARCH_CHUNK_SIZE = 10_000; /** * The default configuration values. From 45e5e614d63a2a011fc16046fe2bcdc12583dda9 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Sat, 19 Oct 2024 00:50:30 -0400 Subject: [PATCH 25/27] Apply suggestions from code review Co-authored-by: Junhao Liao --- new-log-viewer/src/services/LogFileManager/index.ts | 13 ++++++++----- new-log-viewer/src/services/MainWorker.ts | 2 +- new-log-viewer/src/utils/time.ts | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index 66152076..ee568910 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -60,7 +60,6 @@ class LogFileManager { * @param params.fileName * @param params.onDiskFileSizeInBytes * @param params.pageSize Page size for setting up pagination. - * @param params.onQueryResults The callback function to handle query results. */ constructor ({decoder, fileName, onDiskFileSizeInBytes, pageSize, onQueryResults}: { decoder: Decoder, @@ -278,13 +277,16 @@ class LogFileManager { } /** - * Searches for log events based on the given search string. + * Creates a RegExp object based on the given search string and options, + * and starts querying the first log chunk. * * @param searchString * @param isRegex * @param isCaseSensitive */ startQuery (searchString: string, isRegex: boolean, isCaseSensitive: boolean): void { + this.#queryId++; + // If the search string is empty, or there are no logs, return if ("" === searchString || 0 === this.#numEvents) { return; @@ -299,15 +301,16 @@ class LogFileManager { "i"; const searchRegex = new RegExp(regexPattern, regexFlags); - this.#searchChunkAndScheduleNext(this.#queryId++, 0, searchRegex); + this.#searchChunkAndScheduleNext(this.#queryId, 0, searchRegex); } /** - * Searches for log events in the given range, then schedules itself to search the next chunk. + * Queries a chunk of log events, sends the results, + * and schedules the next chunk query if more log events remain. * * @param queryId * @param beginSearchIdx The beginning index of the search range. - * @param searchRegex The regular expression to search. + * @param searchRegex */ #searchChunkAndScheduleNext ( queryId: number, diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index 2c209853..dfcdd68b 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -39,7 +39,7 @@ const postResp = ( /** - * Post a response of a query chunk. + * Post a response for a chunk of query results. * * @param queryResults */ diff --git a/new-log-viewer/src/utils/time.ts b/new-log-viewer/src/utils/time.ts index 27312a29..471a0020 100644 --- a/new-log-viewer/src/utils/time.ts +++ b/new-log-viewer/src/utils/time.ts @@ -1,7 +1,7 @@ /** * Defers the execution of a callback function until the call stack is clear. * - * @param callbackFn The callback function to be deferred. + * @param callbackFn The callback function to be executed. */ const defer = (callbackFn: () => void) => { setTimeout(callbackFn, 0); From 142275e39ae677c9463f7ea2486ef86ffc5537d1 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Sat, 19 Oct 2024 01:05:39 -0400 Subject: [PATCH 26/27] apply suggestions --- .../src/components/MenuBar/index.tsx | 13 +---- .../src/contexts/StateContextProvider.tsx | 6 +-- new-log-viewer/src/index.tsx | 2 +- .../src/services/LogFileManager/index.ts | 51 ++++++++++--------- new-log-viewer/src/services/MainWorker.ts | 4 +- new-log-viewer/src/typings/worker.ts | 2 +- new-log-viewer/src/utils/config.ts | 4 +- 7 files changed, 36 insertions(+), 46 deletions(-) diff --git a/new-log-viewer/src/components/MenuBar/index.tsx b/new-log-viewer/src/components/MenuBar/index.tsx index 46654183..aac5c979 100644 --- a/new-log-viewer/src/components/MenuBar/index.tsx +++ b/new-log-viewer/src/components/MenuBar/index.tsx @@ -9,7 +9,6 @@ import { } from "@mui/joy"; import FolderOpenIcon from "@mui/icons-material/FolderOpen"; -import SearchIcon from "@mui/icons-material/Search"; import {StateContext} from "../../contexts/StateContextProvider"; import {CURSOR_CODE} from "../../typings/worker"; @@ -26,7 +25,7 @@ import "./index.css"; * @return */ const MenuBar = () => { - const {fileName, loadFile, startQuery} = useContext(StateContext); + const {fileName, loadFile} = useContext(StateContext); const handleOpenFile = () => { openFile((file) => { @@ -34,10 +33,6 @@ const MenuBar = () => { }); }; - const handleQueryClick = () => { - startQuery("ERROR", false, false); - }; - return ( <> @@ -76,12 +71,6 @@ const MenuBar = () => { - - - ); diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index b6306b0c..6304be12 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -62,7 +62,7 @@ interface StateContextType { loadFile: (fileSrc: FileSrcType, cursor: CursorType) => void, loadPageByAction: (navAction: NavigationAction) => void, setLogLevelFilter: (newLogLevelFilter: LogLevelFilter) => void, - startQuery: (searchString: string, isRegex: boolean, isCaseSensitive: boolean) => void, + startQuery: (queryString: string, isRegex: boolean, isCaseSensitive: boolean) => void, } const StateContext = createContext({} as StateContextType); @@ -301,7 +301,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { }, []); const startQuery = useCallback(( - searchString: string, + queryString: string, isRegex: boolean, isCaseSensitive: boolean ) => { @@ -311,7 +311,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { return; } workerPostReq(mainWorkerRef.current, WORKER_REQ_CODE.START_QUERY, { - searchString: searchString, + queryString: queryString, isRegex: isRegex, isCaseSensitive: isCaseSensitive, }); diff --git a/new-log-viewer/src/index.tsx b/new-log-viewer/src/index.tsx index 04bcd05a..4883d41c 100644 --- a/new-log-viewer/src/index.tsx +++ b/new-log-viewer/src/index.tsx @@ -13,4 +13,4 @@ root.render( ); -export {SEARCH_CHUNK_SIZE} from "./utils/config"; +export {QUERY_CHUNK_SIZE} from "./utils/config"; diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index ee568910..6a0120e5 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -18,7 +18,7 @@ import { } from "../../typings/worker"; import { EXPORT_LOGS_CHUNK_SIZE, - SEARCH_CHUNK_SIZE, + QUERY_CHUNK_SIZE, } from "../../utils/config"; import {getChunkNum} from "../../utils/math"; import {defer} from "../../utils/time"; @@ -60,6 +60,7 @@ class LogFileManager { * @param params.fileName * @param params.onDiskFileSizeInBytes * @param params.pageSize Page size for setting up pagination. + * @param params.onQueryResults */ constructor ({decoder, fileName, onDiskFileSizeInBytes, pageSize, onQueryResults}: { decoder: Decoder, @@ -277,31 +278,31 @@ class LogFileManager { } /** - * Creates a RegExp object based on the given search string and options, + * Creates a RegExp object based on the given query string and options, * and starts querying the first log chunk. * - * @param searchString + * @param queryString * @param isRegex * @param isCaseSensitive */ - startQuery (searchString: string, isRegex: boolean, isCaseSensitive: boolean): void { + startQuery (queryString: string, isRegex: boolean, isCaseSensitive: boolean): void { this.#queryId++; - // If the search string is empty, or there are no logs, return - if ("" === searchString || 0 === this.#numEvents) { + // If the query string is empty, or there are no logs, return + if ("" === queryString || 0 === this.#numEvents) { return; } - // Construct search RegExp + // Construct query RegExp const regexPattern = isRegex ? - searchString : - searchString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + queryString : + queryString.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const regexFlags = isCaseSensitive ? "" : "i"; - const searchRegex = new RegExp(regexPattern, regexFlags); + const queryRegex = new RegExp(regexPattern, regexFlags); - this.#searchChunkAndScheduleNext(this.#queryId, 0, searchRegex); + this.#queryChunkAndScheduleNext(this.#queryId, 0, queryRegex); } /** @@ -309,29 +310,29 @@ class LogFileManager { * and schedules the next chunk query if more log events remain. * * @param queryId - * @param beginSearchIdx The beginning index of the search range. - * @param searchRegex + * @param chunkBeginIdx + * @param queryRegex */ - #searchChunkAndScheduleNext ( + #queryChunkAndScheduleNext ( queryId: number, - beginSearchIdx: number, - searchRegex: RegExp + chunkBeginIdx: number, + queryRegex: RegExp ): void { if (queryId !== this.#queryId) { // Current task no longer corresponds to the latest query in the LogFileManager. return; } - const endSearchIdx = Math.min(beginSearchIdx + SEARCH_CHUNK_SIZE, this.#numEvents); + const chunkEndIdx = Math.min(chunkBeginIdx + QUERY_CHUNK_SIZE, this.#numEvents); const results: QueryResults = new Map(); const decodedEvents = this.#decoder.decodeRange( - beginSearchIdx, - endSearchIdx, + chunkBeginIdx, + chunkEndIdx, null !== this.#decoder.getFilteredLogEventMap() ); decodedEvents?.forEach(([message, , , logEventNum]) => { - const match = message.match(searchRegex); - if (match && "number" === typeof match.index) { + const matchResult = message.match(queryRegex); + if (null !== matchResult && "number" === typeof matchResult.index) { const pageNum = Math.ceil(logEventNum / this.#pageSize); if (false === results.has(pageNum)) { results.set(pageNum, []); @@ -339,17 +340,17 @@ class LogFileManager { results.get(pageNum)?.push({ logEventNum: logEventNum, message: message, - matchRange: [match.index, - (match.index + match[0].length)], + matchRange: [matchResult.index, + (matchResult.index + matchResult[0].length)], }); } }); this.#onQueryResults(results); - if (endSearchIdx < this.#numEvents) { + if (chunkEndIdx < this.#numEvents) { defer(() => { - this.#searchChunkAndScheduleNext(queryId, endSearchIdx, searchRegex); + this.#queryChunkAndScheduleNext(queryId, chunkEndIdx, queryRegex); }); } } diff --git a/new-log-viewer/src/services/MainWorker.ts b/new-log-viewer/src/services/MainWorker.ts index dfcdd68b..73b2f5da 100644 --- a/new-log-viewer/src/services/MainWorker.ts +++ b/new-log-viewer/src/services/MainWorker.ts @@ -114,14 +114,14 @@ onmessage = async (ev: MessageEvent) => { throw new Error("Log file manager hasn't been initialized"); } if ( - "string" !== typeof args.searchString || + "string" !== typeof args.queryString || "boolean" !== typeof args.isRegex || "boolean" !== typeof args.isCaseSensitive ) { throw new Error("Invalid arguments for QUERY_LOG"); } LOG_FILE_MANAGER.startQuery( - args.searchString, + args.queryString, args.isRegex, args.isCaseSensitive ); diff --git a/new-log-viewer/src/typings/worker.ts b/new-log-viewer/src/typings/worker.ts index 487965f4..8e64e283 100644 --- a/new-log-viewer/src/typings/worker.ts +++ b/new-log-viewer/src/typings/worker.ts @@ -99,7 +99,7 @@ type WorkerReqMap = { logLevelFilter: LogLevelFilter, }, [WORKER_REQ_CODE.START_QUERY]: { - searchString: string, + queryString: string, isRegex: boolean, isCaseSensitive: boolean, }, diff --git a/new-log-viewer/src/utils/config.ts b/new-log-viewer/src/utils/config.ts index cbf20fd3..f46167fe 100644 --- a/new-log-viewer/src/utils/config.ts +++ b/new-log-viewer/src/utils/config.ts @@ -11,7 +11,7 @@ import {DecoderOptionsType} from "../typings/decoders"; const EXPORT_LOGS_CHUNK_SIZE = 10_000; const MAX_PAGE_SIZE = 1_000_000; -const SEARCH_CHUNK_SIZE = 10_000; +const QUERY_CHUNK_SIZE = 10_000; /** * The default configuration values. @@ -155,7 +155,7 @@ export { CONFIG_DEFAULT, EXPORT_LOGS_CHUNK_SIZE, getConfig, - SEARCH_CHUNK_SIZE, + QUERY_CHUNK_SIZE, setConfig, testConfig, }; From 24e86c84acc0f833fbbcfd78f45af6ce4f5de6eb Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Sat, 19 Oct 2024 01:16:38 -0400 Subject: [PATCH 27/27] Apply suggestions from code review Co-authored-by: Junhao Liao --- .../src/contexts/StateContextProvider.tsx | 1 + new-log-viewer/src/index.tsx | 1 - .../src/services/LogFileManager/index.ts | 14 ++++++++------ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/new-log-viewer/src/contexts/StateContextProvider.tsx b/new-log-viewer/src/contexts/StateContextProvider.tsx index 6304be12..b8c7f981 100644 --- a/new-log-viewer/src/contexts/StateContextProvider.tsx +++ b/new-log-viewer/src/contexts/StateContextProvider.tsx @@ -305,6 +305,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => { isRegex: boolean, isCaseSensitive: boolean ) => { + setQueryResults(STATE_DEFAULT.queryResults); if (null === mainWorkerRef.current) { console.error("Unexpected null mainWorkerRef.current"); diff --git a/new-log-viewer/src/index.tsx b/new-log-viewer/src/index.tsx index 4883d41c..4409e0de 100644 --- a/new-log-viewer/src/index.tsx +++ b/new-log-viewer/src/index.tsx @@ -13,4 +13,3 @@ root.render( ); -export {QUERY_CHUNK_SIZE} from "./utils/config"; diff --git a/new-log-viewer/src/services/LogFileManager/index.ts b/new-log-viewer/src/services/LogFileManager/index.ts index 6a0120e5..67b1c0e4 100644 --- a/new-log-viewer/src/services/LogFileManager/index.ts +++ b/new-log-viewer/src/services/LogFileManager/index.ts @@ -278,8 +278,8 @@ class LogFileManager { } /** - * Creates a RegExp object based on the given query string and options, - * and starts querying the first log chunk. + * Creates a RegExp object based on the given query string and options, and starts querying the + * first log chunk. * * @param queryString * @param isRegex @@ -306,8 +306,8 @@ class LogFileManager { } /** - * Queries a chunk of log events, sends the results, - * and schedules the next chunk query if more log events remain. + * Queries a chunk of log events, sends the results, and schedules the next chunk query if more + * log events remain. * * @param queryId * @param chunkBeginIdx @@ -340,8 +340,10 @@ class LogFileManager { results.get(pageNum)?.push({ logEventNum: logEventNum, message: message, - matchRange: [matchResult.index, - (matchResult.index + matchResult[0].length)], + matchRange: [ + matchResult.index, + (matchResult.index + matchResult[0].length), + ], }); } });