Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import {
} from "@common/index.js";
import {Socket} from "socket.io-client";

import {MongoCursorSocket} from "./MongoCursorSocket.js";
import {MongoSocketCursor} from "./MongoSocketCursor.js";
import {getSharedSocket} from "./SocketSingleton.js";


/**
* Socket connection to a MongoDB collection residing on a server. Class provides methods to
* query the collection.
*/
class MongoCollectionSocket {
class MongoSocketCollection {
#collectionName: string;

#socket: Socket<ServerToClientEvents, ClientToServerEvents>;
Expand All @@ -25,19 +25,18 @@ class MongoCollectionSocket {
constructor (collectionName: string) {
this.#socket = getSharedSocket();
this.#collectionName = collectionName;
console.log(`MongoDB collection:${collectionName} initialized.`);
}

/**
* Selects documents in collection and returns a cursor-like object.
*
* @param query
* @param options
* @return a `MongoCursorSocket`.
* @return a `MongoSocketCursor`.
*/

find (query: object, options: object) {
return new MongoCursorSocket(
return new MongoSocketCursor(
this.#socket,
this.#collectionName,
query,
Expand All @@ -47,4 +46,4 @@ class MongoCollectionSocket {
}


export default MongoCollectionSocket;
export default MongoSocketCollection;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {Nullable} from "../../typings/common";
/**
* A cursor-like object receiving MongoDB documents over a socket connection.
*/
class MongoCursorSocket {
class MongoSocketCursor {
#socket: Socket<ServerToClientEvents, ClientToServerEvents>;

#collectionName: string;
Expand Down Expand Up @@ -52,7 +52,11 @@ class MongoCursorSocket {
* @throws {Error} if subscription fails.
*/
async subscribe (onDataUpdate: (data: object[]) => void): Promise<void> {
console.log("Attempting to subscribe to query:", JSON.stringify(this.#query));
console.debug(
`Subscribing to query: ${JSON.stringify(this.#query)} ` +
`with options:${JSON.stringify(this.#options)} ` +
`on collection:${this.#collectionName}`
);

this.#updateListener = (respArgs: {queryId: number; data: object[]}) => {
// Server sends updates for multiple queryIDs using the same event name.
Expand Down Expand Up @@ -82,7 +86,12 @@ class MongoCursorSocket {
onDataUpdate(response.data.initialDocuments);

this.#queryId = response.data.queryId;
console.log(`Subscribed to queryID:${this.#queryId}.`);
console.debug(
`Successfully subscribed to query: ${JSON.stringify(this.#query)} ` +
`with options:${JSON.stringify(this.#options)} ` +
`on collection:${this.#collectionName} ` +
`MongoSocketIoQueryID:${this.#queryId}`
);
}

/**
Expand All @@ -105,10 +114,10 @@ class MongoCursorSocket {
this.#updateListener = null;
}

console.log(`Unsubscribed to queryID:${this.#queryId}.`);
console.debug(`Unsubscribed from MongoSocketIoQueryID:${this.#queryId}.`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Minor readability tweak

Add a space after the colon to align with the other log messages.

-        console.debug(`Unsubscribed from MongoSocketIoQueryID:${this.#queryId}.`);
+        console.debug(`Unsubscribed from MongoSocketIoQueryID: ${this.#queryId}.`);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.debug(`Unsubscribed from MongoSocketIoQueryID:${this.#queryId}.`);
console.debug(`Unsubscribed from MongoSocketIoQueryID: ${this.#queryId}.`);
🤖 Prompt for AI Agents
In components/log-viewer-webui/client/src/api/socket/MongoSocketCursor.ts at
line 117, the debug log message lacks a space after the colon in
"MongoSocketIoQueryID:". Add a space after the colon so the message reads
"MongoSocketIoQueryID: " to improve readability and maintain consistency with
other log messages.


this.#queryId = null;
}
}

export {MongoCursorSocket};
export {MongoSocketCursor};
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ import {
} from "react";

import {Nullable} from "../../typings/common";
import {MongoCursorSocket} from "./MongoCursorSocket.js";
import {MongoSocketCursor} from "./MongoSocketCursor.js";


/**
* Custom hook which returns a real-time reactive array of documents from a `MongoCursorSocket`.
* Custom hook which returns a real-time reactive array of documents from a `MongoSocketCursor`.
*
* @template T The document type returned by the cursor.
* @param query Function which returns a `MongoCursorSocket` instance or null.
* @param query Function which returns a `MongoSocketCursor` instance or null.
* @param dependencies Array of dependencies for the query.
* @return
* - If `query` returns a `MongoCursorSocket` instance, then hook returns null while
* - If `query` returns a `MongoSocketCursor` instance, then hook returns null while
Comment on lines +12 to +18

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Updated JSDoc – spellcheck minor typo

The word “recieved” in the comment below is still misspelled.

-            // recieved the queryID from the server, making it impossible to unsubscribe
+            // received the queryID from the server, making it impossible to unsubscribe

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In components/log-viewer-webui/client/src/api/socket/useCursor.tsx around lines
12 to 18, correct the spelling of the word "recieved" to "received" in the JSDoc
comment to fix the minor typo.

* the subscription is pending, and a reactive array of documents when the subscription is ready.
* - If `query` returns null, then the hook also returns null.
*/
const useCursor = <T = object>(
query: () => Nullable<MongoCursorSocket>,
query: () => Nullable<MongoSocketCursor>,
dependencies: DependencyList = []
): Nullable<T[]> => {
const [data, setData] = useState<Nullable<T[]>>(null);
Expand All @@ -37,7 +37,6 @@ const useCursor = <T = object>(

// Flag to ignore updates after unmounting.
let ignore = false;
console.log("Subscribing to cursor");

// Handler to set data updates from the server.
const onDataUpdate = (dataUpdate: object[]) => {
Expand All @@ -63,7 +62,6 @@ const useCursor = <T = object>(
.then(() => {
// Unsubscribe will not run if the subscription failed since the promise was
// rejected.
console.log("Unsubscribing from cursor");
cursor.unsubscribe();
})
.catch((error: unknown) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,17 @@ const handleQuerySubmit = (payload: QueryJobCreationSchema) => {

submitQuery(payload)
.then((result) => {
store.updateSearchJobId(result.data.searchJobId);
store.updateAggregationJobId(result.data.aggregationJobId);
const {searchJobId, aggregationJobId} = result.data;
store.updateSearchJobId(searchJobId);
store.updateAggregationJobId(aggregationJobId);
store.updateSearchUiState(SEARCH_UI_STATE.QUERYING);
console.log("Query ID Returned", result);
console.debug(
"Search job created - ",
"Search job ID:",
searchJobId,
"Aggregation job ID:",
aggregationJobId
);
})
.catch((err: unknown) => {
console.error("Failed to submit query:", err);
Expand All @@ -117,7 +124,7 @@ const handleQueryCancel = (payload: QueryJobSchema) => {
cancelQuery(
payload
).then(() => {
console.log("Query cancelled successfully");
console.debug("Query cancelled successfully");
})
Comment on lines +127 to 128

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Nit: add context to cancellation log

Including IDs helps when multiple tabs/users are active.

-        console.debug("Query cancelled successfully");
+        console.debug(`Query ${payload.searchJobId} cancelled successfully`);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.debug("Query cancelled successfully");
})
console.debug(`Query ${payload.searchJobId} cancelled successfully`);
})
🤖 Prompt for AI Agents
In
components/log-viewer-webui/client/src/pages/SearchPage/SearchControls/search-requests.ts
at lines 123-124, the console.debug log for query cancellation lacks context.
Modify the log message to include relevant identifiers such as query IDs or
user/session IDs to help distinguish cancellations when multiple tabs or users
are active.

.catch((err: unknown) => {
console.error("Failed to cancel query:", err);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import MongoCollectionSocket from "../../../../api/socket/MongoCollectionSocket";
import MongoSocketCollection from "../../../../api/socket/MongoSocketCollection";
import {useCursor} from "../../../../api/socket/useCursor";
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../SearchState/index";
import {
Expand All @@ -23,6 +23,10 @@ const useSearchResults = () => {
return null;
}

console.log(
`Subscribing to updates to search results with job ID: ${searchJobId}`
);

// Retrieve 1k most recent results.
const options = {
sort: [
Expand All @@ -38,7 +42,7 @@ const useSearchResults = () => {
limit: SEARCH_MAX_NUM_RESULTS,
};

const collection = new MongoCollectionSocket(searchJobId.toString());
const collection = new MongoSocketCollection(searchJobId.toString());
return collection.find({}, options);
},
[searchJobId]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import MongoCollectionSocket from "../../../../api/socket/MongoCollectionSocket";
import MongoSocketCollection from "../../../../api/socket/MongoSocketCollection";
import {useCursor} from "../../../../api/socket/useCursor";
import {TimelineBucket} from "../../../../components/ResultsTimeline/typings";
import useSearchStore, {SEARCH_STATE_DEFAULT} from "../../SearchState/index";
Expand All @@ -20,7 +20,11 @@ const useAggregationResults = () => {
return null;
}

const collection = new MongoCollectionSocket(aggregationJobId.toString());
console.log(
`Subscribing to updates to aggregation results with job ID: ${aggregationJobId}`
);

const collection = new MongoSocketCollection(aggregationJobId.toString());
Comment on lines +23 to +27

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Use console.debug for consistency with new logging policy.

All other updated modules migrated from console.log/console.info to console.debug to reduce noise in production builds. These two lines revert to console.log, breaking that consistency.

-            console.log(
+            console.debug(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log(
`Subscribing to updates to aggregation results with job ID: ${aggregationJobId}`
);
const collection = new MongoSocketCollection(aggregationJobId.toString());
console.debug(
`Subscribing to updates to aggregation results with job ID: ${aggregationJobId}`
);
const collection = new MongoSocketCollection(aggregationJobId.toString());
🤖 Prompt for AI Agents
In
components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTimeline/useAggregationResults.ts
between lines 23 and 27, replace the console.log statement with console.debug to
maintain consistency with the new logging policy and reduce noise in production
builds.

return collection.find({}, {});
},
[aggregationJobId]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {SearchResultsMetadataDocument} from "@common/index.js";

import MongoCollectionSocket from "../../../api/socket/MongoCollectionSocket";
import MongoSocketCollection from "../../../api/socket/MongoSocketCollection";
import {useCursor} from "../../../api/socket/useCursor";
import {settings} from "../../../settings";
import useSearchStore, {SEARCH_STATE_DEFAULT} from "./index";
Expand All @@ -22,10 +22,14 @@ const useResultsMetadata = () => {
return null;
}

const collection = new MongoCollectionSocket(
const collection = new MongoSocketCollection(
settings.MongoDbSearchResultsMetadataCollectionName
);

console.log(
`Subscribing to updates for results metadata for search job ID: ${searchJobId}`
);

return collection.find({_id: searchJobId.toString()}, {limit: 1});
Comment on lines +25 to 33

@coderabbitai coderabbitai Bot Jun 10, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Switch to console.debug for uniform log level

Same rationale as in useSearchResults.ts.

-            console.log(
+            console.debug(
                 `Subscribing to updates for results metadata for search job ID: ${searchJobId}`
             );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const collection = new MongoSocketCollection(
settings.MongoDbSearchResultsMetadataCollectionName
);
console.log(
`Subscribing to updates for results metadata for search job ID: ${searchJobId}`
);
return collection.find({_id: searchJobId.toString()}, {limit: 1});
const collection = new MongoSocketCollection(
settings.MongoDbSearchResultsMetadataCollectionName
);
console.debug(
`Subscribing to updates for results metadata for search job ID: ${searchJobId}`
);
return collection.find({_id: searchJobId.toString()}, {limit: 1});
🤖 Prompt for AI Agents
In
components/log-viewer-webui/client/src/pages/SearchPage/SearchState/useResultsMetadata.ts
between lines 25 and 33, replace the console.log statement with console.debug to
maintain consistent log levels across the codebase, matching the approach used
in useSearchResults.ts. This change ensures debug-level messages are uniformly
handled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davemarco Understood—keeping the console.log as-is.

},
[searchJobId]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ class MongoSocketIoServer {
let watcherCollection = this.#collections.get(collectionName);
if ("undefined" === typeof watcherCollection) {
watcherCollection = new MongoWatcherCollection(collectionName, this.#mongoDb);
this.#fastify.log.info(`Initialize Mongo watcher collection:${collectionName}.`);
this.#fastify.log.debug(`Initialize Mongo watcher collection:${collectionName}.`);
this.#collections.set(collectionName, watcherCollection);
}

Expand All @@ -226,7 +226,7 @@ class MongoSocketIoServer {
): Promise<void> {
const {collectionName, query, options} = requestArgs;

this.#fastify.log.info(
this.#fastify.log.debug(
`Socket:${socket.id} requested query:${JSON.stringify(query)} ` +
`with options:${JSON.stringify(options)} to collection:${collectionName}`
);
Expand All @@ -252,7 +252,11 @@ class MongoSocketIoServer {
callback({data: {queryId, initialDocuments}});

this.#addQueryIdToSubscribedList(queryId, socket.id);
this.#fastify.log.info(`Socket:${socket.id} subscribed to queryID:${queryId}.`);
this.#fastify.log.info(
`Socket:${socket.id} subscribed to query:${JSON.stringify(query)} ` +
`with options:${JSON.stringify(options)} ` +
`on collection:${collectionName} with ID:${queryId}`
);
Comment on lines +255 to +259

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Consider downgrading this final “subscribed” message to debug
Earlier discussion left it at info, but now both the request (229-233) and most watcher lifecycle logs are debug. Re-evaluating could further tame noise.

🤖 Prompt for AI Agents
In components/log-viewer-webui/server/src/plugins/MongoSocketIoServer/index.ts
around lines 255 to 259, the log message indicating a socket subscription is
currently at info level, which is inconsistent with earlier request and watcher
lifecycle logs set at debug level. Change the log level from info to debug for
this message to reduce log noise and maintain consistency.

}

/**
Expand Down Expand Up @@ -288,7 +292,7 @@ class MongoSocketIoServer {
#unsubscribe (socket: MongoCustomSocket, queryId: number) {
const queryHash: string | undefined = this.#queryIdToQueryHashMap.get(queryId);
if ("undefined" === typeof queryHash) {
this.#fastify.log.error(`QueryId ${queryId} not found in query map`);
this.#fastify.log.error(`Query:${queryId} not found in query map`);

return;
}
Expand All @@ -303,10 +307,10 @@ class MongoSocketIoServer {
}

const isLastSubscriber = collection.unsubscribe(queryId, socket.id);
this.#fastify.log.info(`Socket ${socket.id} unsubscribed from query ${queryId}`);
this.#fastify.log.info(`Socket:${socket.id} unsubscribed from query:${queryId}`);

if (isLastSubscriber) {
this.#fastify.log.info(`QueryID:${queryId} deleted from query map.`);
this.#fastify.log.debug(`Query:${queryId} deleted from query map.`);
this.#queryIdToQueryHashMap.delete(queryId);
}

Expand All @@ -316,7 +320,7 @@ class MongoSocketIoServer {
);

if (false === collection.isReferenced()) {
this.#fastify.log.info(`Collection:${queryParams.collectionName}` +
this.#fastify.log.debug(`Collection:${queryParams.collectionName}` +
" deallocated from server.");
Comment on lines +323 to 324

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Swap string concatenation for template literal

-            this.#fastify.log.debug(`Collection:${queryParams.collectionName}` +
-            " deallocated from server.");
+            this.#fastify.log.debug(
+                `Collection:${queryParams.collectionName} deallocated from server.`
+            );

This removes the lint error (useTemplate) and is easier to read.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
this.#fastify.log.debug(`Collection:${queryParams.collectionName}` +
" deallocated from server.");
this.#fastify.log.debug(
`Collection:${queryParams.collectionName} deallocated from server.`
);
🧰 Tools
🪛 Biome (1.9.4)

[error] 323-324: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

🤖 Prompt for AI Agents
In components/log-viewer-webui/server/src/plugins/MongoSocketIoServer/index.ts
at lines 323-324, replace the string concatenation used in the debug log
statement with a single template literal. This means combining the entire
message inside backticks and embedding the variable directly using ${}, which
will remove the lint error and improve readability.

this.#collections.delete(queryParams.collectionName);
}
Expand All @@ -334,8 +338,8 @@ class MongoSocketIoServer {
requestArgs: {queryId: number}
): Promise<void> {
const {queryId} = requestArgs;
this.#fastify.log.info(
`Socket:${socket.id} requested unsubscription to QueryId:${queryId}`
this.#fastify.log.debug(
`Socket:${socket.id} requested unsubscription to query:${queryId}`
);

const subscribedQueryIds = this.#subscribedQueryIdsMap.get(socket.id);
Expand Down