Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions src/lsptoolshost/logging/collectLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
verifyOrAcquireDotnetTool,
DumpType,
createActivityLogCapture,
generateReadmeContent,
LogsToCollect,
} from './loggingUtils';
import { runDotnetTraceInTerminal } from './profiling';
import { RazorLogger } from '../../razor/src/razorLogger';
Expand All @@ -30,13 +32,6 @@ interface CollectOptionQuickPickItem extends vscode.QuickPickItem {
option: CollectOption;
}

interface LogsToCollect {
activityLogs: boolean;
performanceTrace: boolean;
memoryDump: boolean;
gcDump: boolean;
}

/**
* Registers the unified collect logs command.
*/
Expand Down Expand Up @@ -142,15 +137,29 @@ async function collectLogs(
}),
{ modal: true }
);
} else if (archiveResult.uri) {
const openFolder = vscode.l10n.t('Open Folder');
const result = await vscode.window.showInformationMessage(
vscode.l10n.t('C# logs saved successfully.'),
openFolder
);
if (result === openFolder) {
await vscode.commands.executeCommand('revealFileInOS', archiveResult.uri);
}
return;
}

if (archiveResult.uri) {
await showReadme(selectedLogs, archiveResult.uri.fsPath);
await showSuccessPopup(archiveResult.uri);
}
}

async function showReadme(selectedLogs: LogsToCollect, archivePath: string) {
const readmeContent = generateReadmeContent(selectedLogs, archivePath);
const document = await vscode.workspace.openTextDocument({
content: readmeContent,
language: 'markdown',
});
await vscode.commands.executeCommand('markdown.showPreview', document.uri);
}

async function showSuccessPopup(uri: vscode.Uri) {
const openFolder = vscode.l10n.t('Open Folder');
const result = await vscode.window.showInformationMessage(vscode.l10n.t('C# logs saved successfully.'), openFolder);
if (result === openFolder) {
await vscode.commands.executeCommand('revealFileInOS', uri);
}
}

Expand Down
110 changes: 110 additions & 0 deletions src/lsptoolshost/logging/loggingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -575,3 +575,113 @@ export async function createActivityLogCapture(
},
};
}

/** Describes which additional logs were selected for collection. */
export interface LogsToCollect {
activityLogs: boolean;
performanceTrace: boolean;
memoryDump: boolean;
gcDump: boolean;
}

/**
* Generate a readme.md file which describes the contents of the log archive,
* warns the user about potentially sensitive information in the logs, and
* provides instructions on how to share the logs with Microsoft for troubleshooting.
* @param options Which additional logs were selected for collection
* @param archivePath The absolute path where the archive was saved on disk
*/
export function generateReadmeContent(options: LogsToCollect, archivePath: string): string {
const lines: string[] = [];

lines.push('# C# Extension Log Archive');
lines.push('');
lines.push(
'An archive was generated by the **C# extension for Visual Studio Code** (`CSharp: Collect C# Logs` command).'
);
lines.push('');
lines.push(`**Archive location**: [${archivePath}](${archivePath})`);
lines.push('');

lines.push('## Contents');
lines.push('');

lines.push('### Current Logs and Settings');
lines.push('');
lines.push('| File | Description |');
lines.push('| --- | --- |');
lines.push('| `csharp.log` | C# extension output log |');
lines.push('| `csharp-lsp-trace.log` | LSP trace log between VS Code and the Roslyn language server |');
lines.push('| `razor.log` | Razor language support log |');
lines.push('| `csharp-settings.json` | Current C# extension settings at time of capture |');
lines.push('');

if (options.activityLogs) {
lines.push('### Record Activity');
lines.push('');
lines.push(
'Activity logs capture live output recorded during the diagnostic session with the log level set to Trace.'
);
lines.push('');
lines.push('| File | Description |');
lines.push('| --- | --- |');
lines.push('| `csharp.activity.log` | C# output captured during the recording session |');
lines.push('| `csharp-lsp-trace.activity.log` | LSP trace captured during the recording session |');
lines.push('| `razor.activity.log` | Razor output captured during the recording session |');
lines.push('');
}

if (options.performanceTrace) {
lines.push('### Performance Trace');
lines.push('');
lines.push(
'A `.nettrace` file captured using `dotnet-trace`. This file contains runtime events from the language server process.'
);
lines.push('');
lines.push(
'You can view this file using [PerfView](https://github.com/microsoft/perfview), [dotnet-trace convert](https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-trace#dotnet-trace-convert), or Visual Studio.'
);
lines.push('');
}

if (options.memoryDump) {
lines.push('### Memory Dump');
lines.push('');
lines.push(
'One or more `.dmp` files captured using `dotnet-dump`. These contain a process memory dump of the language server.'
);
lines.push('');
lines.push(
'> **WARNING**: Memory dumps contain the full process memory and may include sensitive data such as source code, file contents, and credentials loaded in memory.'
);
lines.push('');
}

if (options.gcDump) {
lines.push('### GC Dump');
lines.push('');
lines.push(
'One or more `.gcdump` files captured using `dotnet-gcdump`. These contain managed heap information from the language server.'
);
lines.push('');
}

lines.push('## Sharing');
lines.push('');

lines.push('> **WARNING**: This archive may contain sensitive information such as file paths, project names,');
lines.push('> source code fragments, and other workspace-specific details. Please review the contents before');
lines.push('> sharing publicly.');
lines.push('');

lines.push(
'**Publicly**: Attach this archive to your [GitHub issue](https://github.com/dotnet/vscode-csharp/issues).'
);
lines.push('');
lines.push(
'**Privately**: If the archive contains sensitive information, upload it via the [Developer Community](https://developercommunity.visualstudio.com/dotnet/report) page and reference your GitHub issue in the description.'
);
lines.push('');

return lines.join('\n');
}
Loading