Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new-log-viewer: Define interface for filtering by log level and add support (internally) to JsonlDecoder; Move timestamp field extraction from LogbackFormatter to JsonlDecoder. #79

Merged
merged 25 commits into from
Oct 2, 2024

Conversation

davemarco
Copy link
Contributor

@davemarco davemarco commented Sep 27, 2024

References

new-log-viewer series: #45 #46 #48 #51 #52 #53 #54 #55 #56 #59 #60 #61 #62 #63 #66 #67 #68 #69 #70 #71 #72 #73 #74 #76

Description

Restructures jsonl decoder which will eventually enable log level filtering. Most of the code from this PR is inspired by #63, however, I did a proper review and made many improvements. PR is effectively a heavy refactor of a portion of #63. PR does not add any new functionality to log viewer, it just sets up future PRs. Note the PR is not as big as it looks, I moved some files and github thinks they are completely new.

Specifically made the following changes:

Parsing timestamp and log level moved from decode to build.

jsonl decoder now parses the log level and timestamp during building rather than decoding, this allows us to filter logs without decoding all the events. This also affected the formatter as now it has less work to do since the timestamp is already converted to a dayjs object during build. Effectively it moves more work to the build stage to simplify filtering algorithms.

Add new filtering methods

Added a few new methods that will be required when filtering is enabled. See decoders.ts for a breakdown of interface changes / new methods. Most importantly, added a method to actually filter the jsonl logs. Note none of the new methods are actually being called in this PR, it just sets up future filtering PRs.

Validation performed

I did tests on jsonl and ir files, and everything seemed okay. I did notice the page skipping was a little buggy, but i tested main branch and it had the same bugs. Hopefully #76 unintentionally fixes these bugs.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new JsonlDecoder class for processing JSONL formatted log files.
    • Added methods for log level filtering and retrieving filtered log events.
  • Improvements

    • Streamlined the log decoding process with updated methods and clearer naming conventions.
    • Enhanced log formatting capabilities with a focus on specific log event types.
  • Bug Fixes

    • Improved error handling during log event decoding.
  • Documentation

    • Updated type definitions and method signatures for clarity and consistency.

Copy link

coderabbitai bot commented Sep 27, 2024

Walkthrough

The changes involve significant modifications to the log processing system, including the introduction of new methods for log level filtering, renaming of existing methods to clarify their purpose, and the addition of a new JsonlDecoder class for processing JSONL formatted log files. The LogFileManager and various decoder classes have been updated to streamline their functionality, focusing on formatting options rather than decoding options. Additionally, utility functions for processing JSON log events have been added, and the overall structure of the log formatting process has been simplified.

Changes

Files Change Summary
new-log-viewer/src/services/LogFileManager.ts Removed LOG_EVENT_FILE_END_IDX, replaced decoder.buildIdx() with decoder.build(), renamed setDecoderOptions() to setFormatterOptions(), and updated decoding methods to include a new boolean parameter.
new-log-viewer/src/services/decoders/ClpIrDecoder.ts Introduced getFilteredLogEventMap and setLogLevelFilter methods, removed buildIdx, modified build, renamed setDecoderOptions to setFormatterOptions, and updated decode to decodeRange with an additional parameter.
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts Added a new JsonlDecoder class implementing the Decoder interface for JSONL log files, with methods for estimating log events, filtering, and decoding.
new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts Introduced utility functions: isJsonObject, convertToLogLevelValue, and convertToDayjsTimestamp for processing JSON log events.
new-log-viewer/src/services/formatters/LogbackFormatter.ts Updated formatLogEvent method signature to accept LogEvent and return a string, removed TimestampAndMessageType interface.
new-log-viewer/src/typings/decoders.ts Added getFilteredLogEventMap and setLogLevelFilter methods to the Decoder interface, renamed setDecoderOptions to setFormatterOptions, and updated decode to decodeRange.
new-log-viewer/src/typings/logs.ts Added LogLevelFilter type alias as Nullable<LOG_LEVEL[]>, and introduced LogEvent interface, both exported for use in other parts of the application.

Possibly related PRs

Suggested reviewers

  • kirkrodrigues

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 16

🧹 Outside diff range and nitpick comments (14)
new-log-viewer/src/typings/logs.ts (1)

14-14: LGTM: New LogLevelFilter type alias

The LogLevelFilter type alias is well-defined and aligns with the PR objective of supporting future log filtering. It allows for a nullable array of log levels, which is suitable for optional filtering scenarios.

Consider adding a brief JSDoc comment to explain the purpose of this type alias, for example:

/** Represents an optional filter for log levels. Null means no filtering. */
type LogLevelFilter = Nullable<LOG_LEVEL[]>;
new-log-viewer/src/typings/formatters.ts (1)

Line range hint 1-38: Summary: Changes align well with PR objectives and improve code structure.

The modifications in this file, including the import change, simplification of LogbackFormatterOptionsType, and updates to the Formatter interface, all contribute to the PR's goal of restructuring the jsonl decoder. These changes should facilitate future log level filtering and streamline the log processing workflow.

The removal of the TimestampAndMessageType interface and the shift towards using JsonLogEvent indicate a more structured approach to log event handling. This aligns with the PR's objective of relocating timestamp and log level parsing from the decoding phase to the building phase.

Overall, these changes appear to be well-thought-out and consistent with the PR's objectives. However, it's crucial to ensure that these modifications don't negatively impact existing functionality. Please run the suggested verification scripts and thoroughly test the updated log processing pipeline to confirm that all components work as expected with these new type definitions.

new-log-viewer/src/services/decoders/ClpIrDecoder.ts (4)

37-42: LGTM: Placeholder method for future filtering functionality.

The getFilteredLogEventMap method is correctly implemented as a placeholder for future log level filtering. The TODO comment provides clear guidance for future development.

Consider adding a JIRA ticket reference to the TODO comment for better traceability. For example:

// TODO: Update this after log level filtering is implemented in clp-ffi-js (JIRA-123)

44-49: LGTM: Placeholder method for setting log level filter.

The setLogLevelFilter method is correctly implemented as a placeholder for future log level filtering functionality. The TODO comment provides clear guidance for future development.

Consider adding a JIRA ticket reference to the TODO comment for better traceability. For example:

// TODO: Update this after log level filtering is implemented in clp-ffi-js (JIRA-123)

59-61: LGTM: Method renamed to reflect its purpose.

The renaming of setDecoderOptions to setFormatterOptions is consistent with the restructuring objectives. The implementation remains unchanged, which is appropriate for this PR.

Consider adding a TODO comment to indicate that this method might need further updates in the future. For example:

setFormatterOptions(): boolean {
    // TODO: Implement formatter options when they are defined (JIRA-XXX)
    return true;
}

64-71: LGTM: Method updated for future filtering support.

The renaming of decode to decodeRange and the addition of the useFilter parameter align well with the restructuring objectives. The implementation remains appropriate for this PR.

Consider adding a TODO comment to indicate that the useFilter parameter will be used in future implementations. For example:

decodeRange(
    beginIdx: number,
    endIdx: number,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    useFilter: boolean
): Nullable<DecodeResultType[]> {
    // TODO: Implement filtering logic when log level filtering is added (JIRA-XXX)
    return this.#streamReader.decodeRange(beginIdx, endIdx);
}
new-log-viewer/src/services/MainWorker.ts (2)

88-88: Approve the change and suggest a minor improvement

The modification from setDecoderOptions to setFormatterOptions is consistent with the earlier change and aligns with the PR objectives.

For improved code consistency, consider updating the variable name decoderOptions to formatterOptions throughout the file. This would make the code more self-explanatory and align with the new method name. Here's a suggested change:

-if ("undefined" !== typeof args.decoderOptions) {
-    LOG_FILE_MANAGER.setFormatterOptions(args.decoderOptions);
+if ("undefined" !== typeof args.formatterOptions) {
+    LOG_FILE_MANAGER.setFormatterOptions(args.formatterOptions);

This change should be applied consistently throughout the file, including in the WORKER_REQ_CODE.EXPORT_LOG case.


Line range hint 1-114: Overall assessment of changes in MainWorker.ts

The modifications in this file are consistent and well-aligned with the PR objectives. The changes from setDecoderOptions to setFormatterOptions reflect the restructuring of the jsonl decoder and the shift of parsing responsibilities. These focused updates maintain the existing functionality while preparing the groundwork for future enhancements in log filtering.

As you continue to develop this feature, consider the following architectural advice:

  1. Ensure that the LogFileManager class is updated to handle the new formatter options consistently across all its methods.
  2. If not already done, create unit tests for the new formatting logic to ensure its correctness and prevent regressions.
  3. Consider adding documentation or comments explaining the new formatting process, especially if it differs significantly from the previous decoding process.
  4. As you implement the future log filtering capabilities, ensure that the MainWorker.ts file remains focused on coordination and delegation, with the core filtering logic residing in appropriate service classes.
new-log-viewer/src/services/LogFileManager.ts (3)

76-79: Approved changes with a minor suggestion for error logging

The update from buildIdx() to build() aligns well with the PR objective of restructuring the jsonl decoder. The error handling has been appropriately updated to reflect this change.

Consider enhancing the error logging by including more context:

- console.error("Invalid events found in decoder.buildIdx():", buildResult);
+ console.error(`Invalid events found in decoder.build(): ${buildResult.numInvalidEvents} out of ${this.#numEvents} total events`, buildResult);

This change provides more immediate context about the scale of invalid events.


147-152: Approved changes with a suggestion for documentation

The renaming of setDecoderOptions to setFormatterOptions is consistent with the PR objectives and the overall restructuring of the log processing system. This change clarifies that the method is specifically for setting formatting options.

Consider updating the method documentation to reflect the focus on formatting:

 /**
- * Sets formatting options for the decoder.
+ * Sets options for formatting log events.
  *
- * @param options
+ * @param options Formatting options to be applied to log events
  */

This change provides more specific information about the purpose and impact of the method.


Line range hint 1-268: Overall changes align well with PR objectives

The modifications in this file successfully restructure the jsonl decoder interface, shifting focus towards formatting options and preparing for future log filtering capabilities. The changes are consistent throughout the class and align well with the stated PR objectives.

As the groundwork for future log filtering is now in place, consider the following next steps:

  1. Document the new decoder interface thoroughly, especially the purpose of the new boolean parameter in decodeRange.
  2. Update any relevant test cases to cover the new decoder behaviour.
  3. Plan for the implementation of the log filtering methods mentioned in the PR objectives, ensuring they integrate smoothly with this restructured decoder.

These steps will help maintain code clarity and facilitate the smooth introduction of filtering capabilities in future updates.

new-log-viewer/src/typings/decoders.ts (2)

36-41: Consider renaming FilteredLogEventMap for clarity.

The type FilteredLogEventMap is defined as Nullable<number[]>, which is an array mapping filtered indices to unfiltered indices. Since it's an array, naming it with Map might be misleading. Consider renaming it to FilteredLogEventIndices or similar for clarity.


52-54: Enhance the documentation for getFilteredLogEventMap().

The @return description is brief. Please provide more detail to clarify that the method returns a mapping from filtered log event indices to unfiltered log event indices.

Apply this diff to enhance the comment:

* @return Indices of the filtered events.
+* @return Mapping from filtered log event indices to unfiltered log event indices.
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1)

34-36: Consider default values for logLevelKey and timestampKey.

If these keys are standardised across most JSONL logs, providing default values can enhance usability by reducing the need for explicit specification each time.

Apply this diff to set default values:

#logLevelKey: string;
#timestampKey: string;

constructor (dataArray: Uint8Array, decoderOptions: JsonlDecoderOptionsType) {
+   const defaultLogLevelKey = "level";
+   const defaultTimestampKey = "timestamp";
    this.#dataArray = dataArray;
-   this.#logLevelKey = decoderOptions.logLevelKey;
-   this.#timestampKey = decoderOptions.timestampKey;
+   this.#logLevelKey = decoderOptions.logLevelKey || defaultLogLevelKey;
+   this.#timestampKey = decoderOptions.timestampKey || defaultTimestampKey;
    // Existing logic
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d185624 and f3cb5b4.

📒 Files selected for processing (10)
  • new-log-viewer/src/services/LogFileManager.ts (4 hunks)
  • new-log-viewer/src/services/MainWorker.ts (2 hunks)
  • new-log-viewer/src/services/decoders/ClpIrDecoder.ts (2 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder.ts (0 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts (1 hunks)
  • new-log-viewer/src/services/formatters/LogbackFormatter.ts (2 hunks)
  • new-log-viewer/src/typings/decoders.ts (3 hunks)
  • new-log-viewer/src/typings/formatters.ts (2 hunks)
  • new-log-viewer/src/typings/logs.ts (2 hunks)
💤 Files not reviewed due to no reviewable changes (1)
  • new-log-viewer/src/services/decoders/JsonlDecoder.ts
🔇 Additional comments (16)
new-log-viewer/src/typings/logs.ts (3)

1-1: LGTM: Import statement for Nullable type

The import statement for the Nullable type from the local common module is appropriate and necessary for the new LogLevelFilter type alias.


18-18: LGTM: Export of LogLevelFilter type

The export of the LogLevelFilter type is appropriate and necessary for making this type available to other modules that will implement log filtering functionality.


Line range hint 1-21: Summary: Good foundation for log level filtering

The changes to this file provide a solid foundation for implementing log level filtering functionality. The new LogLevelFilter type, along with its import dependencies and export, are well-structured and align with the PR objectives. These modifications will enable other parts of the application to implement more efficient log processing and filtering in the future.

new-log-viewer/src/typings/formatters.ts (2)

1-1: LGTM: Import change aligns with PR objectives.

The change from importing JsonObject to JsonLogEvent is consistent with the PR's goal of restructuring the jsonl decoder. This modification suggests a move towards a more specific log event structure, which should facilitate future log level filtering.


32-32: Approved: Formatter interface update streamlines log processing.

The changes to the formatLogEvent method signature in the Formatter interface align well with the PR's objectives. Using JsonLogEvent as input and returning a string simplifies the log formatting process and supports the restructuring of the jsonl decoder.

To ensure these changes don't negatively impact downstream code, please run the following verification:

#!/bin/bash
# Description: Check for uses of TimestampAndMessageType and formatLogEvent

# Test 1: Search for uses of TimestampAndMessageType. Expect: No results or only in test files.
echo "Checking for TimestampAndMessageType usage:"
rg --type typescript 'TimestampAndMessageType'

# Test 2: Search for uses of formatLogEvent. Expect: Updated method signatures.
echo "Checking for formatLogEvent usage:"
rg --type typescript 'formatLogEvent'
new-log-viewer/src/services/decoders/ClpIrDecoder.ts (2)

7-8: LGTM: Import statements are consistent with class changes.

The new imports for FilteredLogEventMap, LOG_EVENT_FILE_END_IDX, and LogLevelFilter align well with the modifications made to the ClpIrDecoder class. These additions support the restructuring for future log filtering capabilities.

Also applies to: 11-11


51-56: LGTM with a performance consideration.

The build method has been updated to process all events up to LOG_EVENT_FILE_END_IDX, which aligns with the restructuring objectives. However, this change may have performance implications for large log files.

Consider the performance impact of processing all events. You may want to add logging or metrics to monitor the execution time of this method. For example:

build(): LogEventCount {
    const startTime = performance.now();
    const result = {
        numInvalidEvents: 0,
        numValidEvents: this.#streamReader.deserializeRange(0, LOG_EVENT_FILE_END_IDX),
    };
    const endTime = performance.now();
    console.log(`Build method execution time: ${endTime - startTime} milliseconds`);
    return result;
}

This will help track the performance impact of processing all events.

new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts (3)

1-15: LGTM: Imports and dayjs extension are appropriate.

The imports are well-organized and include all necessary modules and types. Extending dayjs with the UTC plugin is a good practice for consistent timestamp handling across different timezones.


17-24: LGTM: JsonLogEvent interface is well-defined.

The JsonLogEvent interface provides a clear and type-safe structure for log events. Using Dayjs for the timestamp and LOG_LEVEL enum for the level ensures consistency and type safety throughout the application.


95-100: LGTM: Exports are appropriate and consistent.

The file correctly exports the three utility functions (convertToDayjsTimestamp, convertToLogLevelValue, isJsonObject) and the JsonLogEvent type. This aligns well with the file's purpose and content.

new-log-viewer/src/services/MainWorker.ts (1)

53-53: Approve the change from setDecoderOptions to setFormatterOptions

The modification aligns with the PR's objective of restructuring the jsonl decoder. This change reflects the shift from decoding to formatting, which is consistent with moving parsing to the building phase.

To ensure this change doesn't introduce unintended side effects, please run the following verification script:

✅ Verification successful

Change from setDecoderOptions to setFormatterOptions Verified

The setFormatterOptions method is consistently used across the codebase, and setDecoderOptions is no longer present. No issues were found related to this change.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the impact of changing setDecoderOptions to setFormatterOptions

# Test: Check if setFormatterOptions is consistently used across the codebase
rg --type typescript "setFormatterOptions" -C 3

# Test: Ensure setDecoderOptions is not used anymore
rg --type typescript "setDecoderOptions"

# Test: Look for any TODOs or FIXMEs related to this change
rg --type typescript -i "todo|fixme" -C 3 | rg -i "decoder|formatter"

Length of output: 265


Script:

#!/bin/bash
# Description: Verify the impact of changing setDecoderOptions to setFormatterOptions

# Test: Check if setFormatterOptions is consistently used across the codebase
rg "setFormatterOptions" --glob "*.ts" -C 3

# Test: Ensure setDecoderOptions is not used anymore
rg "setDecoderOptions" --glob "*.ts"

# Test: Look for any TODOs or FIXMEs related to this change
rg -i "todo|fixme" --glob "*.ts" -C 3 | rg -i "decoder|formatter"

Length of output: 6403

new-log-viewer/src/services/LogFileManager.ts (2)

168-171: Approved changes with a request for clarification

The update to the decodeRange method call, including the addition of a new boolean parameter, is consistent with the PR objectives of restructuring the jsonl decoder.

Could you please clarify the purpose of the new boolean parameter (set to false) in the decodeRange method? Adding a comment explaining its significance would improve code readability and maintainability.

For example:

 const results = this.#decoder.decodeRange(
     beginLogEventIdx,
     endLogEventIdx,
-    false,
+    false, // Set to false to [explain the purpose]
 );

203-203: Consistent change noted

The update to the decodeRange method call in loadPage is consistent with the change observed in the loadChunk method. This systematic change across methods reflects the restructuring of the decoder interface.

Please ensure that the clarification requested for the new boolean parameter in the loadChunk method (see previous comment) is also applicable here. Consider adding a similar explanatory comment in this method for consistency and clarity.

new-log-viewer/src/services/formatters/LogbackFormatter.ts (2)

9-9: Import statement is appropriate

The import of JsonLogEvent is necessary and correctly specified.


60-65: Ensure all usages of formatLogEvent are updated to the new signature

The formatLogEvent method signature has changed from accepting JsonObject and returning a TimestampAndMessageType to accepting JsonLogEvent and returning a string. Please verify that all calls to formatLogEvent in the codebase have been updated accordingly to prevent any runtime errors.

You can run the following script to find all usages of formatLogEvent:

Review the results to ensure each usage passes a JsonLogEvent and correctly handles the string return type.

✅ Verification successful

Verification Successful: All usages of formatLogEvent are updated to the new signature.

  • new-log-viewer/src/services/decoders/JsonlDecoder/index.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of `formatLogEvent` and check their arguments.

rg --type ts 'formatLogEvent\s*\(' -A 2 -B 2

Length of output: 1077

new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1)

150-156: Confirm the structure of DecodeResultType matches the returned array.

In #getDecodeResult, the method returns an array with [message, timestamp, logLevel, lineNumber]. Ensure that this aligns with the DecodeResultType definition to prevent type inconsistencies.

Please verify that DecodeResultType is defined as [string, number, LOG_LEVEL, number]. If it differs, adjust the return structure accordingly.

new-log-viewer/src/typings/formatters.ts Show resolved Hide resolved
new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts Outdated Show resolved Hide resolved
Comment on lines 26 to 35
/**
* Narrow JSON value to JSON object if compatible.
* Reference: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
*
* @param fields
* @return Whether type is JsonObject.
*/
const isJsonObject = (fields: JsonValue): fields is JsonObject => {
return "object" === typeof fields;
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider handling null values in isJsonObject function.

The isJsonObject function is well-implemented with a correct type predicate. However, it could be more robust by explicitly handling null values.

Consider updating the function to handle null values:

 const isJsonObject = (fields: JsonValue): fields is JsonObject => {
-    return "object" === typeof fields;
+    return typeof fields === "object" && fields !== null;
 };

This change ensures that null values are not incorrectly identified as JSON objects.

📝 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
/**
* Narrow JSON value to JSON object if compatible.
* Reference: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
*
* @param fields
* @return Whether type is JsonObject.
*/
const isJsonObject = (fields: JsonValue): fields is JsonObject => {
return "object" === typeof fields;
};
/**
* Narrow JSON value to JSON object if compatible.
* Reference: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
*
* @param fields
* @return Whether type is JsonObject.
*/
const isJsonObject = (fields: JsonValue): fields is JsonObject => {
return typeof fields === "object" && fields !== null;
};

new-log-viewer/src/typings/decoders.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts Outdated Show resolved Hide resolved
@davemarco davemarco changed the title Restructure jsonl decoder to better support future log filter. new-log-viewer: Restructure jsonl decoder to better support future log filter. Sep 27, 2024
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts Outdated Show resolved Hide resolved
new-log-viewer/src/typings/decoders.ts Outdated Show resolved Hide resolved
new-log-viewer/src/typings/decoders.ts Outdated Show resolved Hide resolved
new-log-viewer/src/typings/decoders.ts Outdated Show resolved Hide resolved
new-log-viewer/src/typings/decoders.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/LogFileManager.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/LogFileManager.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
new-log-viewer/src/services/formatters/LogbackFormatter.ts (1)

Line range hint 1-1: Approve removal of #parseTimestamp with a suggestion

The removal of the #parseTimestamp method is consistent with the new implementation and simplifies the class. This change is appropriate given that the timestamp is now expected to be pre-parsed in the JsonLogEvent.

Consider adding a comment or updating the class-level JSDoc to specify the expected format of the timestamp in the JsonLogEvent. This will help maintainers and users of the class understand the requirements for the input data.

For example:

/**
 * A formatter that uses a Logback-like format string to format log events into a string.
 * 
 * @remarks
 * The `timestamp` in the `JsonLogEvent` is expected to be a valid dayjs.Dayjs object.
 * It's the responsibility of the caller to ensure the timestamp is correctly parsed before passing it to this formatter.
 */
class LogbackFormatter implements Formatter {
    // ... existing code ...
}
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1)

227-227: Add a blank line before the return statement for better readability

As indicated by the static analysis hint, adding a blank line before the return; statement enhances code readability and adheres to the project's style guidelines.

🧰 Tools
🪛 GitHub Check: lint-check

[warning] 227-227:
Expected blank line before this statement

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f3cb5b4 and 4159305.

📒 Files selected for processing (6)
  • new-log-viewer/src/services/LogFileManager.ts (4 hunks)
  • new-log-viewer/src/services/decoders/ClpIrDecoder.ts (2 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts (1 hunks)
  • new-log-viewer/src/services/formatters/LogbackFormatter.ts (2 hunks)
  • new-log-viewer/src/typings/decoders.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • new-log-viewer/src/services/LogFileManager.ts
  • new-log-viewer/src/services/decoders/ClpIrDecoder.ts
  • new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts
  • new-log-viewer/src/typings/decoders.ts
🧰 Additional context used
🪛 GitHub Check: lint-check
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts

[warning] 227-227:
Expected blank line before this statement

🔇 Additional comments (4)
new-log-viewer/src/services/formatters/LogbackFormatter.ts (2)

9-9: LGTM: New import for JsonLogEvent type

The addition of the JsonLogEvent import is appropriate and aligns with the changes in the formatLogEvent method signature. This import enhances type safety and improves code clarity.


58-58: LGTM: Updated JSDoc comment

The JSDoc comment has been appropriately updated to reflect the new return type of the formatLogEvent method. This change maintains consistency between the documentation and the implementation.

new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (2)

71-80: Efficient memory management in the build method

The build method correctly invokes #deserialize() and frees the data array afterward, promoting efficient use of memory.


129-156: Proper handling of valid and invalid log events in #getDecodeResult

The method effectively distinguishes between valid and invalid log events, ensuring robust and reliable decoding results.

new-log-viewer/src/services/formatters/LogbackFormatter.ts Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (2)
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (2)

74-74: Simplify the calculation of numInvalidEvents using Map.size

You can use the size property of the Map object to get the number of invalid events directly, which improves performance and readability.

Apply this diff:

- const numInvalidEvents = Array.from(this.#invalidLogEventIdxToRawLine.keys()).length;
+ const numInvalidEvents = this.#invalidLogEventIdxToRawLine.size;

228-228: Add a blank line before the return statement for readability

The linter suggests adding a blank line before the return statement to adhere to the project's coding style and improve readability.

Apply this diff:

    if (null === logLevelFilter) {
        this.#filteredLogEventMap = null;
+       
        return;
    }
🧰 Tools
🪛 GitHub Check: lint-check

[warning] 228-228:
Expected blank line before this statement

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 4159305 and 01e4723.

📒 Files selected for processing (2)
  • new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1 hunks)
  • new-log-viewer/src/typings/decoders.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • new-log-viewer/src/typings/decoders.ts
🧰 Additional context used
🪛 GitHub Check: lint-check
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts

[warning] 228-228:
Expected blank line before this statement

🔇 Additional comments (1)
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1)

57-59: getEstimatedNumEvents method implementation is correct

The method accurately returns the total number of log events stored.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (8)
new-log-viewer/src/typings/logs.ts (3)

1-7: Simplify and standardize import statements

The new imports are necessary for the added type definitions. However, the import style for JsonObject is inconsistent with the others and flagged by the linter. Consider simplifying it to a single-line import for consistency and to resolve linter warnings.

Apply this change to standardize the imports:

 import {Nullable} from "./common";
 
 import {Dayjs} from "dayjs";
 
-import {
-    JsonObject,
-} from "./js";
+import {JsonObject} from "./js";
🧰 Tools
🪛 GitHub Check: lint-check

[warning] 1-1:
Run autofix to sort these imports!


[failure] 5-5:
Imports must not be broken into multiple lines if there are 1 or less elements


[failure] 5-5:
Unexpected line break after this opening brace


[failure] 7-7:
Unexpected line break before this closing brace


[failure] 7-7:
Expected 2 empty lines after import statement not followed by another import


29-31: Simplify export statement

While it's correct to export the new JsonLogEvent and LogLevelFilter types, the multi-line format is inconsistent with the single-line export below. To improve consistency and resolve the linter warning, consider simplifying this to a single-line export.

Apply this change to standardize the exports:

-export type {
-    JsonLogEvent,
-    LogLevelFilter};
+export type {JsonLogEvent, LogLevelFilter};
🧰 Tools
🪛 GitHub Check: lint-check

[failure] 31-31:
Expected a line break before this closing brace


Line range hint 1-36: Run linter autofix for remaining issues

The overall structure of the file is good, with clear separation of imports, type definitions, and exports. However, there are several linting warnings about line breaks and spacing. To improve code consistency and readability, it's recommended to run the linter's autofix feature.

Please run the linter's autofix command to resolve the remaining stylistic issues, such as:

  • Sorting imports
  • Adjusting line breaks after import statements
  • Ensuring consistent spacing

This will help maintain a consistent code style across the project.

🧰 Tools
🪛 GitHub Check: lint-check

[failure] 31-31:
Expected a line break before this closing brace

new-log-viewer/src/typings/formatters.ts (1)

1-1: Style: Add empty lines after import statement

To adhere to the project's style guide and resolve the linting issue, please add two empty lines after the import statement.

Apply this diff to fix the linting issue:

 import {JsonLogEvent} from "./logs";
+
+
 /**
  * Options for the LogbackFormatter.
🧰 Tools
🪛 GitHub Check: lint-check

[failure] 1-1:
Expected 2 empty lines after import statement not followed by another import

new-log-viewer/src/services/formatters/LogbackFormatter.ts (1)

Line range hint 122-134: Add null check in #formatTimestamp method

The #formatTimestamp method doesn't handle null timestamps, which could lead to runtime errors. Consider adding a null check:

#formatTimestamp (timestamp: dayjs.Dayjs, formatString: string): string {
-   if (null === this.#datePattern) {
+   if (null === this.#datePattern || null === timestamp) {
        return formatString;
    }

    const formattedDate = timestamp.format(this.#dateFormat);
    formatString = formatString.replace(this.#datePattern, formattedDate);

    return formatString;
}

This change will prevent potential runtime errors when dealing with null timestamps.

new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (3)

1-23: Consider sorting import statements to improve code readability

The static analysis tool indicates that the import statements are not sorted. Sorting imports enhances readability and maintains consistency across the codebase.

Apply the suggested autofix from the linter to sort the imports.

🧰 Tools
🪛 GitHub Check: lint-check

[warning] 1-1:
Run autofix to sort these imports!


28-28: Correct capitalization of 'JSON Lines' in the documentation

In the comment, 'JSON lines' should be capitalized as 'JSON Lines' to accurately reference the file format.

Apply this diff to correct the capitalization:

- * A decoder for JSONL (JSON lines) files that contain log events.
+ * A decoder for JSONL (JSON Lines) files that contain log events.

193-193: Add a blank line before return; to adhere to code style guidelines

The static analysis tool indicates that a blank line is expected before the return; statement. Adding a blank line improves code readability and follows the project's coding conventions.

Apply this diff:

    this.#filteredLogEventMap = null;

+   return;
    return;
🧰 Tools
🪛 GitHub Check: lint-check

[warning] 193-193:
Expected blank line before this statement

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 01e4723 and 114af1d.

📒 Files selected for processing (6)
  • new-log-viewer/src/services/LogFileManager.ts (4 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts (1 hunks)
  • new-log-viewer/src/services/formatters/LogbackFormatter.ts (2 hunks)
  • new-log-viewer/src/typings/formatters.ts (2 hunks)
  • new-log-viewer/src/typings/logs.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • new-log-viewer/src/services/LogFileManager.ts
  • new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts
🧰 Additional context used
🪛 GitHub Check: lint-check
new-log-viewer/src/services/decoders/JsonlDecoder/index.ts

[warning] 1-1:
Run autofix to sort these imports!


[warning] 193-193:
Expected blank line before this statement

new-log-viewer/src/typings/formatters.ts

[failure] 1-1:
Expected 2 empty lines after import statement not followed by another import

new-log-viewer/src/typings/logs.ts

[warning] 1-1:
Run autofix to sort these imports!


[failure] 5-5:
Imports must not be broken into multiple lines if there are 1 or less elements


[failure] 5-5:
Unexpected line break after this opening brace


[failure] 7-7:
Unexpected line break before this closing brace


[failure] 7-7:
Expected 2 empty lines after import statement not followed by another import


[failure] 31-31:
Expected a line break before this closing brace

🔇 Additional comments (7)
new-log-viewer/src/typings/logs.ts (2)

19-19: LGTM: New LogLevelFilter type

The new LogLevelFilter type alias is well-defined and provides a clear way to represent an optional array of log levels. This will be useful for implementing log filtering functionality in the future.


23-27: LGTM: Well-structured JsonLogEvent interface

The new JsonLogEvent interface is well-designed and provides a clear structure for JSON log events. It makes good use of the Dayjs type for timestamps, the LOG_LEVEL enum for log levels, and the JsonObject type for flexible field data. This structure will enhance type safety and consistency in log event handling throughout the application.

new-log-viewer/src/typings/formatters.ts (3)

22-24: LGTM: Simplified LogbackFormatterOptionsType

The removal of the timestampKey property from LogbackFormatterOptionsType is consistent with the PR's objective of relocating timestamp parsing. This simplification suggests a standardized approach to timestamp handling.

As mentioned in a previous review, please ensure that all references to timestampKey in other files have been addressed.


31-31: LGTM: Updated Formatter interface

The changes to the formatLogEvent method signature in the Formatter interface align well with the PR objectives. The use of JsonLogEvent instead of JsonObject improves type safety, and the simplified return type (string) suggests a streamlined approach to log formatting.

To ensure this change doesn't break existing code, please run the following verification:

#!/bin/bash
# Description: Check for any remaining uses of TimestampAndMessageType in the codebase

# Test: Search for TimestampAndMessageType. Expect: No results or only in test files.
rg --type typescript 'TimestampAndMessageType'

# Test: Search for formatLogEvent method calls. Expect: Updated method calls in relevant files.
rg --type typescript 'formatLogEvent'

1-1: LGTM: Import statement updated to use JsonLogEvent

The change from JsonObject to JsonLogEvent aligns with the PR objectives and suggests improved type safety for log events.

To ensure this change is consistently applied, please run the following verification:

✅ Verification successful

Verification Successful: Import Statement Update Confirmed

All instances of JsonLogEvent are correctly implemented across the codebase, and no remaining JsonObject references related to log events were detected.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of JsonLogEvent across the codebase

# Test: Search for JsonLogEvent usage. Expect: Multiple occurrences in relevant files.
rg --type typescript 'JsonLogEvent'

# Test: Search for any remaining JsonObject usage related to log events. Expect: No results or only in test files.
rg --type typescript 'JsonObject.*log'

Length of output: 154


Script:

#!/bin/bash
# Description: Verify the usage of JsonLogEvent across the codebase

# Test: Search for JsonLogEvent usage. Expect: Multiple occurrences in relevant files.
rg 'JsonLogEvent'

# Test: Search for any remaining JsonObject usage related to log events. Expect: No results or only in test files.
rg 'JsonObject.*log'

Length of output: 855

🧰 Tools
🪛 GitHub Check: lint-check

[failure] 1-1:
Expected 2 empty lines after import statement not followed by another import

new-log-viewer/src/services/formatters/LogbackFormatter.ts (2)

9-9: Clarify handling of invalid timestamps

With the removal of the #parseTimestamp method and the #timestampKey property, it's not clear how invalid timestamps are being handled. Could you please clarify:

  1. How are invalid timestamps being managed now?
  2. What are the implications of removing the #parseTimestamp method?
  3. Is the JsonLogEvent type ensuring that timestamps are always valid?

This information will help ensure that the log processing system remains robust in handling various timestamp formats and potential errors.


60-65: ⚠️ Potential issue

Add null check for timestamp and consider return type change impact

The refactored formatLogEvent method is more concise, which is good. However, there are a few points to consider:

  1. The method doesn't handle null timestamps. Consider adding a null check:
formatLogEvent (logEvent: JsonLogEvent): string {
    const {fields, timestamp} = logEvent;
+   if (timestamp === null) {
+       console.warn('Received null timestamp in logEvent');
+       return this.#formatVariables(this.#formatString, fields);
+   }
    const formatStringWithTimestamp: string =
        this.#formatTimestamp(timestamp, this.#formatString);

    return this.#formatVariables(formatStringWithTimestamp, fields);
}
  1. The return type has changed from an object to a string. Please verify that this change doesn't break any code that relies on the previous return type (TimestampAndMessageType).

  2. The removal of timestamp parsing logic might affect how invalid timestamps are handled. How are invalid timestamps being managed now?

To verify the impact of the return type change, please run the following script:

getFilteredLogEventMap (): FilteredLogEventMap {
// eslint-disable-next-line no-warning-comments
// TODO: Update this after log level filtering is implemented in clp-ffi-js
return null;
Copy link
Member

Choose a reason for hiding this comment

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

Would it be better if we make the log-level filtering a no-op rather than completely disabling the decoder?

Suggested change
return null;
console.error("Not implemented.");
return Array.from({length: this.#streamReader.getNumEventsBuffered()}, (_, i) => i);

Copy link
Contributor Author

@davemarco davemarco Oct 1, 2024

Choose a reason for hiding this comment

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

I put in the console error but not the return value. If the value is null, the new plan is it will just not use the filter, so it is okay to return null.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between a2814e4 and 81389df.

📒 Files selected for processing (8)
  • new-log-viewer/src/contexts/StateContextProvider.tsx (5 hunks)
  • new-log-viewer/src/services/LogFileManager/index.ts (4 hunks)
  • new-log-viewer/src/services/decoders/ClpIrDecoder.ts (2 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/index.ts (1 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts (1 hunks)
  • new-log-viewer/src/services/formatters/LogbackFormatter.ts (2 hunks)
  • new-log-viewer/src/typings/formatters.ts (2 hunks)
  • new-log-viewer/src/typings/logs.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • new-log-viewer/src/services/decoders/ClpIrDecoder.ts
  • new-log-viewer/src/services/decoders/JsonlDecoder/index.ts
  • new-log-viewer/src/typings/logs.ts
🧰 Additional context used
🪛 GitHub Check: lint-check
new-log-viewer/src/contexts/StateContextProvider.tsx

[failure] 224-224:
Missing semicolon

🔇 Additional comments (14)
new-log-viewer/src/typings/formatters.ts (3)

23-25: Reminder: Ensure timestampKey removal is addressed across the codebase.

The removal of the timestampKey property from LogbackFormatterOptionsType aligns with the PR's goal of relocating timestamp parsing. However, a previous review comment indicated that this property might still be referenced in other files.

Please ensure that all references to timestampKey have been addressed in the following files:

  • new-log-viewer/src/utils/config.ts
  • new-log-viewer/src/typings/decoders.ts
  • new-log-viewer/src/typings/config.ts
  • new-log-viewer/src/services/decoders/JsonlDecoder/index.ts
  • new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx

Let's verify the current status:

#!/bin/bash
# Description: Check for any remaining uses of timestampKey in the specified files

# Test: Search for 'timestampKey' in the specified files
rg 'timestampKey' new-log-viewer/src/utils/config.ts new-log-viewer/src/typings/decoders.ts new-log-viewer/src/typings/config.ts new-log-viewer/src/services/decoders/JsonlDecoder/index.ts new-log-viewer/src/components/modals/SettingsModal/SettingsDialog.tsx

32-32: LGTM: Formatter interface update streamlines log event processing.

The update to the formatLogEvent method signature in the Formatter interface is consistent with the overall restructuring. Changing the parameter type to LogEvent and simplifying the return type to string suggests a more streamlined formatting process.

Let's verify the impact on implementations of the Formatter interface:

#!/bin/bash
# Description: Check for implementations of the Formatter interface

# Test: Search for classes implementing the Formatter interface
rg --type typescript 'class.*implements.*Formatter'

# Test: Search for formatLogEvent method implementations
rg --type typescript 'formatLogEvent.*\(.*\).*{' -g '!*test*'

1-1: LGTM: Import change aligns with restructuring goals.

The change from JsonObject to LogEvent is consistent with the PR's objective of restructuring the log decoder. This suggests a move towards a more specific and structured log event type.

Let's verify the usage of LogEvent across the codebase:

✅ Verification successful

Verification Successful: LogEvent is consistently used across the codebase.

The change from JsonObject to LogEvent has been properly applied in multiple relevant files, aligning with the PR's objective of restructuring the log decoder.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of LogEvent type across the codebase

# Test: Search for LogEvent usage. Expect: Multiple occurrences in relevant files.
rg --type typescript 'LogEvent'

Length of output: 461


Script:

#!/bin/bash
# Description: Verify the usage of LogEvent type across the codebase

# Test: Search for LogEvent usage in TypeScript files. Expect: Multiple occurrences in relevant files.
rg --type ts 'LogEvent'

Length of output: 14453

new-log-viewer/src/services/formatters/LogbackFormatter.ts (3)

9-9: LGTM: Import statement addition is appropriate.

The addition of the LogEvent import aligns well with the changes in method signatures, particularly in the formatLogEvent method. This change enhances type safety and improves code readability.


Line range hint 1-156: Verify impact of removing #parseTimestamp method.

The removal of the #parseTimestamp method aligns with the restructuring of the log processing system. However, it's important to ensure that timestamp parsing and error handling for invalid timestamp values are adequately addressed elsewhere in the codebase.

Please run the following script to verify that timestamp parsing is handled appropriately:

#!/bin/bash
# Description: Verify timestamp parsing handling in the codebase

# Test 1: Search for timestamp parsing logic
echo "Searching for timestamp parsing logic:"
rg --type typescript -A 5 $'parseTimestamp|parse.*timestamp'

# Test 2: Search for dayjs usage related to timestamps
echo "Searching for dayjs usage related to timestamps:"
rg --type typescript -A 5 $'dayjs\s*\('

Review the results to ensure that timestamp parsing and error handling are implemented correctly in the appropriate location within the codebase.


60-60: Approve signature change and verify usage across codebase.

The updated method signature improves type safety by using the more specific LogEvent type instead of JsonObject. The change in return type to string simplifies the method's output. These changes align well with the refactoring objectives.

Please run the following script to verify that all calls to formatLogEvent have been updated accordingly:

✅ Verification successful

Update the shell script to use the correct file type identifier 'ts' instead of 'typescript'.

Please run the following script to verify that all calls to formatLogEvent have been updated accordingly:


Signature change verified and all usages are consistent.

The formatLogEvent method signature has been successfully updated, and all calls to this method across the codebase are consistent with the new signature. No issues were found during the verification process.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all calls to formatLogEvent match the new signature

# Test: Search for function calls to formatLogEvent. Expect: Only occurrences of the new signature.
rg --type typescript -A 5 $'formatLogEvent\s*\('

Length of output: 366


Script:

#!/bin/bash
# Description: Verify all calls to formatLogEvent match the new signature

# Test: Search for function calls to formatLogEvent. Expect: Only occurrences of the new signature.
rg --type ts -A 5 'formatLogEvent\s*\('

Length of output: 1205

new-log-viewer/src/contexts/StateContextProvider.tsx (5)

189-189: Excellent use of React state for page number management.

The introduction of the pageNum state variable using useState is a great improvement. This approach aligns better with React's state management paradigm compared to the previous use of useRef. It ensures that changes to the page number will trigger re-renders, which is crucial for keeping the UI in sync with the current page.


198-198: Removal of pageNumRef improves code clarity and state management.

The removal of pageNumRef is a positive change that complements the introduction of the pageNum state variable. This simplification eliminates potential synchronization issues between the ref and the rendered state, making the code more maintainable and less prone to errors related to stale ref values.


293-293: Correct usage of pageNum state in loadPageByAction.

The update to use pageNum instead of pageNumRef.current in the loadPageByAction function is correct and consistent with the new state-based approach. This change ensures that the most current page number is always used when navigating between pages, maintaining synchronization between the UI state and the navigation logic.


385-385: Correct update of context value with pageNum state.

The change to use pageNum instead of pageNumRef.current in the StateContext.Provider value is correct and consistent with the new state-based approach. This ensures that any components consuming this context will receive updates and re-render when the page number changes, maintaining consistency throughout the application.


Line range hint 1-391: Overall excellent refactoring of page number management.

The changes in this file represent a significant improvement in state management for the StateContextProvider component. By replacing pageNumRef with a pageNum state variable, the code now better aligns with React's state management paradigm. This refactoring ensures that:

  1. Changes to the page number will trigger appropriate re-renders.
  2. The risk of stale values due to ref usage is eliminated.
  3. The code is more maintainable and easier to reason about.

These changes contribute to a more robust and reactive log viewer application. Great job on this refactoring!

new-log-viewer/src/services/LogFileManager/index.ts (3)

144-144: Verify the correctness of parameters passed to decodeRange

Ensure that the parameters beginLogEventIdx and endLogEventIdx passed to decodeRange accurately represent the intended range of log events. It's important to confirm that these indices align with the decoder's expectations to avoid potential off-by-one errors.

If needed, consult the decodeRange method's documentation or implementation details to ensure proper usage.

Also applies to: 146-147


186-191: ⚠️ Potential issue

Double-check index adjustments to prevent off-by-one errors

Subtracting 1 from pageBeginLogEventNum and pageEndLogEventNum may introduce off-by-one errors if not handled correctly. Please verify that this adjustment is necessary and aligns with zero-based indexing used by the decoder.

Consider reviewing the index calculations or applying the following diff if an adjustment is required:

-                pageBeginLogEventNum - 1,
-                pageEndLogEventNum - 1,
+                pageBeginLogEventNum,
+                pageEndLogEventNum,

To confirm the correct indices, you can perform tests or review decoder expectations.


124-128: Ensure consistent method naming across the codebase

The method setDecoderOptions has been renamed to setFormatterOptions, which clarifies its purpose. Please verify that all references to this method have been updated accordingly throughout the codebase and in any related documentation.

To confirm consistency, you can run the following script:

✅ Verification successful

Consistent method naming confirmed

All references to setDecoderOptions have been appropriately renamed to setFormatterOptions. No remaining references to the old method name were found, ensuring consistency across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to the old method name.

# Test: Search for occurrences of 'setDecoderOptions'. Expect: No matches.
rg 'setDecoderOptions'

# Verify that 'setFormatterOptions' is used consistently.
rg 'setFormatterOptions'

Length of output: 823

@@ -220,7 +221,7 @@
break;
case WORKER_RESP_CODE.PAGE_DATA: {
setLogData(args.logs);
pageNumRef.current = args.pageNum;
setPageNum(args.pageNum)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update to use setPageNum is correct, but a semicolon is missing.

The change to use setPageNum(args.pageNum) is correct and consistent with the new state-based approach for managing the page number. This ensures that the component will re-render when the page number changes.

However, there's a minor syntax issue:

Add a semicolon at the end of the line for consistency with the coding style:

-                setPageNum(args.pageNum)
+                setPageNum(args.pageNum);
📝 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
setPageNum(args.pageNum)
setPageNum(args.pageNum);
🧰 Tools
🪛 GitHub Check: lint-check

[failure] 224-224:
Missing semicolon

Comment on lines 20 to 22
const isJsonObject = (value: JsonValue): value is JsonObject => {
return "object" === typeof value && null !== value;
};
Copy link

@coderabbitai coderabbitai bot Oct 1, 2024

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure value is not an array in isJsonObject

In JavaScript, arrays are of type "object", so the current check may incorrectly identify arrays as JsonObject. This could lead to unexpected behaviour when processing logs.

Apply the following change to exclude arrays:

 return "object" === typeof value && null !== value
+    && !Array.isArray(value);

This ensures that only non-null objects that are not arrays are considered as JsonObject.

📝 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 isJsonObject = (value: JsonValue): value is JsonObject => {
return "object" === typeof value && null !== value;
};
const isJsonObject = (value: JsonValue): value is JsonObject => {
return "object" === typeof value && null !== value
&& !Array.isArray(value);
};

Copy link
Member

Choose a reason for hiding this comment

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

The Rabbit is right about this one.

Copy link

Choose a reason for hiding this comment

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

@kirkrodrigues, glad to hear that!

(\╹‿╹)/

new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts Outdated Show resolved Hide resolved
Comment on lines +54 to +57
// Build index for the entire file.
const buildResult = decoder.build();
if (0 < buildResult.numInvalidEvents) {
console.error("Invalid events found in decoder.build():", buildResult);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider enhancing error handling for invalid events

While logging invalid events using console.error aids in debugging, it might be beneficial to implement a more robust error-handling mechanism. This could include counting invalid events, aggregating them for reporting, or providing feedback to the user if a significant number are encountered.

@davemarco
Copy link
Contributor Author

davemarco commented Oct 2, 2024

I did notice a small bug that the page number sometimes does not update when manually setting the log event number. I am 95% sure this is due to pageNum being a ref. However, I will fix in another PR, and not here. This PR is ready for final review, then merge.

new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts Outdated Show resolved Hide resolved
Comment on lines 37 to 40
// Json stringify covers edge case where the field is an object with more than one key, e.g.,
// `field = { "name": "INFO", "value": 20 }`.
const logLevelName = "object" === typeof field ?
JSON.stringify(field) :
Copy link
Member

Choose a reason for hiding this comment

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

@junhaoliao, if it's an object, shouldn't we just return early? A stringified JSON object won't match any of our hard-coded log levels, right?

Copy link
Member

Choose a reason for hiding this comment

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

If we are to support stringified JSON objects, the code below should be written as

    const uppercaseLogLevelName = logLevelName.toUpperCase();
    logLevelValue = LOG_LEVEL_NAMES.splice(1).find((name) => 
        uppercaseLogLevelName.includes(name)
    ) ?? LOG_LEVEL.NONE;

I vaguely remember seeing log levels being stored nested as an object in some logs though I can't find the logs now. If you believe the code has too much overhead introduced, let's do early returns, and we can come back to this for a more properly implementation when we see such requirements.

Copy link
Member

Choose a reason for hiding this comment

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

Gotcha. Iirc, the MongoDB log dataset has the level nested in key. That said, I'm not sure we should bother stringifying the field if it's an object since:

  1. It introduces overhead.
  2. It's a heuristic to search for the log level string in the stringified object.
  3. It hides the issue from the user which is really that they should be specifying the nested key as the level field.

What do you think?

Copy link
Member

@junhaoliao junhaoliao Oct 2, 2024

Choose a reason for hiding this comment

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

Sound good. Let's do early return here and defer the requirement of handling such nested objects.

Just curious, how does clp-s handle timestamps from nested objects? e.g., how should the user specify a timestamp key if the log looks like this:

{
    "t":
    {
        "timestamp.value": 123
    }
}

Copy link
Member

Choose a reason for hiding this comment

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

Theoretically, the user would escape any periods that are part of a key. So in the example: t.timestamp\.value. That said, clp-s doesn't support querying keys with escaped characters yet.

Copy link
Member

Choose a reason for hiding this comment

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

I see. In the log viewer, we don't treat periods as children access specifiers at the moment so accessing nested nodes are impossible. Let me create an issue for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added early return for object. Used generic object so will early return for null & array as well.

new-log-viewer/src/services/decoders/ClpIrDecoder.ts Outdated Show resolved Hide resolved
new-log-viewer/src/services/decoders/ClpIrDecoder.ts Outdated Show resolved Hide resolved
Comment on lines 20 to 22
const isJsonObject = (value: JsonValue): value is JsonObject => {
return "object" === typeof value && null !== value;
};
Copy link
Member

Choose a reason for hiding this comment

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

The Rabbit is right about this one.

Comment on lines 33 to 34
// If the field is an object , e.g. `field = { "name": "INFO", "value": 20 }`.
// Then the user should specify a nested key.
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure this comment is necessary since the if below basically reads: If it's undefined or an object, ignore it, which I think is pretty clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


// If the field is an object , e.g. `field = { "name": "INFO", "value": 20 }`.
// Then the user should specify a nested key.
if ("undefined" === typeof field || "object" === typeof field) {
Copy link
Member

Choose a reason for hiding this comment

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

Shall we use isJsonObject? Otherwise it's possible that field is an array or null.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

* @return A TypeScript type predicate indicating whether `value` is a `JsonObject`.
*/
const isJsonObject = (value: JsonValue): value is JsonObject => {
return "object" === typeof value && null !== value && !Array.isArray(value);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return "object" === typeof value && null !== value && !Array.isArray(value);
return "object" === typeof value && null !== value && false === Array.isArray(value);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (4)
new-log-viewer/src/services/decoders/ClpIrDecoder.ts (3)

37-44: LGTM: Method stub added for future implementation.

The getFilteredLogEventMap method has been correctly added as a placeholder for future implementation. The TODO comment provides clear guidance for developers.

Consider adding a JSDoc comment to describe the intended functionality of this method, which would be helpful for other developers working on this class.


46-53: LGTM: Method stub added for future implementation.

The setLogLevelFilter method has been correctly added as a placeholder for future implementation. The TODO comment provides clear guidance for developers.

Consider adding a JSDoc comment to describe the intended functionality of this method, including the expected behaviour when the filter is successfully set.


67-73: LGTM: Method renamed and updated for future filtering support.

The decode method has been appropriately renamed to decodeRange, which better describes its functionality. The addition of the useFilter parameter aligns with the PR objectives for future log level filtering.

Consider adding a TODO comment explaining the intended use of the useFilter parameter in the future implementation. This would complement the existing eslint-disable comment and provide clarity for future development.

new-log-viewer/src/typings/decoders.ts (1)

52-54: LGTM: getFilteredLogEventMap method added with a minor suggestion.

The getFilteredLogEventMap method is correctly defined and returns the appropriate type. However, the comment could be more descriptive.

Consider expanding the comment to provide more context:

-     * @return The filtered log events map.
+     * @return The filtered log events map, which maps indices in the filtered collection to indices in the unfiltered collection.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 81389df and 637d488.

📒 Files selected for processing (3)
  • new-log-viewer/src/services/decoders/ClpIrDecoder.ts (2 hunks)
  • new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts (1 hunks)
  • new-log-viewer/src/typings/decoders.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • new-log-viewer/src/services/decoders/JsonlDecoder/utils.ts
🔇 Additional comments (9)
new-log-viewer/src/services/decoders/ClpIrDecoder.ts (2)

7-8: LGTM: New imports added correctly.

The new imports for FilteredLogEventMap and LOG_EVENT_FILE_END_IDX have been added appropriately. These additions align with the new methods and changes in the class.


55-59: LGTM: Build method updated to align with restructuring objectives.

The build method has been successfully updated to use LOG_EVENT_FILE_END_IDX, ensuring consistent behaviour across the class. The return type LogEventCount provides more structured information about the build process, which is a good improvement.

new-log-viewer/src/typings/decoders.ts (7)

2-2: LGTM: Import statement for LogLevelFilter added.

The import of LogLevelFilter is correctly placed and necessary for the new log level filtering functionality.


36-40: LGTM: FilteredLogEventMap type added.

The FilteredLogEventMap type is well-defined and properly documented. The use of Nullable<number[]> is appropriate for cases where the map might not exist.


56-63: LGTM: setLogLevelFilter method added.

The setLogLevelFilter method is well-defined with appropriate parameters and return type. The comment provides a clear description of the method's purpose and return value.


64-70: LGTM: build method updated.

The build method has been simplified by removing parameters and now returns a more specific LogEventCount type. The updated comment accurately reflects these changes.


73-78: LGTM: setFormatterOptions method renamed and updated.

The method has been appropriately renamed from setDecoderOptions to setFormatterOptions, clarifying its specific purpose. The updated comment accurately reflects this change while maintaining the correct parameter and return types.


81-94: LGTM: decodeRange method updated with new parameter.

The method has been appropriately renamed from decode to decodeRange, better reflecting its functionality. The addition of the useFilter parameter enhances flexibility in decoding. The updated comment provides a clear and comprehensive explanation of the method's purpose and parameters.


108-108: LGTM: FilteredLogEventMap added to export statement.

The FilteredLogEventMap type has been correctly added to the export statement, making it accessible to other modules that may need to use this new type.

Copy link
Member

@kirkrodrigues kirkrodrigues left a comment

Choose a reason for hiding this comment

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

For the PR title, how about:

new-log-viewer: Define interface for filtering by log level and add support (internally) to JsonlDecoder; Move timestamp field extraction from LogbackFormatter to JsonlDecoder.

@davemarco davemarco changed the title new-log-viewer: Restructure jsonl decoder to better support future log filter. new-log-viewer: Define interface for filtering by log level and add support (internally) to JsonlDecoder; Move timestamp field extraction from LogbackFormatter to JsonlDecoder. Oct 2, 2024
@davemarco davemarco merged commit 5bc746a into y-scope:main Oct 2, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants