parent
8b93c01655
commit
247d61f4f1
|
@ -50,7 +50,7 @@ _code()
|
|||
--uninstall-extension --enable-proposed-api --verbose --log -s
|
||||
--status -p --performance --prof-startup --disable-extensions
|
||||
--disable-extension --inspect-extensions
|
||||
--inspect-brk-extensions --disable-gpu --upload-logs
|
||||
--inspect-brk-extensions --disable-gpu
|
||||
--max-memory=' -- "$cur") )
|
||||
[[ $COMPREPLY == *= ]] && compopt -o nospace
|
||||
return
|
||||
|
|
|
@ -30,7 +30,6 @@ arguments=(
|
|||
'--inspect-extensions[allow debugging and profiling of extensions]'
|
||||
'--inspect-brk-extensions[allow debugging and profiling of extensions with the extension host being paused after start]'
|
||||
'--disable-gpu[disable GPU hardware acceleration]'
|
||||
'--upload-logs[upload logs from current session to a secure endpoint]:confirm:(iConfirmLogsUpload)'
|
||||
'--max-memory=[max memory size for a window (in Mbytes)]:size (Mbytes)'
|
||||
'*:file or directory:_files'
|
||||
)
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import * as cp from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { localize } from 'vs/nls';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { IRequestService } from 'vs/platform/request/node/request';
|
||||
import { IRequestContext } from 'vs/base/node/request';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ILaunchService } from 'vs/platform/launch/electron-main/launchService';
|
||||
|
||||
interface PostResult {
|
||||
readonly blob_id: string;
|
||||
}
|
||||
|
||||
class Endpoint {
|
||||
private constructor(
|
||||
readonly url: string
|
||||
) { }
|
||||
|
||||
static getFromProduct(): Endpoint | undefined {
|
||||
const logUploaderUrl = product.logUploaderUrl;
|
||||
return logUploaderUrl ? new Endpoint(logUploaderUrl) : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadLogs(
|
||||
launchService: ILaunchService,
|
||||
requestService: IRequestService,
|
||||
environmentService: IEnvironmentService
|
||||
): Promise<any> {
|
||||
const endpoint = Endpoint.getFromProduct();
|
||||
if (!endpoint) {
|
||||
console.error(localize('invalidEndpoint', 'Invalid log uploader endpoint'));
|
||||
return;
|
||||
}
|
||||
|
||||
const logsPath = await launchService.getLogsPath();
|
||||
|
||||
if (await promptUserToConfirmLogUpload(logsPath, environmentService)) {
|
||||
console.log(localize('beginUploading', 'Uploading...'));
|
||||
const outZip = await zipLogs(logsPath);
|
||||
const result = await postLogs(endpoint, outZip, requestService);
|
||||
console.log(localize('didUploadLogs', 'Upload successful! Log file ID: {0}', result.blob_id));
|
||||
}
|
||||
}
|
||||
|
||||
function promptUserToConfirmLogUpload(
|
||||
logsPath: string,
|
||||
environmentService: IEnvironmentService
|
||||
): boolean {
|
||||
const confirmKey = 'iConfirmLogsUpload';
|
||||
if ((environmentService.args['upload-logs'] || '').toLowerCase() === confirmKey.toLowerCase()) {
|
||||
return true;
|
||||
} else {
|
||||
const message = localize('logUploadPromptHeader', 'You are about to upload your session logs to a secure Microsoft endpoint that only Microsoft\'s members of the VS Code team can access.')
|
||||
+ '\n\n' + localize('logUploadPromptBody', 'Session logs may contain personal information such as full paths or file contents. Please review and redact your session log files here: \'{0}\'', logsPath)
|
||||
+ '\n\n' + localize('logUploadPromptBodyDetails', 'By continuing you confirm that you have reviewed and redacted your session log files and that you agree to Microsoft using them to debug VS Code.')
|
||||
+ '\n\n' + localize('logUploadPromptAcceptInstructions', 'Please run code with \'--upload-logs={0}\' to proceed with upload', confirmKey);
|
||||
console.log(message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function postLogs(
|
||||
endpoint: Endpoint,
|
||||
outZip: string,
|
||||
requestService: IRequestService
|
||||
): Promise<PostResult> {
|
||||
const dotter = setInterval(() => console.log('.'), 5000);
|
||||
let result: IRequestContext;
|
||||
try {
|
||||
result = await requestService.request({
|
||||
url: endpoint.url,
|
||||
type: 'POST',
|
||||
data: Buffer.from(fs.readFileSync(outZip)).toString('base64'),
|
||||
headers: {
|
||||
'Content-Type': 'application/zip'
|
||||
}
|
||||
}, CancellationToken.None);
|
||||
} catch (e) {
|
||||
clearInterval(dotter);
|
||||
console.log(localize('postError', 'Error posting logs: {0}', e));
|
||||
throw e;
|
||||
}
|
||||
|
||||
return new Promise<PostResult>((resolve, reject) => {
|
||||
const parts: Buffer[] = [];
|
||||
result.stream.on('data', data => {
|
||||
parts.push(data);
|
||||
});
|
||||
|
||||
result.stream.on('end', () => {
|
||||
clearInterval(dotter);
|
||||
try {
|
||||
const response = Buffer.concat(parts).toString('utf-8');
|
||||
if (result.res.statusCode === 200) {
|
||||
resolve(JSON.parse(response));
|
||||
} else {
|
||||
const errorMessage = localize('responseError', 'Error posting logs. Got {0} — {1}', result.res.statusCode, response);
|
||||
console.log(errorMessage);
|
||||
reject(new Error(errorMessage));
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(localize('parseError', 'Error parsing response'));
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function zipLogs(
|
||||
logsPath: string
|
||||
): Promise<string> {
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vscode-log-upload'));
|
||||
const outZip = path.join(tempDir, 'logs.zip');
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
doZip(logsPath, outZip, tempDir, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.error(localize('zipError', 'Error zipping logs: {0}', err.message));
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(outZip);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function doZip(
|
||||
logsPath: string,
|
||||
outZip: string,
|
||||
tempDir: string,
|
||||
callback: (error: Error, stdout: string, stderr: string) => void
|
||||
) {
|
||||
switch (os.platform()) {
|
||||
case 'win32':
|
||||
// Copy directory first to avoid file locking issues
|
||||
const sub = path.join(tempDir, 'sub');
|
||||
return cp.execFile('powershell', ['-Command',
|
||||
`[System.IO.Directory]::CreateDirectory("${sub}"); Copy-Item -recurse "${logsPath}" "${sub}"; Compress-Archive -Path "${sub}" -DestinationPath "${outZip}"`],
|
||||
{ cwd: logsPath },
|
||||
callback);
|
||||
default:
|
||||
return cp.execFile('zip', ['-r', outZip, '.'], { cwd: logsPath }, callback);
|
||||
}
|
||||
}
|
|
@ -35,7 +35,6 @@ import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
|||
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { IDiagnosticsService, DiagnosticsService } from 'vs/platform/diagnostics/electron-main/diagnosticsService';
|
||||
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
||||
import { uploadLogs } from 'vs/code/electron-main/logUploader';
|
||||
import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
|
||||
import { IThemeMainService, ThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
|
||||
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
|
@ -263,7 +262,7 @@ class CodeMain {
|
|||
// Skip this if we are running with --wait where it is expected that we wait for a while.
|
||||
// Also skip when gathering diagnostics (--status) which can take a longer time.
|
||||
let startupWarningDialogHandle: NodeJS.Timeout | undefined = undefined;
|
||||
if (!environmentService.wait && !environmentService.status && !environmentService.args['upload-logs']) {
|
||||
if (!environmentService.wait && !environmentService.status) {
|
||||
startupWarningDialogHandle = setTimeout(() => {
|
||||
this.showStartupWarningDialog(
|
||||
localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort),
|
||||
|
@ -285,16 +284,6 @@ class CodeMain {
|
|||
});
|
||||
}
|
||||
|
||||
// Log uploader
|
||||
if (typeof environmentService.args['upload-logs'] !== 'undefined') {
|
||||
return instantiationService.invokeFunction(async accessor => {
|
||||
await uploadLogs(launchClient, accessor.get(IRequestService), environmentService);
|
||||
|
||||
throw new ExpectedError();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Windows: allow to set foreground
|
||||
if (platform.isWindows) {
|
||||
await this.windowsAllowSetForegroundWindow(launchClient, logService);
|
||||
|
@ -322,13 +311,6 @@ class CodeMain {
|
|||
throw new ExpectedError('Terminating...');
|
||||
}
|
||||
|
||||
// Log uploader usage info
|
||||
if (typeof environmentService.args['upload-logs'] !== 'undefined') {
|
||||
logService.warn('Warning: The --upload-logs argument can only be used if Code is already running. Please run it again after Code has started.');
|
||||
|
||||
throw new ExpectedError('Terminating...');
|
||||
}
|
||||
|
||||
// dock might be hidden at this case due to a retry
|
||||
if (platform.isMacintosh) {
|
||||
app.dock.show();
|
||||
|
|
|
@ -125,7 +125,7 @@ export async function main(argv: string[]): Promise<any> {
|
|||
|
||||
const processCallbacks: ((child: ChildProcess) => Promise<any>)[] = [];
|
||||
|
||||
const verbose = args.verbose || args.status || typeof args['upload-logs'] !== 'undefined';
|
||||
const verbose = args.verbose || args.status;
|
||||
if (verbose) {
|
||||
env['ELECTRON_ENABLE_LOGGING'] = '1';
|
||||
|
||||
|
@ -350,9 +350,7 @@ export async function main(argv: string[]): Promise<any> {
|
|||
env
|
||||
};
|
||||
|
||||
if (typeof args['upload-logs'] !== 'undefined') {
|
||||
options['stdio'] = ['pipe', 'pipe', 'pipe'];
|
||||
} else if (!verbose) {
|
||||
if (!verbose) {
|
||||
options['stdio'] = 'ignore';
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,6 @@ export interface ParsedArgs {
|
|||
'max-memory'?: string;
|
||||
'file-write'?: boolean;
|
||||
'file-chmod'?: boolean;
|
||||
'upload-logs'?: string;
|
||||
'driver'?: string;
|
||||
'driver-verbose'?: boolean;
|
||||
remote?: string;
|
||||
|
|
|
@ -61,7 +61,6 @@ export const options: Option[] = [
|
|||
{ id: 'inspect-extensions', type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") },
|
||||
{ id: 'inspect-brk-extensions', type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") },
|
||||
{ id: 'disable-gpu', type: 'boolean', cat: 't', description: localize('disableGPU', "Disable GPU hardware acceleration.") },
|
||||
{ id: 'upload-logs', type: 'string', cat: 't', description: localize('uploadLogs', "Uploads logs from current session to a secure endpoint.") },
|
||||
{ id: 'max-memory', type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") },
|
||||
|
||||
{ id: 'remote', type: 'string' },
|
||||
|
|
Loading…
Reference in a new issue