Skip to content

Commit f4049d9

Browse files
authored
Log settings when capturing logs (#8948)
2 parents 6328d07 + 7a7b27a commit f4049d9

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

src/lsptoolshost/logging/captureLogs.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as fs from 'fs';
88
import archiver from 'archiver';
99
import { RoslynLanguageServer } from '../server/roslynLanguageServer';
1010
import { ObservableLogOutputChannel, LogMessage } from './observableLogOutputChannel';
11+
import { commonOptions, languageServerOptions, razorOptions } from '../../shared/options';
1112

1213
/**
1314
* Registers the command to capture C# log output.
@@ -199,6 +200,10 @@ async function createZipWithLogs(
199200
archive.append(csharpActivityLogContent, { name: 'csharp.activity.log' });
200201
archive.append(traceActivityLogContent, { name: 'csharp-lsp-trace.activity.log' });
201202

203+
// Add current settings to the archive
204+
const settingsContent = gatherCurrentSettings();
205+
archive.append(settingsContent, { name: 'csharp-settings.json' });
206+
202207
void archive.finalize();
203208
});
204209
}
@@ -216,6 +221,43 @@ async function readLogFileContent(logFileUri: vscode.Uri): Promise<string | null
216221
}
217222
}
218223

224+
/**
225+
* Gathers the current settings for CommonOptions, LanguageServerOptions, and RazorOptions.
226+
* Returns a formatted JSON string.
227+
*/
228+
function gatherCurrentSettings(): string {
229+
const settings = {
230+
commonOptions: getOptionValues(commonOptions),
231+
languageServerOptions: getOptionValues(languageServerOptions),
232+
razorOptions: getOptionValues(razorOptions),
233+
};
234+
return JSON.stringify(settings, null, 2);
235+
}
236+
237+
/**
238+
* Extracts all option values from an options object by iterating over its property descriptors.
239+
*
240+
* Note: We cannot use Object.keys() here because the options objects are class instances where
241+
* all properties are defined as getters on the prototype, not as own properties on the instance.
242+
* Object.keys() only returns enumerable own properties, so it would return an empty array.
243+
* Instead, we inspect the prototype's property descriptors to find all the getter functions.
244+
*/
245+
function getOptionValues<T extends object>(options: T): Record<string, unknown> {
246+
const result: Record<string, unknown> = {};
247+
const prototype = Object.getPrototypeOf(options);
248+
const descriptors = Object.getOwnPropertyDescriptors(prototype);
249+
250+
for (const [key, descriptor] of Object.entries(descriptors)) {
251+
// Skip constructor and non-getter properties
252+
if (key === 'constructor' || typeof descriptor.get !== 'function') {
253+
continue;
254+
}
255+
result[key] = (options as Record<string, unknown>)[key];
256+
}
257+
258+
return result;
259+
}
260+
219261
/**
220262
* Gets the default URI for saving the log archive.
221263
* Uses the first workspace folder if available, otherwise falls back to the user's home directory.

0 commit comments

Comments
 (0)