Skip to content

Commit

Permalink
implement log api feedback (#161343)
Browse files Browse the repository at this point in the history
  • Loading branch information
sandy081 committed Sep 20, 2022
1 parent 8550d02 commit 725207d
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 160 deletions.
146 changes: 67 additions & 79 deletions src/vs/workbench/api/common/extHostOutput.ts
Expand Up @@ -17,8 +17,11 @@ import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSyste
import { toLocalISOString } from 'vs/base/common/date';
import { VSBuffer } from 'vs/base/common/buffer';
import { isString } from 'vs/base/common/types';
import { FileSystemProviderErrorCode, toFileSystemProviderErrorCode } from 'vs/platform/files/common/files';

export class ExtHostLogOutputChannel extends AbstractMessageLogger implements vscode.LogOutputChannel {
class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOutputChannel {

private offset: number = 0;

private _disposed: boolean = false;
get disposed(): boolean { return this._disposed; }
Expand All @@ -35,51 +38,11 @@ export class ExtHostLogOutputChannel extends AbstractMessageLogger implements vs
}

appendLine(value: string): void {
this.info(value);
}

show(preserveFocus?: boolean): void {
this.proxy.$reveal(this.id, !!preserveFocus);
}

hide(): void {
this.proxy.$close(this.id);
}

protected log(level: LogLevel, message: string): void {
log(this.logger, level, message);
}

override dispose(): void {
super.dispose();

if (!this._disposed) {
this.proxy.$dispose(this.id);
this._disposed = true;
}
}

}

export class ExtHostOutputChannel extends ExtHostLogOutputChannel implements vscode.OutputChannel {

private offset: number = 0;

constructor(
id: string, name: string,
logger: ILogger,
proxy: MainThreadOutputServiceShape,
extension: IExtensionDescription
) {
super(id, name, logger, proxy, extension);
}

override appendLine(value: string): void {
this.append(value + '\n');
}

append(value: string): void {
this.write(value);
this.info(value);
if (this.visible) {
this.logger.flush();
this.proxy.$update(this.id, OutputChannelUpdateMode.Append);
Expand All @@ -94,21 +57,42 @@ export class ExtHostOutputChannel extends ExtHostLogOutputChannel implements vsc

replace(value: string): void {
const till = this.offset;
this.write(value);
this.info(value);
this.proxy.$update(this.id, OutputChannelUpdateMode.Replace, till);
if (this.visible) {
this.logger.flush();
}
}

override show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
this.logger.flush();
super.show(!!(typeof columnOrPreserveFocus === 'boolean' ? columnOrPreserveFocus : preserveFocus));
this.proxy.$reveal(this.id, !!(typeof columnOrPreserveFocus === 'boolean' ? columnOrPreserveFocus : preserveFocus));
}

private write(value: string): void {
this.offset += VSBuffer.fromString(value).byteLength;
this.logger.info(value);
hide(): void {
this.proxy.$close(this.id);
}

protected log(level: LogLevel, message: string): void {
this.offset += VSBuffer.fromString(message).byteLength;
log(this.logger, level, message);
}

override dispose(): void {
super.dispose();

if (!this._disposed) {
this.proxy.$dispose(this.id);
this._disposed = true;
}
}

}

class ExtHostLogOutputChannel extends ExtHostOutputChannel {

override appendLine(value: string): void {
this.append(value);
}

}
Expand All @@ -121,14 +105,15 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {

private readonly outputsLocation: URI;
private outputDirectoryPromise: Thenable<URI> | undefined;
private readonly extensionLogDirectoryPromise = new Map<string, Thenable<URI>>();
private namePool: number = 1;

private readonly channels = new Map<string, ExtHostLogOutputChannel | ExtHostOutputChannel>();
private visibleChannelId: string | null = null;

constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostInitDataService initData: IExtHostInitDataService,
@IExtHostInitDataService private readonly initData: IExtHostInitDataService,
@IExtHostConsumerFileSystem private readonly extHostFileSystem: IExtHostConsumerFileSystem,
@IExtHostFileSystemInfo private readonly extHostFileSystemInfo: IExtHostFileSystemInfo,
@ILoggerService private readonly loggerService: ILoggerService,
Expand Down Expand Up @@ -163,25 +148,40 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
}

private async doCreateOutputChannel(name: string, languageId: string | undefined, extension: IExtensionDescription): Promise<ExtHostOutputChannel> {
const file = await this.createLogFile(name);
if (!this.outputDirectoryPromise) {
this.outputDirectoryPromise = this.extHostFileSystem.value.createDirectory(this.outputsLocation).then(() => this.outputsLocation);
}
const outputDir = await this.outputDirectoryPromise;
const file = this.extHostFileSystemInfo.extUri.joinPath(outputDir, `${this.namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`);
const logger = this.loggerService.createLogger(file, { always: true, donotRotate: true, donotUseFormatters: true });
const id = await this.proxy.$register(name, file, false, languageId, extension.identifier.value);
return new ExtHostOutputChannel(id, name, logger, this.proxy, extension);
}

private async doCreateLogOutputChannel(name: string, extension: IExtensionDescription): Promise<ExtHostLogOutputChannel> {
const file = await this.createLogFile(name);
const extensionLogDir = await this.createExtensionLogDirectory(extension);
const file = this.extHostFileSystemInfo.extUri.joinPath(extensionLogDir, `${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`);
const logger = this.loggerService.createLogger(file, { name });
const id = await this.proxy.$register(name, file, true, undefined, extension.identifier.value);
return new ExtHostLogOutputChannel(id, name, logger, this.proxy, extension);
}

private async createLogFile(name: string): Promise<URI> {
if (!this.outputDirectoryPromise) {
this.outputDirectoryPromise = this.extHostFileSystem.value.createDirectory(this.outputsLocation).then(() => this.outputsLocation);
private createExtensionLogDirectory(extension: IExtensionDescription): Thenable<URI> {
let extensionLogDirectoryPromise = this.extensionLogDirectoryPromise.get(extension.identifier.value);
if (!extensionLogDirectoryPromise) {
const extensionLogDirectory = this.extHostFileSystemInfo.extUri.joinPath(this.initData.logsLocation, extension.identifier.value);
this.extensionLogDirectoryPromise.set(extension.identifier.value, extensionLogDirectoryPromise = (async () => {
try {
await this.extHostFileSystem.value.createDirectory(extensionLogDirectory);
} catch (err) {
if (toFileSystemProviderErrorCode(err) !== FileSystemProviderErrorCode.FileExists) {
throw err;
}
}
return extensionLogDirectory;
})());
}
const outputDir = await this.outputDirectoryPromise;
return this.extHostFileSystemInfo.extUri.joinPath(outputDir, `${this.namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`);
return extensionLogDirectoryPromise;
}

private createExtHostOutputChannel(name: string, channelPromise: Promise<ExtHostOutputChannel>): vscode.OutputChannel {
Expand Down Expand Up @@ -232,38 +232,26 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
}
};
return {
get name(): string { return name; },
appendLine(value: string): void {
...this.createExtHostOutputChannel(name, channelPromise),
trace(value: string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.appendLine(value));
},
trace(value: string): void {
validate();
channelPromise.then(channel => channel.info(value));
},
debug(value: string): void {
validate();
channelPromise.then(channel => channel.debug(value));
channelPromise.then(channel => channel.info(value, ...args));
},
info(value: string): void {
debug(value: string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.info(value));
channelPromise.then(channel => channel.debug(value, ...args));
},
warn(value: string): void {
info(value: string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.warn(value));
channelPromise.then(channel => channel.info(value, ...args));
},
error(value: Error | string): void {
warn(value: string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.error(value));
channelPromise.then(channel => channel.warn(value, ...args));
},
show(preserveFocus?: boolean): void {
error(value: Error | string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.show(preserveFocus));
},
hide(): void {
validate();
channelPromise.then(channel => channel.hide());
channelPromise.then(channel => channel.error(value, ...args));
},
dispose(): void {
disposed = true;
Expand Down
92 changes: 11 additions & 81 deletions src/vscode-dts/vscode.proposed.extensionLog.d.ts
Expand Up @@ -5,120 +5,50 @@

declare module 'vscode' {

export interface AbstractOutputChannel {
/**
* The human-readable name of this output channel.
*/
readonly name: string;

/**
* Append the given value and a line feed character
* to the channel.
*
* @param value A string, falsy values will be printed.
*/
appendLine(value: string): void;

/**
* Reveal this channel in the UI.
*
* @param preserveFocus When `true` the channel will not take focus.
*/
show(preserveFocus?: boolean): void;

/**
* Hide this channel from the UI.
*/
hide(): void;

/**
* Dispose and free associated resources.
*/
dispose(): void;
}

/**
* An output channel is a container for readonly textual information.
*
* To get an instance of an `OutputChannel` use
* {@link window.createOutputChannel createOutputChannel}.
*/
export interface OutputChannel extends AbstractOutputChannel {

/**
* Append the given value to the channel.
*
* @param value A string, falsy values will not be printed.
*/
append(value: string): void;

/**
* Replaces all output from the channel with the given value.
*
* @param value A string, falsy values will not be printed.
*/
replace(value: string): void;

/**
* Removes all output from the channel.
*/
clear(): void;

/**
* Reveal this channel in the UI.
*
* @deprecated Use the overload with just one parameter (`show(preserveFocus?: boolean): void`).
*
* @param column This argument is **deprecated** and will be ignored.
* @param preserveFocus When `true` the channel will not take focus.
*/
show(column?: ViewColumn, preserveFocus?: boolean): void;
}

/**
* A channel for containing log output.
*/
export interface LogOutputChannel extends AbstractOutputChannel {
export interface LogOutputChannel extends OutputChannel {
/**
* Log the given trace message to the channel.
*
* Messages are only printed when the user has enabled trace logging for the extension.
* Messages are only printed when the user has enabled trace logging.
*
* @param message trace message to log
*/
trace(message: string): void;
trace(message: string, ...args: any[]): void;
/**
* Log the given debug message to the channel.
*
* Messages are only printed when the user has enabled debug logging for the extension.
* Messages are only printed when the user has enabled debug logging.
*
* @param message debug message to log
*/
debug(message: string): void;
debug(message: string, ...args: any[]): void;
/**
* Log the given info message to the channel.
*
* Messages are only printed when the user has enabled info logging for the extension.
* Messages are only printed when the user has enabled info logging.
*
* @param message info message to log
*/
info(message: string): void;
info(message: string, ...args: any[]): void;
/**
* Log the given warning message to the channel.
*
* Messages are only printed when the user has enabled warn logging for the extension.
* Messages are only printed when the user has enabled warn logging.
*
* @param message warning message to log
*/
warn(message: string): void;
warn(message: string, ...args: any[]): void;
/**
* Log the given error or error message to the channel.
*
* Messages are only printed when the user has enabled error logging for the extension.
* Messages are only printed when the user has enabled error logging.
*
* @param error Error or error message to log
*/
error(error: string | Error): void;
error(error: string | Error, ...args: any[]): void;
}

export namespace window {
Expand Down

0 comments on commit 725207d

Please sign in to comment.