diff --git a/src/vs/platform/remote/common/tunnel.ts b/src/vs/platform/remote/common/tunnel.ts index 2352d2a8a27..0be0c057d96 100644 --- a/src/vs/platform/remote/common/tunnel.ts +++ b/src/vs/platform/remote/common/tunnel.ts @@ -180,7 +180,7 @@ export abstract class AbstractTunnelService implements ITunnelService { } openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded: boolean = false, isPublic: boolean = false): Promise | undefined { - this.logService.trace(`openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`); + this.logService.trace(`ForwardedPorts: (TunnelService) openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`); if (!addressProvider) { return undefined; } @@ -191,20 +191,20 @@ export abstract class AbstractTunnelService implements ITunnelService { const resolvedTunnel = this.retainOrCreateTunnel(addressProvider, remoteHost, remotePort, localPort, elevateIfNeeded, isPublic); if (!resolvedTunnel) { - this.logService.trace(`Tunnel was not created.`); + this.logService.trace(`ForwardedPorts: (TunnelService) Tunnel was not created.`); return resolvedTunnel; } return resolvedTunnel.then(tunnel => { if (!tunnel) { - this.logService.trace('New tunnel is undefined.'); + this.logService.trace('ForwardedPorts: (TunnelService) New tunnel is undefined.'); this.removeEmptyTunnelFromMap(remoteHost!, remotePort); return undefined; } - this.logService.trace('New tunnel established.'); + this.logService.trace('ForwardedPorts: (TunnelService) New tunnel established.'); const newTunnel = this.makeTunnel(tunnel); if (tunnel.tunnelRemoteHost !== remoteHost || tunnel.tunnelRemotePort !== remotePort) { - this.logService.warn('Created tunnel does not match requirements of requested tunnel. Host or port mismatch.'); + this.logService.warn('ForwardedPorts: (TunnelService) Created tunnel does not match requirements of requested tunnel. Host or port mismatch.'); } this._onTunnelOpened.fire(newTunnel); return newTunnel; @@ -219,6 +219,7 @@ export abstract class AbstractTunnelService implements ITunnelService { localAddress: tunnel.localAddress, public: tunnel.public, dispose: async () => { + this.logService.trace(`ForwardedPorts: (TunnelService) dispose request for ${tunnel.tunnelRemotePort} `); const existingHost = this._tunnels.get(tunnel.tunnelRemoteHost); if (existingHost) { const existing = existingHost.get(tunnel.tunnelRemotePort); @@ -233,7 +234,7 @@ export abstract class AbstractTunnelService implements ITunnelService { private async tryDisposeTunnel(remoteHost: string, remotePort: number, tunnel: { refcount: number, readonly value: Promise }): Promise { if (tunnel.refcount <= 0) { - this.logService.trace(`Tunnel is being disposed ${remoteHost}:${remotePort}.`); + this.logService.trace(`ForwardedPorts: (TunnelService) Tunnel is being disposed ${remoteHost}:${remotePort}.`); const disposePromise: Promise = tunnel.value.then(async (tunnel) => { if (tunnel) { await tunnel.dispose(true); @@ -248,6 +249,7 @@ export abstract class AbstractTunnelService implements ITunnelService { } async closeTunnel(remoteHost: string, remotePort: number): Promise { + this.logService.trace(`ForwardedPorts: (TunnelService) close request for ${remotePort} `); const portMap = this._tunnels.get(remoteHost); if (portMap && portMap.has(remotePort)) { const value = portMap.get(remotePort)!; @@ -306,13 +308,13 @@ export abstract class AbstractTunnelService implements ITunnelService { protected abstract retainOrCreateTunnel(addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, isPublic: boolean): Promise | undefined; protected createWithProvider(tunnelProvider: ITunnelProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, isPublic: boolean): Promise | undefined { - this.logService.trace(`Creating tunnel with provider ${remoteHost}:${remotePort} on local port ${localPort}.`); + this.logService.trace(`ForwardedPorts: (TunnelService) Creating tunnel with provider ${remoteHost}:${remotePort} on local port ${localPort}.`); const preferredLocalPort = localPort === undefined ? remotePort : localPort; const creationInfo = { elevationRequired: elevateIfNeeded ? isPortPrivileged(preferredLocalPort) : false }; const tunnelOptions: TunnelOptions = { remoteAddress: { host: remoteHost, port: remotePort }, localAddressPort: localPort, public: isPublic }; const tunnel = tunnelProvider.forwardPort(tunnelOptions, creationInfo); - this.logService.trace('Tunnel created by provider.'); + this.logService.trace('ForwardedPorts: (TunnelService) Tunnel created by provider.'); if (tunnel) { this.addTunnelToMap(remoteHost, remotePort, tunnel); } diff --git a/src/vs/platform/remote/node/tunnelService.ts b/src/vs/platform/remote/node/tunnelService.ts index 80ef45f229e..0f0bb25118a 100644 --- a/src/vs/platform/remote/node/tunnelService.ts +++ b/src/vs/platform/remote/node/tunnelService.ts @@ -150,7 +150,7 @@ export class BaseTunnelService extends AbstractTunnelService { if (this._tunnelProvider) { return this.createWithProvider(this._tunnelProvider, remoteHost, remotePort, localPort, elevateIfNeeded, isPublic); } else { - this.logService.trace(`Creating tunnel without provider ${remoteHost}:${remotePort} on local port ${localPort}.`); + this.logService.trace(`ForwardedPorts: (TunnelService) Creating tunnel without provider ${remoteHost}:${remotePort} on local port ${localPort}.`); const options: IConnectionOptions = { commit: this.productService.commit, socketFactory: this.socketFactory, @@ -161,7 +161,7 @@ export class BaseTunnelService extends AbstractTunnelService { }; const tunnel = createRemoteTunnel(options, remoteHost, remotePort, localPort); - this.logService.trace('Tunnel created without provider.'); + this.logService.trace('ForwardedPorts: (TunnelService) Tunnel created without provider.'); this.addTunnelToMap(remoteHost, remotePort, tunnel); return tunnel; } diff --git a/src/vs/workbench/api/browser/mainThreadTunnelService.ts b/src/vs/workbench/api/browser/mainThreadTunnelService.ts index 5713bf1fddb..e58a00c5f2e 100644 --- a/src/vs/workbench/api/browser/mainThreadTunnelService.ts +++ b/src/vs/workbench/api/browser/mainThreadTunnelService.ts @@ -103,7 +103,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun forwardPort: (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions) => { const forward = this._proxy.$forwardPort(tunnelOptions, tunnelCreationOptions); return forward.then(tunnel => { - this.logService.trace(`MainThreadTunnelService: New tunnel established by tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`); + this.logService.trace(`ForwardedPorts: (MainThreadTunnelService) New tunnel established by tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`); if (!tunnel) { return undefined; } @@ -114,7 +114,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun tunnelLocalPort: typeof tunnel.localAddress !== 'string' ? tunnel.localAddress.port : undefined, public: tunnel.public, dispose: async (silent?: boolean) => { - this.logService.trace(`MainThreadTunnelService: Closing tunnel from tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`); + this.logService.trace(`ForwardedPorts: (MainThreadTunnelService) Closing tunnel from tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`); return this._proxy.$closeTunnel({ host: tunnel.remoteAddress.host, port: tunnel.remoteAddress.port }, silent); } }; diff --git a/src/vs/workbench/api/node/extHostTunnelService.ts b/src/vs/workbench/api/node/extHostTunnelService.ts index 9b9dd79dc9c..4c2be0c2599 100644 --- a/src/vs/workbench/api/node/extHostTunnelService.ts +++ b/src/vs/workbench/api/node/extHostTunnelService.ts @@ -152,6 +152,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe } async openTunnel(extension: IExtensionDescription, forward: TunnelOptions): Promise { + this.logService.trace(`ForwardedPorts: (ExtHostTunnelService) ${extension.identifier} called openTunnel API for ${forward.remoteAddress.port}.`); const tunnel = await this._proxy.$openTunnel(forward, extension.displayName); if (tunnel) { const disposableTunnel: vscode.Tunnel = new ExtensionTunnel(tunnel.remoteAddress, tunnel.localAddress, () => { @@ -184,6 +185,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe while (this._candidateFindingEnabled) { const startTime = new Date().getTime(); const newPorts = await this.findCandidatePorts(); + this.logService.trace(`ForwardedPorts: (ExtHostTunnelService) found candidate ports ${newPorts.map(port => port.port).join(', ')}`); const timeTaken = new Date().getTime() - startTime; movingAverage.update(timeTaken); if (!oldPorts || (JSON.stringify(oldPorts) !== JSON.stringify(newPorts))) { @@ -238,23 +240,26 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe async $forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise { if (this._forwardPortProvider) { try { - this.logService.trace('$forwardPort: Getting tunnel from provider.'); + this.logService.trace('ForwardedPorts: (ExtHostTunnelService) Getting tunnel from provider.'); const providedPort = this._forwardPortProvider(tunnelOptions, tunnelCreationOptions); - this.logService.trace('$forwardPort: Got tunnel promise from provider.'); + this.logService.trace('ForwardedPorts: (ExtHostTunnelService) Got tunnel promise from provider.'); if (providedPort !== undefined) { const tunnel = await providedPort; - this.logService.trace('$forwardPort: Successfully awaited tunnel from provider.'); + this.logService.trace('ForwardedPorts: (ExtHostTunnelService) Successfully awaited tunnel from provider.'); if (!this._extensionTunnels.has(tunnelOptions.remoteAddress.host)) { this._extensionTunnels.set(tunnelOptions.remoteAddress.host, new Map()); } - const disposeListener = this._register(tunnel.onDidDispose(() => this._proxy.$closeTunnel(tunnel.remoteAddress))); + const disposeListener = this._register(tunnel.onDidDispose(() => { + this.logService.trace('ForwardedPorts: (ExtHostTunnelService) Extension fired tunnel\'s onDidDispose.'); + return this._proxy.$closeTunnel(tunnel.remoteAddress); + })); this._extensionTunnels.get(tunnelOptions.remoteAddress.host)!.set(tunnelOptions.remoteAddress.port, { tunnel, disposeListener }); return TunnelDto.fromApiTunnel(tunnel); } else { - this.logService.trace('$forwardPort: Tunnel is undefined'); + this.logService.trace('ForwardedPorts: (ExtHostTunnelService) Tunnel is undefined'); } } catch (e) { - this.logService.trace('$forwardPort: tunnel provider error'); + this.logService.trace('ForwardedPorts: (ExtHostTunnelService) tunnel provider error'); } } return undefined; @@ -262,7 +267,9 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe async $applyCandidateFilter(candidates: CandidatePort[]): Promise { const filter = await Promise.all(candidates.map(candidate => this._showCandidatePort(candidate.host, candidate.port, candidate.detail))); - return candidates.filter((candidate, index) => filter[index]); + const result = candidates.filter((candidate, index) => filter[index]); + this.logService.trace(`ForwardedPorts: (ExtHostTunnelService) filtered from ${candidates.map(port => port.port).join(', ')} to ${result.map(port => port.port).join(', ')}`); + return result; } async findCandidatePorts(): Promise { diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts index 39fe22bfbd4..717528fa2df 100644 --- a/src/vs/workbench/services/remote/common/remoteExplorerService.ts +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -18,6 +18,7 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { isNumber, isObject, isString } from 'vs/base/common/types'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { hash } from 'vs/base/common/hash'; +import { ILogService } from 'vs/platform/log/common/log'; export const IRemoteExplorerService = createDecorator('remoteExplorerService'); export const REMOTE_EXPLORER_TYPE_KEY: string = 'remote.explorerType'; @@ -269,7 +270,8 @@ export class TunnelModel extends Disposable { @IConfigurationService private readonly configurationService: IConfigurationService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IRemoteAuthorityResolverService private readonly remoteAuthorityResolverService: IRemoteAuthorityResolverService, - @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, + @ILogService private readonly logService: ILogService ) { super(); this.portsAttributes = new PortsAttributes(configurationService); @@ -355,6 +357,7 @@ export class TunnelModel extends Disposable { const tunnelRestoreValue = await this.tunnelRestoreValue; if (tunnelRestoreValue) { const tunnels = JSON.parse(tunnelRestoreValue) ?? []; + this.logService.trace(`ForwardedPorts: (TunnelModel) restoring ports ${tunnels.map(tunnel => tunnel.remotePort).join(', ')}`); for (let tunnel of tunnels) { if (!mapHasAddressLocalhostOrAllInterfaces(this.detected, tunnel.remoteHost, tunnel.remotePort)) { await this.forward({ host: tunnel.remoteHost, port: tunnel.remotePort }, tunnel.localPort, tunnel.name, undefined, undefined, tunnel.privacy === TunnelPrivacy.Public); @@ -482,6 +485,7 @@ export class TunnelModel extends Disposable { processedCandidates = await this._candidateFilter(candidates); } const removedCandidates = this.updateInResponseToCandidates(processedCandidates); + this.logService.trace(`ForwardedPorts: (TunnelModel) removed candidates ${Array.from(removedCandidates.values()).map(candidate => candidate.port).join(', ')}`); this._onCandidatesChanged.fire(removedCandidates); } @@ -592,9 +596,10 @@ class RemoteExplorerService implements IRemoteExplorerService { @IConfigurationService configurationService: IConfigurationService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, - @IWorkspaceContextService workspaceContextService: IWorkspaceContextService + @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, + @ILogService logService: ILogService ) { - this._tunnelModel = new TunnelModel(tunnelService, storageService, configurationService, environmentService, remoteAuthorityResolverService, workspaceContextService); + this._tunnelModel = new TunnelModel(tunnelService, storageService, configurationService, environmentService, remoteAuthorityResolverService, workspaceContextService, logService); } set targetType(name: string[]) {