Skip to content

Commit

Permalink
Fix open ts server log command on web (#172885)
Browse files Browse the repository at this point in the history
Fixes #172853
  • Loading branch information
mjbvz committed Jan 31, 2023
1 parent c18f80a commit 855dd78
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ import { createLazyClientHost, lazilyActivateClient } from './lazyClientHost';
import RemoteRepositories from './remoteRepositories.browser';
import { noopRequestCancellerFactory } from './tsServer/cancellation';
import { noopLogDirectoryProvider } from './tsServer/logDirectoryProvider';
import { WorkerServerProcess } from './tsServer/serverProcess.browser';
import { WorkerServerProcessFactory } from './tsServer/serverProcess.browser';
import { ITypeScriptVersionProvider, TypeScriptVersion, TypeScriptVersionSource } from './tsServer/versionProvider';
import { ActiveJsTsEditorTracker } from './utils/activeJsTsEditorTracker';
import API from './utils/api';
import { TypeScriptServiceConfiguration } from './utils/configuration';
import { BrowserServiceConfigurationProvider } from './utils/configuration.browser';
import { getPackageInfo } from './utils/packageInfo';
import { PluginManager } from './utils/plugins';
import { Logger } from './utils/logger';
import { getPackageInfo } from './utils/packageInfo';
import { isWebAndHasSharedArrayBuffers } from './utils/platform';
import { PluginManager } from './utils/plugins';

class StaticVersionProvider implements ITypeScriptVersionProvider {

Expand Down Expand Up @@ -78,7 +78,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {
logDirectoryProvider: noopLogDirectoryProvider,
cancellerFactory: noopRequestCancellerFactory,
versionProvider,
processFactory: WorkerServerProcess,
processFactory: new WorkerServerProcessFactory(context.extensionUri),
activeJsTsEditorTracker,
serviceConfigurationProvider: new BrowserServiceConfigurationProvider(),
experimentTelemetryReporter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'mocha';
import * as stream from 'stream';
import type * as Proto from '../../protocol';
import { NodeRequestCanceller } from '../../tsServer/cancellation.electron';
import { ProcessBasedTsServer, TsServerProcess } from '../../tsServer/server';
import { SingleTsServer, TsServerProcess } from '../../tsServer/server';
import { ServerType } from '../../typescriptService';
import { nulToken } from '../../utils/cancellation';
import { Logger } from '../../utils/logger';
Expand Down Expand Up @@ -65,7 +65,7 @@ suite.skip('Server', () => {

test('should send requests with increasing sequence numbers', async () => {
const process = new FakeServerProcess();
const server = new ProcessBasedTsServer('semantic', ServerType.Semantic, process, undefined, new NodeRequestCanceller('semantic', tracer), undefined!, NoopTelemetryReporter, tracer);
const server = new SingleTsServer('semantic', ServerType.Semantic, process, undefined, new NodeRequestCanceller('semantic', tracer), undefined!, NoopTelemetryReporter, tracer);

const onWrite1 = process.onWrite();
server.executeImpl('geterr', {}, { isAsync: false, token: nulToken, expectsResult: true });
Expand Down
22 changes: 13 additions & 9 deletions extensions/typescript-language-features/src/tsServer/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ export interface TypeScriptServerExitEvent {
readonly signal: string | null;
}

export type TsServerLog =
{ readonly type: 'file'; readonly uri: vscode.Uri } |
{ readonly type: 'output'; readonly output: vscode.OutputChannel };

export interface ITypeScriptServer {
readonly onEvent: vscode.Event<Proto.Event>;
readonly onExit: vscode.Event<TypeScriptServerExitEvent>;
readonly onError: vscode.Event<any>;

readonly tsServerLogFile: vscode.Uri | undefined;
readonly tsServerLog: TsServerLog | undefined;

kill(): void;

Expand Down Expand Up @@ -66,7 +70,7 @@ export interface TsServerProcessFactory {
kind: TsServerProcessKind,
configuration: TypeScriptServiceConfiguration,
versionManager: TypeScriptVersionManager,
extensionUri: vscode.Uri,
tsServerLog: TsServerLog | undefined,
): TsServerProcess;
}

Expand All @@ -80,7 +84,7 @@ export interface TsServerProcess {
kill(): void;
}

export class ProcessBasedTsServer extends Disposable implements ITypeScriptServer {
export class SingleTsServer extends Disposable implements ITypeScriptServer {
private readonly _requestQueue = new RequestQueue();
private readonly _callbacks = new CallbackMap<Proto.Response>();
private readonly _pendingResponses = new Set<number>();
Expand All @@ -89,7 +93,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe
private readonly _serverId: string,
private readonly _serverSource: ServerType,
private readonly _process: TsServerProcess,
private readonly _tsServerLogFile: vscode.Uri | undefined,
private readonly _tsServerLog: TsServerLog | undefined,
private readonly _requestCanceller: OngoingRequestCanceller,
private readonly _version: TypeScriptVersion,
private readonly _telemetryReporter: TelemetryReporter,
Expand Down Expand Up @@ -121,7 +125,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe
private readonly _onError = this._register(new vscode.EventEmitter<any>());
public readonly onError = this._onError.event;

public get tsServerLogFile() { return this._tsServerLogFile; }
public get tsServerLog() { return this._tsServerLog; }

private write(serverRequest: Proto.Request) {
this._process.write(serverRequest);
Expand Down Expand Up @@ -215,7 +219,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe
request,
expectsResponse: executeInfo.expectsResult,
isAsync: executeInfo.isAsync,
queueingType: ProcessBasedTsServer.getQueueingType(command, executeInfo.lowPriority)
queueingType: SingleTsServer.getQueueingType(command, executeInfo.lowPriority)
};
let result: Promise<ServerResponse.Response<Proto.Response>> | undefined;
if (executeInfo.expectsResult) {
Expand Down Expand Up @@ -304,7 +308,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe
command: string,
lowPriority?: boolean
): RequestQueueingType {
if (ProcessBasedTsServer.fenceCommands.has(command)) {
if (SingleTsServer.fenceCommands.has(command)) {
return RequestQueueingType.Fence;
}
return lowPriority ? RequestQueueingType.LowPriority : RequestQueueingType.Normal;
Expand Down Expand Up @@ -465,7 +469,7 @@ export class GetErrRoutingTsServer extends Disposable implements ITypeScriptServ
private readonly _onError = this._register(new vscode.EventEmitter<any>());
public readonly onError = this._onError.event;

public get tsServerLogFile() { return this.mainServer.tsServerLogFile; }
public get tsServerLog() { return this.mainServer.tsServerLog; }

public kill(): void {
this.getErrServer.kill();
Expand Down Expand Up @@ -605,7 +609,7 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ
private readonly _onError = this._register(new vscode.EventEmitter<any>());
public readonly onError = this._onError.event;

public get tsServerLogFile() { return this.semanticServer.tsServerLogFile; }
public get tsServerLog() { return this.semanticServer.tsServerLog; }

public kill(): void {
this.syntaxServer.kill();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference lib='webworker' />
import { ServiceConnection } from '@vscode/sync-api-common/browser';
import { ApiService, Requests } from '@vscode/sync-api-service';
import * as vscode from 'vscode';
import type * as Proto from '../protocol';
import { TypeScriptServiceConfiguration } from '../utils/configuration';
import { memoize } from '../utils/memoize';
import { TsServerProcess, TsServerProcessKind } from './server';
import { TypeScriptVersion } from './versionProvider';
import { ServiceConnection } from '@vscode/sync-api-common/browser';
import { Requests, ApiService } from '@vscode/sync-api-service';
import { TypeScriptVersionManager } from './versionManager';
import { FileWatcherManager } from './fileWatchingManager';
import { TsServerLog, TsServerProcess, TsServerProcessFactory, TsServerProcessKind } from './server';
import { TypeScriptVersionManager } from './versionManager';
import { TypeScriptVersion } from './versionProvider';

type BrowserWatchEvent = {
type: 'watchDirectory' | 'watchFile';
Expand All @@ -28,29 +27,31 @@ type BrowserWatchEvent = {
id: number;
};

export class WorkerServerProcess implements TsServerProcess {
@memoize
private static get tsServerlogOutputChannel(): vscode.OutputChannel {
return vscode.window.createOutputChannel(vscode.l10n.t("TypeScript Server Log"));
}
export class WorkerServerProcessFactory implements TsServerProcessFactory {
constructor(
private readonly _extensionUri: vscode.Uri,
) { }

public static fork(
public fork(
version: TypeScriptVersion,
args: readonly string[],
kind: TsServerProcessKind,
_configuration: TypeScriptServiceConfiguration,
_versionManager: TypeScriptVersionManager,
extensionUri: vscode.Uri,
tsServerLog: TsServerLog | undefined,
) {
const tsServerPath = version.tsServerPath;
return new WorkerServerProcess(kind, tsServerPath, extensionUri, [
return new WorkerServerProcess(kind, tsServerPath, this._extensionUri, [
...args,

// Explicitly give TS Server its path so it can
// load local resources
'--executingFilePath', tsServerPath,
]);
], tsServerLog);
}
}

class WorkerServerProcess implements TsServerProcess {

private static idPool = 0;

Expand All @@ -75,6 +76,7 @@ export class WorkerServerProcess implements TsServerProcess {
tsServerPath: string,
extensionUri: vscode.Uri,
args: readonly string[],
private readonly tsServerLog: TsServerLog | undefined,
) {
this.worker = new Worker(tsServerPath, { name: `TS ${kind} server #${this.id}` });

Expand Down Expand Up @@ -167,7 +169,9 @@ export class WorkerServerProcess implements TsServerProcess {
}

private appendLog(msg: string) {
WorkerServerProcess.tsServerlogOutputChannel.appendLine(`(${this.id} - ${this.kind}) ${msg}`);
if (this.tsServerLog?.type === 'output') {
this.tsServerLog.output.appendLine(`(${this.id} - ${this.kind}) ${msg}`);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type * as Proto from '../protocol';
import API from '../utils/api';
import { TypeScriptServiceConfiguration } from '../utils/configuration';
import { Disposable } from '../utils/dispose';
import { TsServerProcess, TsServerProcessFactory, TsServerProcessKind } from './server';
import { TsServerLog, TsServerProcess, TsServerProcessFactory, TsServerProcessKind } from './server';
import { TypeScriptVersionManager } from './versionManager';
import { TypeScriptVersion } from './versionProvider';

Expand Down Expand Up @@ -253,6 +253,7 @@ export class ElectronServiceProcessFactory implements TsServerProcessFactory {
kind: TsServerProcessKind,
configuration: TypeScriptServiceConfiguration,
versionManager: TypeScriptVersionManager,
_tsserverLog: TsServerLog | undefined,
): TsServerProcess {
let tsServerPath = version.tsServerPath;

Expand Down
40 changes: 25 additions & 15 deletions extensions/typescript-language-features/src/tsServer/spawner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import { PluginManager } from '../utils/plugins';
import { TelemetryReporter } from '../utils/telemetry';
import Tracer from '../utils/tracer';
import { ILogDirectoryProvider } from './logDirectoryProvider';
import { GetErrRoutingTsServer, ITypeScriptServer, ProcessBasedTsServer, SyntaxRoutingTsServer, TsServerDelegate, TsServerProcessFactory, TsServerProcessKind } from './server';
import { GetErrRoutingTsServer, ITypeScriptServer, SingleTsServer, SyntaxRoutingTsServer, TsServerDelegate, TsServerLog, TsServerProcessFactory, TsServerProcessKind } from './server';
import { TypeScriptVersionManager } from './versionManager';
import { ITypeScriptVersionProvider, TypeScriptVersion } from './versionProvider';
import { memoize } from '../utils/memoize';

const enum CompositeServerType {
/** Run a single server that handles all commands */
Expand All @@ -34,6 +35,12 @@ const enum CompositeServerType {
}

export class TypeScriptServerSpawner {

@memoize
public static get tsServerLogOutputChannel(): vscode.OutputChannel {
return vscode.window.createOutputChannel(vscode.l10n.t("TypeScript Server Log"));
}

public constructor(
private readonly _versionProvider: ITypeScriptVersionProvider,
private readonly _versionManager: TypeScriptVersionManager,
Expand All @@ -43,7 +50,6 @@ export class TypeScriptServerSpawner {
private readonly _telemetryReporter: TelemetryReporter,
private readonly _tracer: Tracer,
private readonly _factory: TsServerProcessFactory,
private readonly _extensionUri: vscode.Uri,
) { }

public spawn(
Expand Down Expand Up @@ -133,13 +139,15 @@ export class TypeScriptServerSpawner {
const apiVersion = version.apiVersion || API.defaultVersion;

const canceller = cancellerFactory.create(kind, this._tracer);
const { args, tsServerLogFile, tsServerTraceDirectory } = this.getTsServerArgs(kind, configuration, version, apiVersion, pluginManager, canceller.cancellationPipeName);
const { args, tsServerLog, tsServerTraceDirectory } = this.getTsServerArgs(kind, configuration, version, apiVersion, pluginManager, canceller.cancellationPipeName);

if (TypeScriptServerSpawner.isLoggingEnabled(configuration)) {
if (tsServerLogFile) {
this._logger.info(`<${kind}> Log file: ${tsServerLogFile}`);
} else {
this._logger.error(`<${kind}> Could not create log directory`);
if (!isWeb()) {
if (tsServerLog) {
this._logger.info(`<${kind}> Log file: ${tsServerLog}`);
} else {
this._logger.error(`<${kind}> Could not create log directory`);
}
}
}

Expand All @@ -152,14 +160,14 @@ export class TypeScriptServerSpawner {
}

this._logger.info(`<${kind}> Forking...`);
const process = this._factory.fork(version, args, kind, configuration, this._versionManager, this._extensionUri);
const process = this._factory.fork(version, args, kind, configuration, this._versionManager, tsServerLog);
this._logger.info(`<${kind}> Starting...`);

return new ProcessBasedTsServer(
return new SingleTsServer(
kind,
this.kindToServerType(kind),
process!,
tsServerLogFile,
tsServerLog,
canceller,
version,
this._telemetryReporter,
Expand All @@ -186,9 +194,9 @@ export class TypeScriptServerSpawner {
apiVersion: API,
pluginManager: PluginManager,
cancellationPipeName: string | undefined,
): { args: string[]; tsServerLogFile: vscode.Uri | undefined; tsServerTraceDirectory: vscode.Uri | undefined } {
): { args: string[]; tsServerLog: TsServerLog | undefined; tsServerTraceDirectory: vscode.Uri | undefined } {
const args: string[] = [];
let tsServerLogFile: vscode.Uri | undefined;
let tsServerLog: TsServerLog | undefined;
let tsServerTraceDirectory: vscode.Uri | undefined;

if (kind === TsServerProcessKind.Syntax) {
Expand Down Expand Up @@ -216,13 +224,15 @@ export class TypeScriptServerSpawner {
if (TypeScriptServerSpawner.isLoggingEnabled(configuration)) {
if (isWeb()) {
args.push('--logVerbosity', TsServerLogLevel.toString(configuration.tsServerLogLevel));
tsServerLog = { type: 'output', output: TypeScriptServerSpawner.tsServerLogOutputChannel };
} else {
const logDir = this._logDirectoryProvider.getNewLogDirectory();
if (logDir) {
tsServerLogFile = vscode.Uri.joinPath(logDir, `tsserver.log`);
const logFilePath = vscode.Uri.joinPath(logDir, `tsserver.log`);
tsServerLog = { type: 'file', uri: logFilePath };

args.push('--logVerbosity', TsServerLogLevel.toString(configuration.tsServerLogLevel));
args.push('--logFile', tsServerLogFile.path);
args.push('--logFile', logFilePath.path);
}
}
}
Expand Down Expand Up @@ -265,7 +275,7 @@ export class TypeScriptServerSpawner {
args.push('--enableProjectWideIntelliSenseOnWeb');
}

return { args, tsServerLogFile, tsServerTraceDirectory };
return { args, tsServerLog: tsServerLog, tsServerTraceDirectory };
}

private static isLoggingEnabled(configuration: TypeScriptServiceConfiguration) {
Expand Down

0 comments on commit 855dd78

Please sign in to comment.