Skip to content

Conversation

@nikhilsaikethe
Copy link
Contributor

@nikhilsaikethe nikhilsaikethe commented Aug 20, 2025

User description

This PR helps to highlight text in logs page and also adds a left border for each depending upon the status of the logs


PR Type

Enhancement


Description

Add LogsHighLighting component for semantic highlighting
Highlight query terms across logs and JSON
Visual status indicators via colored borders/lines
FTS-aware coloring for selected columns


Diagram Walkthrough

flowchart LR
  Highlighter["LogsHighLighting.vue (new)"] -- "used by" --> Detail["DetailTable.vue"]
  Highlighter -- "used by" --> JsonPrev["JsonPreview.vue"]
  Highlighter -- "used by" --> Table["TenstackTable.vue"]
  Status["statusParser.ts (new)"] -- "row/log status color" --> Detail
  Status -- "row status stripe" --> Table
  Colors["keyValueParser.ts (new)"] -- "theme colors" --> Highlighter
  Composable["useTextHighlighter.ts (new)"] -- "highlight + semantic color" --> Highlighter
  Search["SearchResult.vue"] -- "pass highlight + FTS keys" --> Table
Loading

File Walkthrough

Relevant files
Enhancement
8 files
LogsHighLighting.vue
New component for semantic JSON/log highlighting                 
+324/-0 
DetailTable.vue
Add status top border and inline highlighting                       
+21/-6   
JsonPreview.vue
Use highlighter for key/value rendering                                   
+8/-14   
SearchResult.vue
Provide highlight query and FTS keys downstream                   
+16/-0   
TenstackTable.vue
Integrate highlighter and add status stripe                           
+34/-6   
useTextHighlighter.ts
New composable for text highlighting logic                             
+486/-0 
keyValueParser.ts
Theme-aware color palette utilities                                           
+53/-0   
statusParser.ts
Derive log severity and colors                                                     
+246/-0 
Bug fix
2 files
Index.vue
Fix column update timeout scoping                                               
+3/-3     
useLogs.ts
Correct FTS key detection logic                                                   
+1/-1     

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR introduces text highlighting functionality for the logs page along with a critical bug fix in the useLogs composable. The changes include:

  1. Bug Fix in useLogs: Corrects a critical error on line 3530 where indexOf was being called without the required parameter. The fix changes stream.settings.full_text_search_keys.indexOf > -1 to stream.settings.full_text_search_keys.indexOf(field) > -1, ensuring proper detection of full-text search keys.

  2. New Text Highlighting Composable: Adds useTextHighlighter.ts that provides comprehensive text highlighting and semantic colorization for log content. This composable combines:

    • Keyword highlighting by extracting search terms from SQL patterns (match_all, fuzzy_match)
    • Semantic colorization for different text types (IPs, URLs, timestamps, file paths)
    • Smart tokenization with quote merging to handle complex log formats
    • HTML escaping for security when rendering highlighted content

The text highlighter uses sophisticated pattern recognition to automatically colorize various technical content types commonly found in logs, making them more visually scannable. The implementation includes comprehensive tokenization logic that intelligently merges quoted strings and handles edge cases in log formatting. This enhancement integrates with the existing logs infrastructure through the useLogs composable to provide real-time highlighting based on current search queries and filters.

Confidence score: 4/5

  • This PR combines a critical bug fix with new functionality, making it generally safe but requiring attention to the new complexity
  • Score reflects the solid bug fix but concerns about unused imports, missing error handling in regex operations, and potential performance impacts with complex patterns
  • Pay close attention to the new useTextHighlighter.ts file for potential performance and error handling issues

2 files reviewed, 1 comment

Edit Code Review Bot Settings | Greptile

* @param text - Text segment to analyze
* @returns Object containing analysis results with boolean flags and counts for various text patterns
*/
function analyzeSegment(text: string): any {
Copy link
Contributor

Choose a reason for hiding this comment

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

style: return type should be properly typed instead of any for better type safety

Suggested change
function analyzeSegment(text: string): any {
function analyzeSegment(text: string): {
length: number;
wordCount: number;
hasUppercase: boolean;
hasLowercase: boolean;
hasDigits: boolean;
hasSpecialChars: boolean;
hasDots: boolean;
hasAtSymbol: boolean;
hasColons: boolean;
hasSlashes: boolean;
hasHyphens: boolean;
hasParentheses: boolean;
dotSeparatedNumbers: number;
startsWithUppercase: boolean;
isThreeDigitStatusCode: boolean;
isLargeNumber: boolean;
hasDateTimePattern: boolean;
hasVersionPattern: boolean;
hasCommonHttpVerb: boolean;
isUuidPattern: boolean;
isFilePath: boolean;
} {

@github-actions
Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Highlight Accuracy

The keyword splitting uses exact-case equality after a case-insensitive split, which may miss partial matches or mixed-case occurrences compared to expected highlighting; verify behavior against existing HighLight component and user expectations.

function splitTextByKeywords(text: string, keywords: string[]): Array<{ text: string; isHighlighted: boolean }> {
  if (!keywords.length || !text) {
    return [{ text, isHighlighted: false }];
  }

  // Create regex pattern from keywords (escape special characters)
  const escapedKeywords = keywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
  const pattern = new RegExp(`(${escapedKeywords.join('|')})`, 'gi');

  // Split by pattern but keep the delimiters
  const parts = text.split(pattern);
  const result: Array<{ text: string; isHighlighted: boolean }> = [];

  for (const part of parts) {
    if (!part) continue;

    // Check if this part matches any keyword (case-insensitive)
    const isHighlighted = keywords.some(keyword => 
      keyword.toLowerCase() === part.toLowerCase()
    );

    result.push({ text: part, isHighlighted });
  }
Debounce Refactor

The debounce/timeout state was changed from a ref to a plain property; ensure lifecycle and reactivity are correct and that updateColumnsTimeout is defined/cleared consistently to avoid leaks or race conditions.

updateSelectedColumns() {
  this.searchObj.meta.resultGrid.manualRemoveFields = true;
  // Clear any existing timeout
  if (this.updateColumnsTimeout) {
    clearTimeout(this.updateColumnsTimeout);
  }
  this.updateColumnsTimeout = setTimeout(() => {
    this.updateGridColumns();
  }, 50);
},
FTS Key Check

The condition now uses indexOf(field) on stream.settings.full_text_search_keys; validate that the array exists for all streams to avoid runtime errors and that field casing matches.

fieldObj = {
  name: field,
  ftsKey:
    stream.settings.full_text_search_keys.indexOf(field) > -1
      ? true
      : false,
  isSchemaField: true,

@github-actions
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Guard and normalize FTS key check

Accessing indexOf without arguments was a bug; your fix still fails if
full_text_search_keys is undefined or not an array, causing runtime errors. Guard
the access and normalize casing to match comparisons elsewhere.

web/src/composables/useLogs.ts [3688-3692]

-ftsKey:
-  stream.settings.full_text_search_keys.indexOf(field) > -1
-    ? true
-    : false,
+ftsKey: Array.isArray(stream.settings?.full_text_search_keys)
+  ? stream.settings.full_text_search_keys.map((k: string) => String(k).toLowerCase()).indexOf(String(field).toLowerCase()) > -1
+  : false,
Suggestion importance[1-10]: 8

__

Why: Adding Array.isArray guards prevents runtime errors when full_text_search_keys is undefined and normalizing case improves correctness across varying inputs, directly addressing a potential crash and logic flaw.

Medium
Avoid pre tag around HTML content

Rendering HTML via v-html inside a

 can cause double-escaping or broken whitespace 
because the child component injects spans. Replace
 with a semantic 
and explicitly
preserve whitespace via CSS to avoid layout bugs. Keep monospace styling on the
container class.

web/src/plugins/logs/DetailTable.vue [266-271]

-<pre
+<div
   :data-test="`log-detail-${value}-value`"
   class="table-pre"
   :style="{
-    'white-space': !shouldWrapValues ? 'nowrap' : 'pre-wrap',
+    whiteSpace: !shouldWrapValues ? 'nowrap' : 'pre-wrap',
   }"
-><LogsHighLighting :data="key" :show-braces="false" :query-string="highlightQuery" /></pre>
+>
+  <LogsHighLighting :data="key" :show-braces="false" :query-string="highlightQuery" />
+</div>
Suggestion importance[1-10]: 6

__

Why: Wrapping an HTML-rendering child inside a pre tag can create whitespace/styling issues; switching to a div while preserving whitespace is a reasonable UX fix with low risk and moderate impact.

Low
Fix column width boolean logic

The cell width calc mixes OR/AND incorrectly, forcing width calc for most cells. Use
explicit grouping so only non-resizable source cells fall back to dynamic width.
This prevents mis-sized columns and layout jitter.

web/src/plugins/logs/TenstackTable.vue [296-314]

-<td
-  v-for="(cell, cellIndex) in formattedRows[virtualRow.index]?.getVisibleCells?.()"
-  :key="cell.id"
-  :data-test="
-    'log-table-column-' +
-    virtualRow.index +
-    '-' +
-    cell.column.columnDef.id
-  "
-  class="tw-py-none tw-px-2 tw-items-center tw-justify-start tw-relative table-cell"
-  :class="[...tableCellClass, { 'tw-pl-4': cellIndex === 0 }]"
-  :style="{
-    width:
-      cell.column.columnDef.id !== 'source' ||
-      cell.column.columnDef.enableResizing
-        ? `calc(var(--col-${cell.column.columnDef.id}-size) * 1px)`
-        : wrap
-          ? width - 260 - 12 + 'px'
-          : 'auto',
-    height: wrap ? '100%' : '20px',
-  }"
->
-  ...
-  <LogsHighLighting
-    :data="cell.column.columnDef.id === 'source' ? cell.row.original : cell.renderValue()"
-    :show-braces="cell.column.columnDef.id === 'source'"
-    :show-quotes="cell.column.columnDef.id === 'source'"
-    :query-string="highlightQuery"
-    :simple-mode="!(cell.column.columnDef.id === 'source' || isFTSColumn(cell.column.columnDef.id, cell.renderValue(), selectedStreamFtsKeys))"
-  />
-</td>
+:style="{
+  width:
+    (cell.column.columnDef.id !== 'source' && cell.column.columnDef.enableResizing) ||
+    (cell.column.columnDef.id !== 'source' && !cell.column.columnDef.enableResizing)
+      ? `calc(var(--col-${cell.column.columnDef.id}-size) * 1px)`
+      : (cell.column.columnDef.id === 'source' && !cell.column.columnDef.enableResizing)
+        ? (wrap ? (width - 260 - 12 + 'px') : 'auto')
+        : `calc(var(--col-${cell.column.columnDef.id}-size) * 1px)`,
+  height: wrap ? '100%' : '20px',
+}"
Suggestion importance[1-10]: 3

__

Why: The original condition already calculates width for non-source or resizable columns; the proposed logic is overly complex and not clearly more correct, offering limited benefit and potential for confusion.

Low

@nikhilsaikethe nikhilsaikethe force-pushed the logs-ui-improvements branch 8 times, most recently from 4925797 to 46ac50d Compare August 25, 2025 13:28
@nikhilsaikethe nikhilsaikethe added the testing In Testing label Aug 25, 2025
@nikhilsaikethe nikhilsaikethe merged commit 1e9761b into main Aug 31, 2025
28 checks passed
@nikhilsaikethe nikhilsaikethe deleted the logs-ui-improvements branch August 31, 2025 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants