Preserve printf-style format substitution when piping server logs to browser console by mvanhorn · Pull Request #479 · TanStack/devtools · GitHub
Skip to content

Preserve printf-style format substitution when piping server logs to browser console#479

Open
mvanhorn wants to merge 1 commit into
TanStack:mainfrom
mvanhorn:fix/435-server-log-printf-format
Open

Preserve printf-style format substitution when piping server logs to browser console#479
mvanhorn wants to merge 1 commit into
TanStack:mainfrom
mvanhorn:fix/435-server-log-printf-format

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Jun 24, 2026

Copy link
Copy Markdown

🎯 Changes

Server log messages that use console format strings (%s, %d, %c, etc.) are now substituted correctly when forwarded to the browser devtools console, including the default enhanced-logs path where the source-location prefix sits before the user's arguments. Previously the format string was passed through as a plain argument, so substitutions were not applied and the raw %s tokens appeared in the panel.

The SSE bridge that forwards server-side console.log/console.error did not detect format strings in all cases: with enhanced logs enabled (the default), enhanceConsoleLog prepends a LOG /path:line:col prefix, so the real format string was no longer the first argument and the substitution path was skipped. This now accounts for the enhanced-log prefix, the direct SSE path, and the %c/empty-argument edge cases. Closes #435.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.

Summary by CodeRabbit

  • New Features

    • Server logs piped into the browser console now preserve printf-style formatting, including %s and %c substitutions.
  • Bug Fixes

    • Improved handling of server log output so styled prefixes and empty substitution segments display correctly.
    • Warn-level logs now keep the expected server prefix without unintended formatting changes.
    • Non-string first arguments are no longer treated as format strings.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/devtools-vite/src/virtual-console.ts`:
- Around line 321-324: The preserve-format detection in getConsoleFormatIndex is
too permissive and can treat literal percent text like “100%c” as a format
string when there are no matching substitution arguments. Update the logic
around getConsoleFormatIndex and the related preserve-format path to only
preserve formatting when the number of actual console placeholders is supported
by the available trailing args, so literal % sequences are not reclassified
after prefix injection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 37abba98-2a17-4807-b0ce-73c14e43479c

📥 Commits

Reviewing files that changed from the base of the PR and between e026667 and 2cc1dda.

📒 Files selected for processing (3)
  • .changeset/fresh-mails-bow.md
  • packages/devtools-vite/src/virtual-console.test.ts
  • packages/devtools-vite/src/virtual-console.ts

Comment on lines +321 to +324

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Avoid classifying literal % sequences as format substitutions.

getConsoleFormatIndex currently enables the preserve-format branch even when there are no substitution arguments. Literal messages like "CPU at 100%c" can then be treated as format strings and rendered incorrectly after prefix injection. Gate preservation by placeholder count vs available trailing args.

Suggested fix
-    function hasConsoleFormatSubstitution(arg) {
-      return typeof arg === 'string' && /(^|[^%])%[sdifocOj]/.test(arg);
-    }
+    function getConsoleFormatPlaceholderCount(arg) {
+      if (typeof arg !== 'string') return 0;
+      var matches = arg.match(/(^|[^%])%[sdifocOj]/g);
+      return matches ? matches.length : 0;
+    }

     function isEnhancedLogPrefix(arg) {
       return typeof arg === 'string' &&
         arg.indexOf('LOG') !== -1 &&
         arg.indexOf(String.fromCharCode(10) + ' ' + String.fromCharCode(8594) + ' ') !== -1;
     }

+    function hasResolvableConsoleFormatSubstitution(args, formatIndex) {
+      var placeholderCount = getConsoleFormatPlaceholderCount(args[formatIndex]);
+      return placeholderCount > 0 && (args.length - (formatIndex + 1)) >= placeholderCount;
+    }
+
     function getConsoleFormatIndex(args) {
-      if (hasConsoleFormatSubstitution(args[0])) return 0;
-      return isEnhancedLogPrefix(args[0]) && hasConsoleFormatSubstitution(args[1]) ? 1 : -1;
+      if (hasResolvableConsoleFormatSubstitution(args, 0)) return 0;
+      return isEnhancedLogPrefix(args[0]) && hasResolvableConsoleFormatSubstitution(args, 1) ? 1 : -1;
     }

Also applies to: 334-336

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/devtools-vite/src/virtual-console.ts` around lines 321 - 324, The
preserve-format detection in getConsoleFormatIndex is too permissive and can
treat literal percent text like “100%c” as a format string when there are no
matching substitution arguments. Update the logic around getConsoleFormatIndex
and the related preserve-format path to only preserve formatting when the number
of actual console placeholders is supported by the available trailing args, so
literal % sequences are not reclassified after prefix injection.

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.

Server log pipe drops printf-style format substitution, leaks raw %s into browser console

1 participant