Portal Community

What Is Searched

FieldSearchedNotes
messageYesFull message text (post-sanitization)
dataYesSerialized to JSON string first, then searched
levelNoUse the level filter chips instead
nodeId / node nameNoUse the node filter dropdown instead
traceIdYesAllows searching by trace ID to find all logs for a specific trace

Search Implementation

// Case-insensitive substring search
function matchesSearch(entry: LogEntry, term: string): boolean {
  if (!term) return true;
  const lower = term.toLowerCase();
  const messageMatch = entry.message.toLowerCase().includes(lower);
  const dataMatch = entry.data
    ? JSON.stringify(entry.data).toLowerCase().includes(lower)
    : false;
  const traceMatch = entry.traceId.toLowerCase().includes(lower);
  return messageMatch || dataMatch || traceMatch;
}

Debounced Input

The search input is debounced by 200ms to avoid re-filtering the entire log buffer on every keystroke. With a 10,000-entry buffer, filtering is fast but debouncing prevents UI jank during rapid typing:

// Debounced search term state
const [searchTerm, setSearchTerm] = useState('');
const debouncedTerm = useDebounce(searchTerm, 200);

Highlight in Results

Matched portions of the message are wrapped in a highlight span. The highlight uses the accent colour (#fbbf24 — amber) so it is visually distinct from all level colours:

// Simple highlight utility
function highlight(text: string, term: string): ReactNode {
  if (!term) return text;
  const parts = text.split(new RegExp(`(${escapeRegex(term)})`, 'gi'));
  return parts.map((part, i) =>
    part.toLowerCase() === term.toLowerCase()
      ? <mark key={i} className="log-highlight">{part}</mark>
      : part
  );
}
Search + Filters Stack Text search combines with the level filter and node filter. All three constraints must be satisfied for a log entry to appear. For example: level=Error AND node=send-email AND message contains "timeout".