Skip to content

Commit 66ab0c8

Browse files
committed
chore(lsp): per-server stderr noise filter via suppressStderrPattern
Pyrefly narrates every request on stderr at INFO level, flooding the console with error-level noise. registerLanguageServer now accepts an optional suppressStderrPattern regex string (it crosses the node connector, so not a RegExp); matching stderr lines are dropped from the console log only. stderrTail still keeps the full text for crash reports, an invalid pattern is ignored, and servers without a pattern are untouched. PythonSupport opts in with ^\s*INFO\b.
1 parent d0fba7b commit 66ab0c8

3 files changed

Lines changed: 38 additions & 4 deletions

File tree

src-node/lsp-client.js

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,25 @@ exports.ping = async function ping() {
236236
* @param {Object} [params.workspaceConfiguration] - settings tree served to the server's
237237
* workspace/configuration pulls (sections resolved by dotted path); pulls answer null
238238
* without it
239+
* @param {string} [params.suppressStderrPattern] - regex source; stderr lines matching it are
240+
* dropped from the live console log for this server (for servers that narrate every
241+
* request, e.g. pyrefly with "^\\s*INFO\\b"). The full stderr is still kept in
242+
* stderrTail for crash reports
239243
* @returns {Promise<Object>} Result with success status and server info
240244
*/
241245
exports.startServer = async function startServer(params) {
242-
const { serverId, command, args = ['--stdio'], rootUri, workspaceConfiguration } = params;
246+
const { serverId, command, args = ['--stdio'], rootUri, workspaceConfiguration,
247+
suppressStderrPattern } = params;
248+
249+
// Compiled once here; a broken pattern must not take the server down over log cosmetics.
250+
let stderrDropRegex = null;
251+
if (suppressStderrPattern) {
252+
try {
253+
stderrDropRegex = new RegExp(suppressStderrPattern);
254+
} catch (err) {
255+
console.error(`[lsp-client][${serverId}] invalid suppressStderrPattern ignored:`, err.message);
256+
}
257+
}
243258

244259
if (!serverId || !command) {
245260
throw new Error('serverId and command are required');
@@ -291,7 +306,19 @@ exports.startServer = async function startServer(params) {
291306
if (serverState.stderrTail.length > 50) {
292307
serverState.stderrTail.shift();
293308
}
294-
console.error(`[lsp-client][${serverId} stderr]`, text.trimEnd());
309+
// A server registered with suppressStderrPattern narrates routine traffic on stderr
310+
// (e.g. pyrefly logs every request at INFO level), which drowns real problems in the
311+
// console. Drop matching lines from the console log only - stderrTail above keeps the
312+
// full text, so crash reports still carry everything.
313+
let consoleText = text.trimEnd();
314+
if (stderrDropRegex) {
315+
consoleText = text.split('\n')
316+
.filter(line => line.trim() && !stderrDropRegex.test(line))
317+
.join('\n');
318+
}
319+
if (consoleText) {
320+
console.error(`[lsp-client][${serverId} stderr]`, consoleText);
321+
}
295322
});
296323

297324
serverProcess.on('spawn', () => {

src/extensions/default/PythonSupport/main.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ define(function (require, exports, module) {
105105
// pyproject.toml stays authoritative over this.
106106
workspaceConfiguration: {
107107
python: { pyrefly: { typeCheckingMode: "default" } }
108-
}
108+
},
109+
// pyrefly narrates every request on stderr at INFO level - keep that out of the console
110+
suppressStderrPattern: "^\\s*INFO\\b"
109111
});
110112
if (client) {
111113
registered = true;

src/languageTools/LSPClient.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,8 @@ define(function (require, exports, module) {
705705
command: config.command,
706706
args: config.args || ["--stdio"],
707707
rootUri: rootUri,
708-
workspaceConfiguration: config.workspaceConfiguration
708+
workspaceConfiguration: config.workspaceConfiguration,
709+
suppressStderrPattern: config.suppressStderrPattern
709710
});
710711

711712
const initResult = await conn.execPeer("sendRequest", {
@@ -812,6 +813,10 @@ define(function (require, exports, module) {
812813
* treats the default null answer as "all diagnostics off").
813814
* @param {function(Array):Array} [config.filterDiagnostics] - server-specific post-filter for
814815
* published diagnostics
816+
* @param {string} [config.suppressStderrPattern] - regex source (string, not RegExp - it
817+
* crosses the node connector); stderr lines matching it are dropped from the live
818+
* console log. Opt in for servers that narrate every request on stderr (pyrefly uses
819+
* "^\\s*INFO\\b"); the full stderr is still kept node-side for crash reports.
815820
* @return {Promise<LanguageClient|null>} the client, or null if it could not be started
816821
*/
817822
async function registerLanguageServer(config) {

0 commit comments

Comments
 (0)