Logging system improvements: privacy, dedup, server identification, and log viewer enhancements#3230
Conversation
… writes - Add Debug Logging toggle in Developer Settings (runtime log level switch) - Add log deduplication: skip consecutive identical non-error messages at file transport and IPC boundary, keeping logs clean and lightweight - Enable async file writes (electron-log batching) to avoid blocking main thread - Buffer errors.jsonl writes with periodic flush instead of per-error appendFile - Fix privacy hook ordering: redact data before writing to errors.jsonl - Fix IPC rate limit memory leak: clean up on webContents destroy - Add incremental log reading (byte offset tailing) for efficient auto-refresh - Add clear logs confirmation dialog - Add scoped logger process context - Add log viewer i18n locale detection - Remove dead code (unused log wrappers, constants, background color fn) - Change search filter to session-only state for privacy - Clear authorized log paths on window close - Add missing IPC log levels (verbose, silly, default)
Add server-N tags to webview log entries so logs from different workspaces can be distinguished. The preload script queries the main process for the server index via a synchronous IPC handler that matches window.location.origin against the Redux server list. Log viewer UI gains a "Show Server" toggle, server filter dropdown, and server name resolution (server-N mapped to workspace title/URL via a new get-server-mapping IPC handler).
Load all entries from disk and apply the entry limit as a display cap on filtered results. Previously "Last 100 entries" loaded 100 from disk then filtered, showing fewer matches. Now it shows the last 100 entries matching the current filters.
- Add JWT detection and partial masking (eyJh...xK9s) - Add URL credential detection (https://user:pass@host) - Add credit card detection with Luhn checksum validation - Add long hex token detection (32+ char API keys/hashes) - Add IP address partial masking (preserve localhost/private ranges) - Add webhook URL and client secret patterns - Require 8+ char values on credential patterns to reduce false positives - Fix email regex to exclude package scopes and file extensions - Use partial masking instead of full [REDACTED] for better debugging - Add safe-key allowlist (token_type, password_policy, etc.) - Add max depth protection against stack overflow on nested objects - Update verbose logging toggle description for clarity
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review infoConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🧰 Additional context used📓 Path-based instructions (1)**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🔇 Additional comments (7)
WalkthroughAdds a persisted debug-logging flag with UI toggle and runtime watch; extends log viewer with server tagging, server filtering, incremental tail reads, and new IPC endpoints; implements logging deduplication, layered privacy redaction, NDJSON error buffering/rotation, and locale-aware i18n loading for the log viewer. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant UI as Log Viewer UI
participant Main as Main Process
participant FS as File System
User->>UI: Request server mapping / on load
UI->>Main: IPC: log-viewer-window/get-server-mapping()
Main->>Main: Read servers from store & build mapping
Main-->>UI: { success: true, mapping }
User->>UI: Trigger incremental read (tail)
UI->>Main: IPC: log-viewer-window/read-logs-tail({ fromByte, filePath? })
Main->>FS: Read file from offset
FS-->>Main: { logs, newSize, lastModifiedTime }
Main-->>UI: { success: true, logs, newSize, lastModifiedTime }
UI->>UI: Append incremental logs and re-render filtered results
sequenceDiagram
participant App as App Logger
participant Dedup as LogDeduplicator
participant Privacy as Privacy Hook
participant File as File Transport
App->>Dedup: shouldLog(level, context, args)
Dedup-->>App: allow/suppress
App->>Privacy: redactSensitiveData(entry)
Privacy-->>App: redactedEntry
App->>File: file transport hook (write redactedEntry)
File->>Dedup: file transport hook dedup check
File->>File: Append NDJSON error / rotate errors.jsonl as needed
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/logging/index.ts (1)
396-411:⚠️ Potential issue | 🟠 MajorUse
event.sender.idfor rate limiting instead of renderer-suppliedwebContentsId.The
console-logIPC handler uses renderer-suppliedwebContentsId(line 399) andserverUrl(lines 420–431) for rate limiting and server attribution. A malicious renderer can send arbitrary values in the IPC message—even if injected correctly at execution time (line 313), the renderer controls what it sends over IPC. This enables:
- Rate limit bypass: Send different spoofed
webContentsIdvalues to defeat per-process throttling- Server attribution forgery: Send arbitrary
serverUrlvalues to forge which server the logs came fromUse
event.sender.id(the authenticated sender from Electron's IPC event) for the rate limit key andsenderWebContents.getURL()for server matching instead.🔧 Proposed fix
(event, level, webContentsId, serverUrl, ...args) => { try { + const senderId = event.sender.id; const now = Date.now(); - let rateState = ipcRateLimit.get(webContentsId); + let rateState = ipcRateLimit.get(senderId); if (!rateState || now > rateState.resetTime) { rateState = { count: 0, resetTime: now + 1000 }; - ipcRateLimit.set(webContentsId, rateState); + ipcRateLimit.set(senderId, rateState); } rateState.count++; if (rateState.count > MAX_IPC_MESSAGES_PER_SECOND) { return; } - // Find the webContents that sent this message - const senderWebContents = - webContents.fromId(webContentsId) || event.sender; + const senderWebContents = event.sender; // Create enhanced context string with server info const context = getLogContext(senderWebContents); let contextStr = formatLogContext(context); // Add server index to webview context if ( selectFunction && - serverUrl && - serverUrl !== 'unknown' && senderWebContents.getType() === 'webview' ) { try { + const currentUrl = senderWebContents.getURL(); const servers = selectFunction( (state: RootState) => state.servers ); const serverIndex = servers.findIndex( (s: any) => - s.url === serverUrl + s.url && currentUrl.startsWith(s.url.replace(/\/$/, '')) ) + 1; if (serverIndex > 0) { contextStr = contextStr.replace(🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/logging/index.ts` around lines 396 - 411, The IPC console-log handler currently trusts renderer-supplied webContentsId and serverUrl for rate-limiting and attribution; update the handler to use event.sender.id as the rate-limit key (replace uses of webContentsId when accessing ipcRateLimit and counting against MAX_IPC_MESSAGES_PER_SECOND) and derive the origin URL from the authenticated sender (use senderWebContents.getURL() after computing senderWebContents from event.sender or webContents.fromId) instead of using the renderer-supplied serverUrl; adjust any logic that falls back to webContents.fromId(...) so it always treats event.sender as the authoritative source for id and URL.
🧹 Nitpick comments (1)
src/ipc/channels.ts (1)
98-122: Keep IPC contracts centralized by typing the server-tag channel too.
src/logging/preload.tssends'log-viewer-window/get-server-tag', but that channel is not present inChannelToArgsMap. Adding it here preserves compile-time contract checks.💡 Proposed addition
'log-viewer-window/get-server-mapping': () => { success: boolean; mapping: Record<string, string>; }; + 'log-viewer-window/get-server-tag': ( + origin: string + ) => string | undefined; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/ipc/channels.ts` around lines 98 - 122, Channel contract missing for the server-tag channel: add an entry for 'log-viewer-window/get-server-tag' into ChannelToArgsMap with the correct request/response shape so TypeScript checks cover preload.ts; for example, add a mapping from () => { success: boolean; tag?: string; error?: string } under the ChannelToArgsMap object to mirror other log-viewer-window contracts and ensure compile-time verification.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/logging/dedup.ts`:
- Around line 19-25: The makeKey method can throw when JSON.stringify is given
circular or non-serializable values; update makeKey in src/logging/dedup.ts to
safely serialize each arg instead of calling JSON.stringify directly: for each
arg in the args array attempt JSON.stringify in a try/catch and on failure fall
back to a safe, non-throwing representation (e.g., use String(a), a.toString(),
or util.inspect(a) with a fallback for BigInt), ensuring no exceptions propagate
from makeKey; preserve the existing replacements (.replace(/\b\d{4,}\b/g, '#')
and .replace(/\b\d+\.\d+\b/g, '#')) and continue returning `${level}|${text}`.
- Around line 12-13: The deduplication state is shared via the single field
lastKey causing IPC and file transport to interfere; add two separate fields
(e.g., lastIpcKey and lastFileKey) on the LogDeduplicator class, initialize them
like the current lastKey, update shouldLog(...) to read/update lastIpcKey only,
and update createFileHook(...) (and any file-write-related helpers) to
read/update lastFileKey only so IPC and file deduplication are isolated.
In `@src/logging/index.ts`:
- Around line 148-173: flushErrorJsonl currently appends errorJsonlBuffer using
fs.promises.appendFile without awaiting, and the before-quit handler invokes
flushErrorJsonl synchronously so logs can be lost on fast shutdown; modify
flushErrorJsonl (and any caller such as the before-quit handler) to perform a
synchronous write path during shutdown: expose a new synchronous flush path
inside flushErrorJsonl that uses fs.existsSync/fs.statSync and fs.writeFileSync
or fs.appendFileSync to truncate and append to errorJsonlPath when called with a
shutdown flag (or call a new flushErrorJsonlSync helper), ensure it handles
MAX_ERROR_LOG_SIZE truncation the same way, and update the before-quit handler
to call the synchronous variant (flushErrorJsonlSync or flushErrorJsonl(true))
so the process writes logs to disk before exit.
In `@src/logging/privacy.ts`:
- Around line 148-157: The current replacer in the IP redaction logic (pattern:
... , replacer: (m) => { ... }) incorrectly treats all 172.* addresses as
private; update the condition so only 172.16.0.0–172.31.255.255 are exempted.
Replace the m.startsWith('172.') check with a precise test (e.g. parse the
second octet with m.split('.') and ensure parseInt(octets[1]) is between 16 and
31 inclusive, or use a regex like /^172\.(1[6-9]|2[0-9]|3[01])\./) inside the
replacer so public 172.x.x.x addresses are masked. Ensure you keep existing
exemptions (127.0.0.1, 0.0.0.0, 192.168.*, 10.*) and only alter the 172 check.
In `@src/logViewerWindow/ipc.ts`:
- Around line 325-356: The IPC handler should validate and sanitize
options.fromByte before numeric ops: in the async handler that reads options ({
fromByte: number; filePath?: string }), check that options.fromByte is a finite
integer (e.g., typeof === 'number' && Number.isFinite(...) &&
Number.isInteger(...)) or coerce it safely (Number(...) and floor) and fallback
to 0 if invalid, then use that sanitized value when computing fromByte =
Math.max(0, Math.min(sanitizedFromByte, stats.size)); this prevents NaN being
passed to fs.createReadStream or other downstream APIs.
---
Outside diff comments:
In `@src/logging/index.ts`:
- Around line 396-411: The IPC console-log handler currently trusts
renderer-supplied webContentsId and serverUrl for rate-limiting and attribution;
update the handler to use event.sender.id as the rate-limit key (replace uses of
webContentsId when accessing ipcRateLimit and counting against
MAX_IPC_MESSAGES_PER_SECOND) and derive the origin URL from the authenticated
sender (use senderWebContents.getURL() after computing senderWebContents from
event.sender or webContents.fromId) instead of using the renderer-supplied
serverUrl; adjust any logic that falls back to webContents.fromId(...) so it
always treats event.sender as the authoritative source for id and URL.
---
Nitpick comments:
In `@src/ipc/channels.ts`:
- Around line 98-122: Channel contract missing for the server-tag channel: add
an entry for 'log-viewer-window/get-server-tag' into ChannelToArgsMap with the
correct request/response shape so TypeScript checks cover preload.ts; for
example, add a mapping from () => { success: boolean; tag?: string; error?:
string } under the ChannelToArgsMap object to mirror other log-viewer-window
contracts and ensure compile-time verification.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
src/app/PersistableValues.tssrc/app/selectors.tssrc/i18n/en.i18n.jsonsrc/ipc/channels.tssrc/logViewerWindow/LogEntry.tsxsrc/logViewerWindow/constants.tssrc/logViewerWindow/ipc.tssrc/logViewerWindow/log-viewer-window.tsxsrc/logViewerWindow/logViewerWindow.tsxsrc/logViewerWindow/types.tssrc/logging/cleanup.tssrc/logging/dedup.tssrc/logging/index.tssrc/logging/preload.tssrc/logging/privacy.tssrc/logging/scopes.tssrc/logging/utils.tssrc/main.tssrc/store/rootReducer.tssrc/ui/actions.tssrc/ui/components/SettingsView/DeveloperTab.tsxsrc/ui/components/SettingsView/features/DebugLogging.tsxsrc/ui/reducers/isDebugLoggingEnabled.ts
💤 Files with no reviewable changes (2)
- src/logViewerWindow/constants.ts
- src/logging/utils.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: check (macos-latest)
- GitHub Check: check (windows-latest)
- GitHub Check: check (ubuntu-latest)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript strict mode enabled in TypeScript configuration
Use React functional components with hooks instead of class components
Follow FSA (Flux Standard Action) pattern for Redux actions
Use camelCase for file names and PascalCase for component file names
All code must pass ESLint and TypeScript checks
Write self-documenting code with clear naming; avoid unnecessary comments except for complex business logic or non-obvious decisions
Use Fuselage components from@rocket.chat/fuselagefor all UI work and only create custom components when Fuselage doesn't provide what's needed
CheckTheme.d.tsfor valid color tokens when using Fuselage components
Use defensive coding with optional chaining and fallbacks for Linux-only APIs (process.getuid(), process.getgid(), process.geteuid(), process.getegid()) to ensure cross-platform compatibility across Windows, macOS, and Linux
Files:
src/logging/preload.tssrc/logging/dedup.tssrc/ui/reducers/isDebugLoggingEnabled.tssrc/ui/actions.tssrc/logging/cleanup.tssrc/ui/components/SettingsView/features/DebugLogging.tsxsrc/app/PersistableValues.tssrc/ui/components/SettingsView/DeveloperTab.tsxsrc/logViewerWindow/types.tssrc/logging/index.tssrc/app/selectors.tssrc/ipc/channels.tssrc/logViewerWindow/logViewerWindow.tsxsrc/store/rootReducer.tssrc/logging/privacy.tssrc/logViewerWindow/log-viewer-window.tsxsrc/main.tssrc/logViewerWindow/ipc.tssrc/logViewerWindow/LogEntry.tsxsrc/logging/scopes.ts
🧠 Learnings (7)
📚 Learning: 2026-02-04T19:30:03.354Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-02-04T19:30:03.354Z
Learning: Applies to src/outlookCalendar/**/preload.ts : In `preload.ts`, keep logging minimal as it runs in the renderer process and cannot access the centralized `global.isVerboseOutlookLoggingEnabled` variable, causing all logs to always appear
Applied to files:
src/logging/preload.tssrc/logging/index.tssrc/main.tssrc/logging/scopes.ts
📚 Learning: 2026-02-04T19:30:03.354Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-02-04T19:30:03.354Z
Learning: Applies to src/outlookCalendar/**/*@(calendar|outlook)*.{ts,tsx} : Always use the centralized logger from `logger.ts` (import `outlookLog`, `outlookError`, `outlookWarn`, or `outlookDebug`) instead of using `console.log` directly for Outlook Calendar module logging
Applied to files:
src/logging/preload.tssrc/logging/index.tssrc/main.tssrc/i18n/en.i18n.jsonsrc/logging/scopes.ts
📚 Learning: 2026-02-04T19:30:03.354Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-02-04T19:30:03.354Z
Learning: Applies to src/outlookCalendar/**/*@(calendar|outlook)*.{ts,tsx} : Use `outlookError()` for errors that should always be logged regardless of verbose mode settings, since error visibility is critical for debugging
Applied to files:
src/logging/preload.tssrc/i18n/en.i18n.json
📚 Learning: 2026-02-04T19:30:03.354Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-02-04T19:30:03.354Z
Learning: Applies to src/outlookCalendar/**/*@(calendar|outlook)*.{ts,tsx} : Use `outlookLog()`, `outlookWarn()`, and `outlookDebug()` only when verbose logging is expected to be enabled - they respect the verbose logging toggle from Settings > Developer > Verbose Outlook Logging
Applied to files:
src/ui/actions.tssrc/ui/components/SettingsView/features/DebugLogging.tsxsrc/app/PersistableValues.tssrc/ui/components/SettingsView/DeveloperTab.tsxsrc/logging/index.tssrc/app/selectors.tssrc/main.tssrc/i18n/en.i18n.jsonsrc/logging/scopes.ts
📚 Learning: 2026-02-04T19:29:54.650Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-04T19:29:54.650Z
Learning: Applies to **/*.{ts,tsx} : Use Fuselage components from `rocket.chat/fuselage` for all UI work and only create custom components when Fuselage doesn't provide what's needed
Applied to files:
src/ui/components/SettingsView/features/DebugLogging.tsxsrc/ui/components/SettingsView/DeveloperTab.tsxsrc/logViewerWindow/LogEntry.tsx
📚 Learning: 2026-02-04T19:29:54.650Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-04T19:29:54.650Z
Learning: Applies to **/*.{ts,tsx} : Use defensive coding with optional chaining and fallbacks for Linux-only APIs (process.getuid(), process.getgid(), process.geteuid(), process.getegid()) to ensure cross-platform compatibility across Windows, macOS, and Linux
Applied to files:
src/logging/index.ts
📚 Learning: 2026-02-04T19:29:54.650Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-04T19:29:54.650Z
Learning: Applies to **/*.{ts,tsx} : Check `Theme.d.ts` for valid color tokens when using Fuselage components
Applied to files:
src/logViewerWindow/LogEntry.tsx
🧬 Code graph analysis (11)
src/ui/reducers/isDebugLoggingEnabled.ts (3)
src/store/actions.ts (1)
ActionOf(42-42)src/ui/actions.ts (1)
SETTINGS_SET_DEBUG_LOGGING_CHANGED(129-130)src/app/actions.ts (1)
APP_SETTINGS_LOADED(6-6)
src/ui/components/SettingsView/features/DebugLogging.tsx (5)
src/ui/reducers/isDebugLoggingEnabled.ts (1)
isDebugLoggingEnabled(11-27)src/store/rootReducer.ts (1)
RootState(123-123)src/store/index.ts (1)
dispatch(38-41)src/store/actions.ts (1)
RootAction(44-46)src/ui/actions.ts (1)
SETTINGS_SET_DEBUG_LOGGING_CHANGED(129-130)
src/ui/components/SettingsView/DeveloperTab.tsx (1)
src/ui/components/SettingsView/features/DebugLogging.tsx (1)
DebugLogging(22-58)
src/logging/index.ts (6)
src/logging/dedup.ts (1)
LogDeduplicator(10-66)src/logging/privacy.ts (2)
createPrivacyHook(306-331)redactSensitiveData(235-257)src/store/rootReducer.ts (1)
RootState(123-123)src/urls.ts (1)
server(20-34)src/logging/context.ts (2)
getLogContext(216-237)formatLogContext(242-259)src/store/index.ts (1)
select(66-67)
src/app/selectors.ts (2)
src/store/rootReducer.ts (1)
RootState(123-123)src/ui/reducers/isDebugLoggingEnabled.ts (1)
isDebugLoggingEnabled(11-27)
src/logViewerWindow/logViewerWindow.tsx (2)
src/logViewerWindow/types.ts (2)
ReadLogsTailResponse(67-67)ClearLogsResponse(70-70)src/logViewerWindow/LogEntry.tsx (1)
LogEntry(61-138)
src/logViewerWindow/log-viewer-window.tsx (2)
src/i18n/common.ts (1)
fallbackLng(3-3)src/i18n/renderer.ts (1)
setupI18n(9-34)
src/main.ts (1)
src/logging/index.ts (1)
setupDebugLoggingWatch(506-524)
src/logViewerWindow/ipc.ts (4)
src/servers/reducers.ts (1)
servers(102-277)src/store/index.ts (1)
select(66-67)src/store/rootReducer.ts (1)
RootState(123-123)src/urls.ts (1)
server(20-34)
src/logViewerWindow/LogEntry.tsx (1)
src/logViewerWindow/types.ts (1)
LogEntryType(65-65)
src/logging/scopes.ts (1)
src/logging/context.ts (1)
getProcessContext(34-65)
🔇 Additional comments (20)
src/logging/cleanup.ts (1)
8-8: LGTM!The update from
errors.jsontoerrors.jsonlcorrectly aligns with the PR's migration to NDJSON format for error logging.src/app/PersistableValues.ts (2)
105-112: LGTM!The new
PersistableValues_4_13_0type and updatedPersistableValuesdefinition follow the established versioned type pattern correctly.
200-203: LGTM!The migration correctly initializes
isDebugLoggingEnabledtofalse, which is a sensible default (debug logging should be opt-in).src/logViewerWindow/types.ts (2)
25-25: LGTM!Adding
fileSizetoIReadLogsResponseenables tracking file size for incremental reading, consistent with the PR's tail reading feature.
30-36: LGTM!The new
IReadLogsTailResponseinterface is well-designed for incremental log reading, providing the necessary fields (newSize,lastModifiedTime) to track file state between reads.Also applies to: 67-67
src/ui/components/SettingsView/DeveloperTab.tsx (1)
4-4: LGTM!The
DebugLoggingcomponent is properly imported and positioned at the top of the logging section, which makes sense as it's a general debug toggle that should precede the more specific verbose logging options.Also applies to: 17-17
src/main.ts (1)
23-28: LGTM!The
setupDebugLoggingWatchcall is correctly positioned aftercreateMainReduxStore(), ensuring the Redux store is available when the watcher initializes. The implementation's defensive try/catch provides a safety net for edge cases.Also applies to: 82-82
src/store/rootReducer.ts (1)
26-26: LGTM!The
isDebugLoggingEnabledreducer is properly imported and integrated into the root reducer, correctly extendingRootStateto include the new debug logging state.Also applies to: 113-113
src/app/selectors.ts (1)
84-85: LGTM!The
isDebugLoggingEnabledselector is correctly added toselectPersistableValues, ensuring the debug logging preference is persisted across app sessions.src/ui/actions.ts (1)
129-130: LGTM!The new
SETTINGS_SET_DEBUG_LOGGING_CHANGEDaction follows the established FSA pattern and naming conventions, with a correct boolean payload type for the toggle setting.Also applies to: 268-268
src/logging/scopes.ts (1)
3-27: Looks good: scoped logs now include stable process context.This is a solid observability improvement and keeps the logger API unchanged.
src/i18n/en.i18n.json (1)
167-174: Translation additions are well-scoped and consistent.New keys match the introduced clear-logs, verbose logging, and server filter UX.
Also applies to: 327-331, 561-562, 600-603
src/logViewerWindow/log-viewer-window.tsx (1)
42-76: Locale detection and bundle loading flow looks correct.Good fallback strategy and clean integration into
setupI18n.src/logging/preload.ts (1)
11-25: Server tag enrichment is integrated cleanly with existing console override flow.Fallback behavior remains safe when IPC is unavailable.
Also applies to: 41-86
src/ui/reducers/isDebugLoggingEnabled.ts (1)
7-27: Reducer implementation is solid.State initialization and action handling are consistent with the new setting lifecycle.
src/ui/components/SettingsView/features/DebugLogging.tsx (1)
1-58: Nice implementation for the new developer setting toggle.Component wiring (state, dispatch, i18n, and label association) is clean.
src/logViewerWindow/LogEntry.tsx (1)
72-87: Server-tag derivation and conditional rendering look solid.The memoized server parsing and server/context chip split are clean and keep the row rendering predictable.
Also applies to: 117-125
src/logViewerWindow/logViewerWindow.tsx (2)
324-370: Filter + entry-limit ordering is correctly implemented.Applying the limit after all filters is the right behavior for “last N matching entries.”
399-460: Incremental tail-update flow is well structured.The truncate/rotate fallback plus tail-read append path is clear and resilient for normal streaming updates.
src/logging/index.ts (1)
133-140: Privacy-first hook ordering is correct.Applying redaction before dedup/file handling is the right sequencing to avoid leaking sensitive data into downstream paths.
- Use event.sender.id for IPC rate limiting instead of renderer-supplied webContentsId to prevent spoofing - Use senderWebContents.getURL() for server attribution instead of renderer-supplied serverUrl - Separate IPC and file transport dedup keys to prevent interference - Add try/catch in dedup makeKey to handle circular objects - Use synchronous writes in flushErrorJsonl during shutdown to prevent data loss - Fix IP address exemption: only 172.16-31.x.x are private (RFC 1918), not all 172.x.x.x - Validate fromByte parameter in read-logs-tail IPC handler
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/logging/dedup.ts`:
- Around line 69-72: The dedup key generation currently uses
message.data?.map(String).join(' ') which converts non-string structured
payloads to "[object Object]" and can erroneously suppress distinct logs; update
the logic that builds text (used in key and compared to this.lastFileKey) to
serialize non-string items deterministically (e.g., if item is a string keep it,
otherwise JSON.stringify with a safe fallback for circular refs or use
util.inspect) so structured objects produce meaningful tokens; modify the code
around message.data, text and key (references: message.data, text, key,
this.lastFileKey) to use the safe serialization helper and ensure the rest of
the key normalization (digit masking) stays the same.
In `@src/logging/privacy.ts`:
- Around line 279-283: redactObject(rest, ...) can return a non-object sentinel
(e.g. string), so do not spread its result unguarded; instead assign const
redactedRest = redactObject(rest, depth + 1, seen) and check its type: if typeof
redactedRest === 'object' && redactedRest !== null return { ...redactedRest,
state: '[Redux State Redacted]' }, otherwise return a stable object that
preserves the state key and carries the sentinel (for example return {
_redacted: redactedRest, state: '[Redux State Redacted]' }) so callers never
receive a corrupted shape; update the code around redactObject/rest accordingly.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/logViewerWindow/ipc.tssrc/logging/dedup.tssrc/logging/index.tssrc/logging/privacy.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: check (macos-latest)
- GitHub Check: check (ubuntu-latest)
- GitHub Check: check (windows-latest)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript strict mode enabled in TypeScript configuration
Use React functional components with hooks instead of class components
Follow FSA (Flux Standard Action) pattern for Redux actions
Use camelCase for file names and PascalCase for component file names
All code must pass ESLint and TypeScript checks
Write self-documenting code with clear naming; avoid unnecessary comments except for complex business logic or non-obvious decisions
Use Fuselage components from@rocket.chat/fuselagefor all UI work and only create custom components when Fuselage doesn't provide what's needed
CheckTheme.d.tsfor valid color tokens when using Fuselage components
Use defensive coding with optional chaining and fallbacks for Linux-only APIs (process.getuid(), process.getgid(), process.geteuid(), process.getegid()) to ensure cross-platform compatibility across Windows, macOS, and Linux
Files:
src/logging/index.tssrc/logging/privacy.tssrc/logging/dedup.tssrc/logViewerWindow/ipc.ts
🧠 Learnings (4)
📚 Learning: 2026-02-04T19:30:03.354Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-02-04T19:30:03.354Z
Learning: Applies to src/outlookCalendar/**/preload.ts : In `preload.ts`, keep logging minimal as it runs in the renderer process and cannot access the centralized `global.isVerboseOutlookLoggingEnabled` variable, causing all logs to always appear
Applied to files:
src/logging/index.ts
📚 Learning: 2026-02-04T19:30:03.354Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-02-04T19:30:03.354Z
Learning: Applies to src/outlookCalendar/**/*@(calendar|outlook)*.{ts,tsx} : Always use the centralized logger from `logger.ts` (import `outlookLog`, `outlookError`, `outlookWarn`, or `outlookDebug`) instead of using `console.log` directly for Outlook Calendar module logging
Applied to files:
src/logging/index.ts
📚 Learning: 2026-02-04T19:30:03.354Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: src/outlookCalendar/AGENTS.md:0-0
Timestamp: 2026-02-04T19:30:03.354Z
Learning: Applies to src/outlookCalendar/**/*@(calendar|outlook)*.{ts,tsx} : Use `outlookLog()`, `outlookWarn()`, and `outlookDebug()` only when verbose logging is expected to be enabled - they respect the verbose logging toggle from Settings > Developer > Verbose Outlook Logging
Applied to files:
src/logging/index.ts
📚 Learning: 2026-02-04T19:29:54.650Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.Electron PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-04T19:29:54.650Z
Learning: Applies to **/*.{ts,tsx} : Use defensive coding with optional chaining and fallbacks for Linux-only APIs (process.getuid(), process.getgid(), process.geteuid(), process.getegid()) to ensure cross-platform compatibility across Windows, macOS, and Linux
Applied to files:
src/logging/index.tssrc/logViewerWindow/ipc.ts
🧬 Code graph analysis (1)
src/logViewerWindow/ipc.ts (2)
src/store/index.ts (1)
select(66-67)src/store/rootReducer.ts (1)
RootState(123-123)
🔇 Additional comments (5)
src/logging/dedup.ts (1)
13-18: Good separation of IPC and file dedup state.
lastIpcKeyandlastFileKeyisolation is correct and prevents cross-channel suppression.src/logging/privacy.ts (1)
148-157: Private172.16.0.0/12handling is correctly constrained.The Line 156 check now precisely preserves only private 172 ranges while masking public
172.*.src/logViewerWindow/ipc.ts (1)
354-359:fromBytesanitization is solid.The numeric coercion + finite check + floor + clamp at Lines 355-359 is a good defensive boundary for
createReadStream.src/logging/index.ts (2)
214-217: Synchronous flush on shutdown is a strong reliability improvement.Using
flushErrorJsonl(true)inbefore-quitcloses the async-loss gap for buffered errors.
406-409: Good trust-boundary handling for renderer log attribution.Using
event.sender/senderWebContents.getURL()instead of renderer-supplied IDs/URLs is the right security posture.Also applies to: 427-443
src/logging/privacy.ts
Outdated
| const { state: _state, ...rest } = obj; | ||
| return { ...redactObject(rest, seen), state: '[Redux State Redacted]' }; | ||
| return { | ||
| ...redactObject(rest, depth + 1, seen), | ||
| state: '[Redux State Redacted]', | ||
| }; |
There was a problem hiding this comment.
Avoid spreading non-object redaction results.
At Line 281, redactObject(rest, ...) may return a sentinel string; spreading that corrupts the returned shape.
🔧 Proposed fix
- return {
- ...redactObject(rest, depth + 1, seen),
- state: '[Redux State Redacted]',
- };
+ const redactedRest = redactObject(rest, depth + 1, seen);
+ return {
+ ...(typeof redactedRest === 'object' && redactedRest !== null
+ ? redactedRest
+ : {}),
+ state: '[Redux State Redacted]',
+ };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/logging/privacy.ts` around lines 279 - 283, redactObject(rest, ...) can
return a non-object sentinel (e.g. string), so do not spread its result
unguarded; instead assign const redactedRest = redactObject(rest, depth + 1,
seen) and check its type: if typeof redactedRest === 'object' && redactedRest
!== null return { ...redactedRest, state: '[Redux State Redacted]' }, otherwise
return a stable object that preserves the state key and carries the sentinel
(for example return { _redacted: redactedRest, state: '[Redux State Redacted]'
}) so callers never receive a corrupted shape; update the code around
redactObject/rest accordingly.
- Dedup file hook: serialize structured objects with JSON.stringify instead of String() to produce meaningful dedup keys - Privacy: guard redactObject spread against non-object return value when processing nested Redux state
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/logging/privacy.ts`:
- Around line 263-265: The depth check currently uses "if (depth > 10) return
'[Nested Object Redacted]';" which allows processing at depth 10 instead of
redacting at that limit; change the condition to "if (depth >= 10) return
'[Nested Object Redacted]';" (update the check that references the variable
depth and the redaction string '[Nested Object Redacted]') so the function
enforces a maximum depth of 10.
- Around line 104-106: The regex replacer currently preserves the captured
username because the replacer function only accepts (_m, proto, user) and then
injects user into the output; update the replacer to accept the password capture
as a third parameter (e.g., (_m, proto, user, pass)) and redact the username as
well as the password in the returned string (for example return
`${proto}[REDACTED]:[REDACTED]@` or a masked username) so both the username and
password captures from the pattern /(https?:\/\/)([^:]+):([^@]+)@/gi are
removed.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/logging/dedup.tssrc/logging/privacy.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/logging/dedup.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: check (macos-latest)
- GitHub Check: check (windows-latest)
- GitHub Check: check (ubuntu-latest)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript strict mode enabled in TypeScript configuration
Use React functional components with hooks instead of class components
Follow FSA (Flux Standard Action) pattern for Redux actions
Use camelCase for file names and PascalCase for component file names
All code must pass ESLint and TypeScript checks
Write self-documenting code with clear naming; avoid unnecessary comments except for complex business logic or non-obvious decisions
Use Fuselage components from@rocket.chat/fuselagefor all UI work and only create custom components when Fuselage doesn't provide what's needed
CheckTheme.d.tsfor valid color tokens when using Fuselage components
Use defensive coding with optional chaining and fallbacks for Linux-only APIs (process.getuid(), process.getgid(), process.geteuid(), process.getegid()) to ensure cross-platform compatibility across Windows, macOS, and Linux
Files:
src/logging/privacy.ts
🔇 Additional comments (2)
src/logging/privacy.ts (2)
148-157: Precise172.16.0.0/12private-range handling looks good.The current regex correctly exempts only
172.16–172.31, not all172.*.
280-284: Good defensive guard before spreadingredactedRest.This avoids shape corruption when nested redaction returns a non-object sentinel.
- Redact both username and password in URLs with embedded credentials - Change depth check from > 10 to >= 10 to enforce max depth of 10
Summary
Comprehensive overhaul of the logging system focused on privacy, performance, usability, and developer experience.
[server-N]tags so logs from different workspaces can be distinguishedserver-Nto workspace name/URL), and fixed entry limit to apply after filteringChanges
Privacy (
src/logging/privacy.ts)eyJh...xK9s)https://user:pass@host) — password redacted1.2.*.*), localhost/private ranges preserved@rocket.chat/fuselage) or version strings[REDACTED]where possible for debugging utilityDeduplication (
src/logging/dedup.ts— new)Server Identification (
src/logging/preload.ts,src/logging/index.ts)window.location.originagainst Redux server list[renderer:webview] [server-1] [OutlookCalendar]Log Viewer (
src/logViewerWindow/)server-1displayed as workspace title/URL via IPCSettings
infoanddebugat runtimeOther
log.transports.file.sync = false)logInfo,logWarn,logError,logDebugfrom utils.tsMAX_LOG_FILE_SIZEfrom constants.tserrors.jsonrenamed toerrors.jsonlin cleanup protected filesTest plan
errors.jsonlis written and capped at 5MBSummary by CodeRabbit
New Features
Improvements