implement log api feedback (#161343)

This commit is contained in:
Sandeep Somavarapu
2022-09-20 15:33:54 -07:00
committed by GitHub
parent 8550d02362
commit 725207d6d4
2 changed files with 78 additions and 160 deletions
+67 -79
View File
@@ -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; }
@@ -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);
@@ -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);
}
}
@@ -121,6 +105,7 @@ 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>();
@@ -128,7 +113,7 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
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,
@@ -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 {
@@ -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));
channelPromise.then(channel => channel.info(value, ...args));
},
trace(value: string): void {
debug(value: string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.info(value));
channelPromise.then(channel => channel.debug(value, ...args));
},
debug(value: string): void {
info(value: string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.debug(value));
channelPromise.then(channel => channel.info(value, ...args));
},
info(value: string): void {
warn(value: string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.info(value));
channelPromise.then(channel => channel.warn(value, ...args));
},
warn(value: string): void {
error(value: Error | string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.warn(value));
},
error(value: Error | string): void {
validate();
channelPromise.then(channel => channel.error(value));
},
show(preserveFocus?: boolean): 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;
+11 -81
View File
@@ -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 {