Re-use LogLevel enum from VS Code API (#15645)

* Re-use LogLevel enum from VS Code API

* Fix formatting

* Fix errors
This commit is contained in:
Don Jayamanne 2024-05-02 17:22:57 +10:00 коммит произвёл GitHub
Родитель e85320600d
Коммит f6e4b43295
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
22 изменённых файлов: 168 добавлений и 230 удалений

Просмотреть файл

@ -1479,14 +1479,13 @@
},
"jupyter.logging.level": {
"type": "string",
"default": "debug",
"default": "info",
"enum": [
"off",
"error",
"warn",
"info",
"debug",
"verbose"
"debug"
],
"description": "%jupyter.configuration.jupyter.logging.level.description%"
},

Просмотреть файл

@ -14,32 +14,41 @@ import {
type Memento,
type Disposable,
type ProgressOptions,
ProgressLocation
ProgressLocation,
commands
} from 'vscode';
import {
STANDARD_OUTPUT_CHANNEL,
JUPYTER_OUTPUT_CHANNEL,
PylanceExtension,
PythonExtension
PythonExtension,
Telemetry
} from './platform/common/constants';
import { getDisplayPath } from './platform/common/platform/fs-paths';
import {
GLOBAL_MEMENTO,
IConfigurationService,
IDisposableRegistry,
IExperimentService,
IExtensionContext,
IFeaturesManager,
IMemento,
IOutputChannel,
WORKSPACE_MEMENTO
} from './platform/common/types';
import { Common, OutputChannelNames } from './platform/common/utils/localize';
import { IServiceContainer, IServiceManager } from './platform/ioc/types';
import { registerLogger, traceError } from './platform/logging';
import { registerLogger, setLoggingLevel, traceError } from './platform/logging';
import { OutputChannelLogger } from './platform/logging/outputChannelLogger';
import { getJupyterOutputChannel } from './standalone/devTools/jupyterOutputChannel';
import { isUsingPylance } from './standalone/intellisense/notebookPythonPathService';
import { noop } from './platform/common/utils/misc';
import { sendErrorTelemetry } from './platform/telemetry/startupTelemetry';
import { createDeferred } from './platform/common/utils/async';
import { StopWatch } from './platform/common/utils/stopWatch';
import { sendTelemetryEvent } from './telemetry';
import { IExtensionActivationManager } from './platform/activation/types';
import { getVSCodeChannel } from './platform/common/application/applicationEnvironment';
export function addOutputChannel(
context: IExtensionContext,
@ -143,3 +152,38 @@ function notifyUser(msg: string) {
traceError('failed to notify user', ex);
}
}
export async function postActivateLegacy(
context: IExtensionContext,
serviceManager: IServiceManager,
serviceContainer: IServiceContainer
) {
// Load the two data science experiments that we need to register types
// Await here to keep the register method sync
const experimentService = serviceContainer.get<IExperimentService>(IExperimentService);
// This must be done first, this guarantees all experiment information has loaded & all telemetry will contain experiment info.
const stopWatch = new StopWatch();
await experimentService.activate();
const duration = stopWatch.elapsedTime;
sendTelemetryEvent(Telemetry.ExperimentLoad, { duration });
const configuration = serviceManager.get<IConfigurationService>(IConfigurationService);
// We should start logging using the log level as soon as possible, so set it as soon as we can access the level.
// `IConfigurationService` may depend any of the registered types, so doing it after all registrations are finished.
// XXX Move this *after* abExperiments is activated?
const settings = configuration.getSettings();
setLoggingLevel(settings.logging.level, settings.logging.widgets);
context.subscriptions.push(
settings.onDidChange(() => setLoggingLevel(settings.logging.level, settings.logging.widgets))
);
// "initialize" "services"
commands.executeCommand('setContext', 'jupyter.vscode.channel', getVSCodeChannel()).then(noop, noop);
// "activate" everything else
serviceContainer.get<IExtensionActivationManager>(IExtensionActivationManager).activate();
const featureManager = serviceContainer.get<IFeaturesManager>(IFeaturesManager);
featureManager.initialize();
context.subscriptions.push(featureManager);
}

Просмотреть файл

@ -38,14 +38,7 @@ import './platform/logging';
import { commands, env, ExtensionMode, UIKind, workspace } from 'vscode';
import { buildApi, IExtensionApi } from './standalone/api';
import { setHomeDirectory, traceError } from './platform/logging';
import {
IAsyncDisposableRegistry,
IConfigurationService,
IExperimentService,
IExtensionContext,
IFeaturesManager,
IsDevMode
} from './platform/common/types';
import { IAsyncDisposableRegistry, IExtensionContext, IsDevMode } from './platform/common/types';
import { IServiceContainer, IServiceManager } from './platform/ioc/types';
import { sendStartupTelemetry } from './platform/telemetry/startupTelemetry';
import { noop } from './platform/common/utils/misc';
@ -55,16 +48,8 @@ import { registerTypes as registerNotebookTypes } from './notebooks/serviceRegis
import { registerTypes as registerInteractiveTypes } from './interactive-window/serviceRegistry.node';
import { registerTypes as registerStandaloneTypes } from './standalone/serviceRegistry.node';
import { registerTypes as registerWebviewTypes } from './webviews/extension-side/serviceRegistry.node';
import { IExtensionActivationManager } from './platform/activation/types';
import {
Exiting,
isCI,
isTestExecution,
setIsCodeSpace,
setIsWebExtension,
Telemetry
} from './platform/common/constants';
import { registerLogger, setLoggingLevel } from './platform/logging';
import { Exiting, isCI, isTestExecution, setIsCodeSpace, setIsWebExtension } from './platform/common/constants';
import { registerLogger } from './platform/logging';
import { ConsoleLogger } from './platform/logging/consoleLogger';
import { initializeGlobals as initializeTelemetryGlobals } from './platform/telemetry/telemetry';
import { IInterpreterPackages } from './platform/interpreter/types';
@ -77,9 +62,13 @@ import {
} from './standalone/executionAnalysis/extension';
import { activate as activateChat, deactivate as deactivateChat } from './standalone/chat/extesnion';
import { setDisposableTracker } from './platform/common/utils/lifecycle';
import { sendTelemetryEvent } from './telemetry';
import { getVSCodeChannel } from './platform/common/application/applicationEnvironment';
import { addOutputChannel, displayProgress, handleError, initializeGlobals } from './extension.common';
import {
addOutputChannel,
displayProgress,
handleError,
initializeGlobals,
postActivateLegacy
} from './extension.common';
import { activateNotebookTelemetry } from './kernels/telemetry/notebookTelemetry';
durations.codeLoadingTime = stopWatch.elapsedTime;
@ -276,32 +265,5 @@ async function activateLegacy(
registerStandaloneTypes(context, serviceManager, isDevMode);
registerWebviewTypes(serviceManager);
// Load the two data science experiments that we need to register types
// Await here to keep the register method sync
const experimentService = serviceContainer.get<IExperimentService>(IExperimentService);
// This must be done first, this guarantees all experiment information has loaded & all telemetry will contain experiment info.
const stopWatch = new StopWatch();
await experimentService.activate();
const duration = stopWatch.elapsedTime;
sendTelemetryEvent(Telemetry.ExperimentLoad, { duration });
const configuration = serviceManager.get<IConfigurationService>(IConfigurationService);
// We should start logging using the log level as soon as possible, so set it as soon as we can access the level.
// `IConfigurationService` may depend any of the registered types, so doing it after all registrations are finished.
// XXX Move this *after* abExperiments is activated?
const settings = configuration.getSettings();
setLoggingLevel(settings.logging.level, settings.logging.widgets);
settings.onDidChange(() => {
setLoggingLevel(settings.logging.level, settings.logging.widgets);
});
// "initialize" "services"
commands.executeCommand('setContext', 'jupyter.vscode.channel', getVSCodeChannel()).then(noop, noop);
// "activate" everything else
serviceContainer.get<IExtensionActivationManager>(IExtensionActivationManager).activate();
const featureManager = serviceContainer.get<IFeaturesManager>(IFeaturesManager);
featureManager.initialize();
context.subscriptions.push(featureManager);
await postActivateLegacy(context, serviceManager, serviceContainer);
}

Просмотреть файл

@ -49,14 +49,7 @@ import './platform/logging';
import { commands, env, ExtensionMode, UIKind, workspace } from 'vscode';
import { buildApi, IExtensionApi } from './standalone/api';
import { traceError } from './platform/logging';
import {
IAsyncDisposableRegistry,
IConfigurationService,
IExperimentService,
IExtensionContext,
IFeaturesManager,
IsDevMode
} from './platform/common/types';
import { IAsyncDisposableRegistry, IExtensionContext, IsDevMode } from './platform/common/types';
import { IServiceContainer, IServiceManager } from './platform/ioc/types';
import { sendStartupTelemetry } from './platform/telemetry/startupTelemetry';
import { noop } from './platform/common/utils/misc';
@ -67,22 +60,18 @@ import { registerTypes as registerInteractiveTypes } from './interactive-window/
import { registerTypes as registerTerminalTypes } from './platform/terminals/serviceRegistry.web';
import { registerTypes as registerStandaloneTypes } from './standalone/serviceRegistry.web';
import { registerTypes as registerWebviewTypes } from './webviews/extension-side/serviceRegistry.web';
import { IExtensionActivationManager } from './platform/activation/types';
import {
Exiting,
isCI,
isTestExecution,
setIsCodeSpace,
setIsWebExtension,
Telemetry
} from './platform/common/constants';
import { registerLogger, setLoggingLevel } from './platform/logging';
import { Exiting, isCI, isTestExecution, setIsCodeSpace, setIsWebExtension } from './platform/common/constants';
import { registerLogger } from './platform/logging';
import { ConsoleLogger } from './platform/logging/consoleLogger';
import { initializeGlobals as initializeTelemetryGlobals } from './platform/telemetry/telemetry';
import { setDisposableTracker } from './platform/common/utils/lifecycle';
import { sendTelemetryEvent } from './telemetry';
import { getVSCodeChannel } from './platform/common/application/applicationEnvironment';
import { addOutputChannel, displayProgress, handleError, initializeGlobals } from './extension.common';
import {
addOutputChannel,
displayProgress,
handleError,
initializeGlobals,
postActivateLegacy
} from './extension.common';
import { activateNotebookTelemetry } from './kernels/telemetry/notebookTelemetry';
durations.codeLoadingTime = stopWatch.elapsedTime;
@ -234,32 +223,5 @@ async function activateLegacy(
registerStandaloneTypes(context, serviceManager, isDevMode);
registerWebviewTypes(serviceManager);
// Load the two data science experiments that we need to register types
// Await here to keep the register method sync
const experimentService = serviceContainer.get<IExperimentService>(IExperimentService);
// This must be done first, this guarantees all experiment information has loaded & all telemetry will contain experiment info.
const stopWatch = new StopWatch();
await experimentService.activate();
const duration = stopWatch.elapsedTime;
sendTelemetryEvent(Telemetry.ExperimentLoad, { duration });
const configuration = serviceManager.get<IConfigurationService>(IConfigurationService);
// We should start logging using the log level as soon as possible, so set it as soon as we can access the level.
// `IConfigurationService` may depend any of the registered types, so doing it after all registrations are finished.
// XXX Move this *after* abExperiments is activated?
const settings = configuration.getSettings();
setLoggingLevel(settings.logging.level, settings.logging.widgets);
settings.onDidChange(() => {
setLoggingLevel(settings.logging.level, settings.logging.widgets);
});
// "initialize" "services"
commands.executeCommand('setContext', 'jupyter.vscode.channel', getVSCodeChannel()).then(noop, noop);
// "activate" everything else
serviceContainer.get<IExtensionActivationManager>(IExtensionActivationManager).activate();
const featureManager = serviceContainer.get<IFeaturesManager>(IFeaturesManager);
featureManager.initialize();
context.subscriptions.push(featureManager);
await postActivateLegacy(context, serviceManager, serviceContainer);
}

Просмотреть файл

@ -17,7 +17,8 @@ import {
ViewColumn,
workspace,
WorkspaceEdit,
window
window,
LogLevel
} from 'vscode';
import { IKernelProvider, KernelConnectionMetadata } from '../../kernels/types';
import { ICommandNameArgumentTypeMapping } from '../../commands';
@ -232,7 +233,7 @@ export class CommandRegistry implements IDisposable, IExtensionSyncActivationSer
private async enableDebugLogging() {
const previousValue = this.configService.getSettings().logging.level;
if (previousValue !== 'debug') {
if (previousValue !== LogLevel.Debug) {
await this.configService.updateSetting('logging.level', 'debug', undefined, ConfigurationTarget.Global);
commands.executeCommand('jupyter.reloadVSCode', DataScience.reloadRequired).then(noop, noop);
}
@ -240,7 +241,7 @@ export class CommandRegistry implements IDisposable, IExtensionSyncActivationSer
private async resetLoggingLevel() {
const previousValue = this.configService.getSettings().logging.level;
if (previousValue !== 'error') {
if (previousValue !== LogLevel.Error) {
await this.configService.updateSetting('logging.level', 'error', undefined, ConfigurationTarget.Global);
commands.executeCommand('jupyter.reloadVSCode', DataScience.reloadRequired).then(noop, noop);
}

Просмотреть файл

@ -10,7 +10,7 @@ import {
NotebookCellOutputItem,
TextDocument
} from 'vscode';
import { traceInfo, traceVerbose } from '../../platform/logging';
import { traceVerbose } from '../../platform/logging';
import { IKernelController } from '../types';
import { noop } from '../../platform/common/utils/misc';
import { getNotebookTelemetryTracker } from '../telemetry/notebookTelemetry';
@ -78,7 +78,7 @@ export class NotebookCellExecutionWrapper implements NotebookCellExecution {
if (this._endCallback) {
try {
this._impl.end(success, endTime, this.errorInfo);
traceInfo(
traceVerbose(
`Cell ${this.cell.index} completed in ${
((endTime || 0) - (this._startTime || 0)) / 1000
}s (start: ${this._startTime}, end: ${endTime})`

Просмотреть файл

@ -61,17 +61,13 @@ export class JupyterServerHelper implements IJupyterServerHelper {
}
public async dispose(): Promise<void> {
traceInfo(`Disposing HostJupyterExecution`);
if (!this._disposed) {
this._disposed = true;
traceVerbose(`Disposing super HostJupyterExecution`);
this.disposed = true;
// Cleanup on dispose. We are going away permanently
traceVerbose(`Cleaning up server cache`);
await this.cache?.then((s) => s.dispose()).catch(noop);
}
traceVerbose(`Finished disposing HostJupyterExecution`);
}
public async startServer(resource: Resource, cancelToken: CancellationToken): Promise<IJupyterConnection> {
@ -162,7 +158,7 @@ export class JupyterServerHelper implements IJupyterServerHelper {
private async startImpl(resource: Resource, cancelToken: CancellationToken): Promise<IJupyterConnection> {
// If our uri is undefined or if it's set to local launch we need to launch a server locally
// If that works, then attempt to start the server
traceInfo(`Launching server`);
traceVerbose(`Launching server`);
const settings = this.configuration.getSettings(resource);
const useDefaultConfig = settings.useDefaultConfigForJupyter;
const workingDir = await computeWorkingDirectory(resource);

Просмотреть файл

@ -65,7 +65,7 @@ export class JupyterServerStarter implements IJupyterServerStarter {
workingDirectory: Uri,
cancelToken: CancellationToken
): Promise<IJupyterConnection> {
traceInfo('Starting Notebook');
traceInfo('Starting Jupyter Server');
// Now actually launch it
let exitCode: number | null = 0;
let starter: JupyterConnectionWaiter | undefined;
@ -87,7 +87,6 @@ export class JupyterServerStarter implements IJupyterServerStarter {
Cancellation.throwIfCanceled(cancelToken);
// Then use this to launch our notebook process.
traceVerbose('Starting Jupyter Notebook');
const [launchResult, tempDir, interpreter] = await Promise.all([
this.jupyterInterpreterService.startNotebook(args || [], {
throwOnStdErr: false,
@ -256,7 +255,7 @@ export class JupyterServerStarter implements IJupyterServerStarter {
// as starting jupyter with all of the defaults.
const configFile = path.join(tempDir.path, 'jupyter_notebook_config.py');
await this.fs.writeFile(Uri.file(configFile), '');
traceInfo(`Generating custom default config at ${configFile}`);
traceVerbose(`Generating custom default config at ${configFile}`);
// Create extra args based on if we have a config or not
return `--config=${configFile}`;

Просмотреть файл

@ -237,7 +237,7 @@ export class NotebookKernelExecution implements INotebookKernelExecution {
.finally(() => {
completed = true;
!token.isCancellationRequested &&
traceInfo(`Execution of code ${result.executionId} completed in ${stopWatch.elapsedTime}ms`);
traceVerbose(`Execution of code ${result.executionId} completed in ${stopWatch.elapsedTime}ms`);
if (extensionId !== JVSC_EXTENSION_ID) {
sendKernelTelemetryEvent(
this.kernel.resourceUri,

Просмотреть файл

@ -392,7 +392,7 @@ export class VSCodeNotebookController implements Disposable, IVSCodeNotebookCont
if (!workspace.isTrusted) {
return;
}
traceInfo(`Handle Execution of Cells ${cells.map((c) => c.index)} for ${getDisplayPath(notebook.uri)}`);
traceVerbose(`Handle Execution of Cells ${cells.map((c) => c.index)} for ${getDisplayPath(notebook.uri)}`);
await initializeInteractiveOrNotebookTelemetryBasedOnUserAction(notebook.uri, this.connection);
telemetryTracker?.stop();
// Notebook is trusted. Continue to execute cells

Просмотреть файл

@ -21,7 +21,7 @@ import { sendTelemetryEvent } from '../../telemetry';
import { isCI, PythonExtension, Telemetry } from '../common/constants';
import { IDisposableRegistry, IExtensionContext } from '../common/types';
import { createDeferred, sleep } from '../common/utils/async';
import { traceError, traceInfo, traceInfoIfCI, traceVerbose, traceWarning } from '../logging';
import { traceError, traceInfoIfCI, traceVerbose, traceWarning } from '../logging';
import { getDisplayPath, getFilePath } from '../common/platform/fs-paths';
import { IInterpreterService } from '../interpreter/contracts';
import { areInterpreterPathsSame, getInterpreterHash } from '../pythonEnvironments/info/interpreter';
@ -448,7 +448,7 @@ export class InterpreterService implements IInterpreterService {
}
this.lastLoggedResourceAndInterpreterId = key;
const version = getCachedVersion(item);
traceInfo(
traceVerbose(
`Active Interpreter ${resource ? `for '${getDisplayPath(resource)}' ` : ''}is ${getDisplayPath(
item?.id
)} (${item && getEnvironmentType(item)}, '${

Просмотреть файл

@ -7,11 +7,11 @@ import {
Disposable,
Event,
EventEmitter,
LogLevel,
Uri,
WorkspaceConfiguration,
workspace
} from 'vscode';
import { LogLevel } from '../logging/types';
import { isTestExecution } from './constants';
import {
IExperiments,
@ -41,7 +41,7 @@ export class JupyterSettings implements IWatchableJupyterSettings {
private static jupyterSettings: Map<string, JupyterSettings> = new Map<string, JupyterSettings>();
public experiments!: IExperiments;
public logging: ILoggingSettings = { level: 'error' };
public logging: ILoggingSettings = { level: LogLevel.Error };
public allowUnauthorizedRemoteConnection: boolean = false;
public jupyterInterruptTimeout: number = 10_000;
public jupyterLaunchTimeout: number = 60_000;
@ -291,19 +291,16 @@ function convertSettingTypeToLogLevel(setting: LoggingLevelSettingType | undefin
return LogLevel.Info;
}
case 'warn': {
return LogLevel.Warn;
return LogLevel.Warning;
}
case 'off': {
return 'off';
}
case 'debug': {
return LogLevel.Debug;
}
case 'verbose': {
return LogLevel.Trace;
case 'error': {
return LogLevel.Error;
}
default: {
return LogLevel.Error;
return LogLevel.Debug;
}
}
}

Просмотреть файл

@ -6,7 +6,7 @@ import { Memento, workspace } from 'vscode';
import { getExperimentationService, IExperimentationService, TargetPopulation } from 'vscode-tas-client';
import { IApplicationEnvironment } from '../application/types';
import { JVSC_EXTENSION_ID, isPreReleaseVersion } from '../constants';
import { traceInfo, traceVerbose } from '../../logging';
import { traceInfo } from '../../logging';
import { GLOBAL_MEMENTO, IConfigurationService, IExperimentService, IJupyterSettings, IMemento } from '../types';
import { Experiments } from '../utils/localize';
import { Experiments as ExperimentGroups } from '../types';
@ -78,7 +78,6 @@ export class ExperimentService implements IExperimentService {
public async activate() {
if (this.experimentationService && this.enabled) {
traceVerbose(`Experimentation service retrieved: ${this.experimentationService}`);
await this.experimentationService.initializePromise;
if (this.getFeatures().length === 0) {
// Only await on this if we don't have anything in cache.

Просмотреть файл

@ -1,7 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { ConfigurationTarget, Disposable, Event, ExtensionContext, OutputChannel, Uri, Range } from 'vscode';
import {
ConfigurationTarget,
Disposable,
Event,
ExtensionContext,
OutputChannel,
Uri,
Range,
type LogLevel
} from 'vscode';
import { PythonEnvironment } from '../pythonEnvironments/info';
import { CommandIds } from '../../commands';
import { ISystemVariables } from './variables/types';
@ -107,10 +116,10 @@ export interface IWatchableJupyterSettings extends IJupyterSettings {
createSystemVariables(resource: Resource): ISystemVariables;
}
export type LoggingLevelSettingType = 'off' | 'error' | 'warn' | 'info' | 'debug' | 'verbose';
export type LoggingLevelSettingType = 'off' | 'error' | 'warn' | 'info' | 'debug';
export interface ILoggingSettings {
readonly level: LoggingLevelSettingType | 'off';
readonly level: LogLevel;
readonly widgets?: LoggingLevelSettingType | 'off';
}

Просмотреть файл

@ -5,8 +5,10 @@
import { isTestExecution } from '../constants';
import { DataWithExpiry, getCacheKeyFromFunctionArgs, getGlobalCacheStore } from './cacheUtils';
import { noop, TraceInfo, tracing } from './misc';
import { traceError, traceVerbose } from '../../logging';
import { noop } from './misc';
import { traceError, traceVerbose, type TraceInfo } from '../../logging';
import { StopWatch } from './stopWatch';
import { isPromise } from './async';
type PromiseFunctionWithAnyArgs = (...any: any) => Promise<any>;
const cacheStoreForMethods = getGlobalCacheStore();
@ -88,6 +90,39 @@ export type CallInfo = {
target: Object;
};
// Call run(), call log() with the trace info, and return the result.
function tracing<T>(log: (t: TraceInfo) => void, run: () => T, logBeforeCall?: boolean): T {
const timer = new StopWatch();
try {
if (logBeforeCall) {
log(undefined);
}
// eslint-disable-next-line no-invalid-this, @typescript-eslint/no-use-before-define,
const result = run();
// If method being wrapped returns a promise then wait for it.
if (isPromise(result)) {
// eslint-disable-next-line
(result as Promise<void>)
.then((data) => {
log({ elapsed: timer.elapsedTime, returnValue: data });
return data;
})
.catch((ex) => {
log({ elapsed: timer.elapsedTime, err: ex });
// eslint-disable-next-line
// TODO(GH-11645) Re-throw the error like we do
// in the non-Promise case.
});
} else {
log({ elapsed: timer.elapsedTime, returnValue: result });
}
return result;
} catch (ex) {
log({ elapsed: timer.elapsedTime, err: ex });
throw ex;
}
}
// Return a decorator that traces the decorated function.
export function trace(log: (c: CallInfo, t: TraceInfo) => void, logBeforeCall?: boolean) {
// eslint-disable-next-line , @typescript-eslint/no-explicit-any

Просмотреть файл

@ -5,7 +5,6 @@ import type { TextDocument, Uri } from 'vscode';
import { NotebookCellScheme } from '../constants';
import { InterpreterUri, Resource } from '../types';
import { isPromise } from './async';
import { StopWatch } from './stopWatch';
import { Environment } from '@vscode/python-extension';
// eslint-disable-next-line no-empty,@typescript-eslint/no-empty-function
@ -60,51 +59,6 @@ export type ExcludeType<T, Value> = {
[P in keyof T as T[P] extends Value ? never : P]: T[P];
};
// Information about a traced function/method call.
export type TraceInfo =
| {
elapsed: number; // milliseconds
// Either returnValue or err will be set.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
returnValue?: any;
err?: Error;
}
| undefined;
// Call run(), call log() with the trace info, and return the result.
export function tracing<T>(log: (t: TraceInfo) => void, run: () => T, logBeforeCall?: boolean): T {
const timer = new StopWatch();
try {
if (logBeforeCall) {
log(undefined);
}
// eslint-disable-next-line no-invalid-this, @typescript-eslint/no-use-before-define,
const result = run();
// If method being wrapped returns a promise then wait for it.
if (isPromise(result)) {
// eslint-disable-next-line
(result as Promise<void>)
.then((data) => {
log({ elapsed: timer.elapsedTime, returnValue: data });
return data;
})
.catch((ex) => {
log({ elapsed: timer.elapsedTime, err: ex });
// eslint-disable-next-line
// TODO(GH-11645) Re-throw the error like we do
// in the non-Promise case.
});
} else {
log({ elapsed: timer.elapsedTime, returnValue: result });
}
return result;
} catch (ex) {
log({ elapsed: timer.elapsedTime, err: ex });
throw ex;
}
}
/**
* Checking whether something is a Resource (Uri/undefined).
* Using `instanceof Uri` doesn't always work as the object is not an instance of Uri (at least not in tests).

Просмотреть файл

@ -4,11 +4,10 @@
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Disposable, Uri } from 'vscode';
import { Disposable, Uri, LogLevel } from 'vscode';
import { isCI } from '../common/constants';
import { Arguments, ILogger, LogLevel, TraceDecoratorType, TraceOptions } from './types';
import { Arguments, ILogger, TraceDecoratorType, TraceOptions } from './types';
import { CallInfo, trace as traceDecorator } from '../common/utils/decorators';
import { TraceInfo, tracing as _tracing } from '../common/utils/misc';
import { argsToLogString, returnValueToLogString } from './util';
import { LoggingLevelSettingType } from '../common/types';
import { splitLines } from '../common/helpers';
@ -16,6 +15,17 @@ import { getDisplayPath } from '../common/platform/fs-paths';
let homeAsLowerCase = '';
const DEFAULT_OPTS: TraceOptions = TraceOptions.Arguments | TraceOptions.ReturnValue;
// Information about a traced function/method call.
export type TraceInfo =
| {
elapsed: number; // milliseconds
// Either returnValue or err will be set.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
returnValue?: any;
err?: Error;
}
| undefined;
let loggers: ILogger[] = [];
export function registerLogger(logger: ILogger): Disposable {
loggers.push(logger);
@ -26,24 +36,11 @@ export function registerLogger(logger: ILogger): Disposable {
};
}
const logLevelMap: Map<string | undefined, LogLevel> = new Map([
['error', LogLevel.Error],
['warn', LogLevel.Warn],
['info', LogLevel.Info],
['debug', LogLevel.Debug],
['none', LogLevel.Off],
['off', LogLevel.Off],
[undefined, LogLevel.Error]
]);
let globalLoggingLevel: LogLevel = LogLevel.Debug;
let _enabledWidgetLogging: LoggingLevelSettingType = 'off';
export function setLoggingLevel(
level?: LoggingLevelSettingType | number,
enabledWidgetLogging?: LoggingLevelSettingType
): void {
export function setLoggingLevel(level: LogLevel, enabledWidgetLogging?: LoggingLevelSettingType): void {
_enabledWidgetLogging = enabledWidgetLogging || 'off';
globalLoggingLevel = typeof level === 'number' ? level : logLevelMap.get(level) ?? LogLevel.Error;
globalLoggingLevel = level;
}
export function setHomeDirectory(homeDir: string) {
@ -52,7 +49,7 @@ export function setHomeDirectory(homeDir: string) {
function formatErrors(...args: Arguments) {
// Format the error message, if showing verbose then include all of the error stack & other details.
const formatError = globalLoggingLevel <= LogLevel.Trace ? false : true;
const formatError = globalLoggingLevel <= LogLevel.Debug ? false : true;
if (!formatError) {
return args;
}
@ -121,7 +118,7 @@ export function traceError(message: string, ...args: Arguments): void {
}
export function traceWarning(message: string, ...args: Arguments): void {
if (globalLoggingLevel <= LogLevel.Warn) {
if (globalLoggingLevel <= LogLevel.Warning) {
args = formatErrors(...args);
loggers.forEach((l) => l.traceWarn(message, ...args));
}
@ -139,12 +136,12 @@ export function traceInfoWidgets(message: string, ...args: Arguments): void {
}
export function traceVerbose(message: string, ...args: Arguments): void {
if (globalLoggingLevel <= LogLevel.Trace) {
if (globalLoggingLevel <= LogLevel.Debug) {
loggers.forEach((l) => l.traceVerbose(message, ...args));
}
}
export function traceVerboseWidgets(message: string, ...args: Arguments): void {
if (_enabledWidgetLogging !== 'off' && globalLoggingLevel <= LogLevel.Trace) {
if (_enabledWidgetLogging !== 'off' && globalLoggingLevel <= LogLevel.Debug) {
loggers.forEach((l) => l.traceVerbose(message, ...args));
}
}
@ -173,7 +170,7 @@ export function traceInfoIfCI(arg1: any, ...args: Arguments): void {
/** Logging Decorators go here */
export function traceDecoratorVerbose(message: string, opts: TraceOptions = DEFAULT_OPTS): TraceDecoratorType {
return createTracingDecorator({ message, opts, level: LogLevel.Trace });
return createTracingDecorator({ message, opts, level: LogLevel.Debug });
}
export function traceDecoratorError(message: string): TraceDecoratorType {
return createTracingDecorator({ message, opts: DEFAULT_OPTS, level: LogLevel.Error });
@ -182,7 +179,7 @@ export function traceDecoratorInfo(message: string): TraceDecoratorType {
return createTracingDecorator({ message, opts: DEFAULT_OPTS, level: LogLevel.Info });
}
export function traceDecoratorWarn(message: string): TraceDecoratorType {
return createTracingDecorator({ message, opts: DEFAULT_OPTS, level: LogLevel.Warn });
return createTracingDecorator({ message, opts: DEFAULT_OPTS, level: LogLevel.Warning });
}
type ParameterLogInformation =
@ -249,11 +246,6 @@ export function createTracingDecorator(logInfo: LogInfo) {
);
}
// This is like a "context manager" that logs tracing info.
export function tracing<T>(logInfo: LogInfo, run: () => T, call?: CallInfo): T {
return _tracing((traced) => logResult(logInfo, traced, call), run, (logInfo.opts & TraceOptions.BeforeCall) > 0);
}
export type LogInfo = {
opts: TraceOptions;
message: string;
@ -324,7 +316,7 @@ function formatMessages(info: LogInfo, traced: TraceInfo, call?: CallInfo): stri
messages[messages.length - 1] = `${messages[messages.length - 1]} (started execution)`;
}
if ((info.opts & TraceOptions.Arguments) === TraceOptions.Arguments) {
if (info.level === LogLevel.Trace) {
if (info.level === LogLevel.Debug) {
// This is slower, hence do this only when user enables trace logging.
messages.push(
argsToLogString(
@ -363,20 +355,18 @@ function logResult(info: LogInfo, traced: TraceInfo, call?: CallInfo) {
}
}
export function logTo(logLevel: LogLevel, message: string, ...args: Arguments): void {
function logTo(logLevel: LogLevel, message: string, ...args: Arguments): void {
switch (logLevel) {
case LogLevel.Error:
traceError(message, ...args);
break;
case LogLevel.Warn:
case LogLevel.Warning:
traceWarning(message, ...args);
break;
case LogLevel.Info:
traceInfo(message, ...args);
break;
case LogLevel.Debug:
traceVerbose(message, ...args);
break;
case LogLevel.Trace:
traceVerbose(message, ...args);
break;

Просмотреть файл

@ -4,16 +4,6 @@
/* eslint-disable @typescript-eslint/ban-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
export enum LogLevel {
// Larger numbers are higher priority.
Error = 40,
Warn = 30,
Info = 20,
Debug = 10,
Trace = 5,
Off = 100
}
export type Arguments = unknown[];
export interface ILogger {

Просмотреть файл

@ -218,7 +218,7 @@ export class ControllerPreferredService {
// If we found a preferred kernel, set the association on the NotebookController
if (preferredSearchToken.token.isCancellationRequested && !preferredConnection) {
traceInfo('Find preferred kernel cancelled');
traceVerbose('Find preferred kernel cancelled');
return {};
}
if (!preferredConnection) {

Просмотреть файл

@ -133,7 +133,7 @@ async function createSettings(): Promise<string> {
const settingsFile = path.join(userDataDirectory, 'User', 'settings.json');
const defaultSettings: Record<string, string | boolean | string[]> = {
'python.insidersChannel': 'off',
'jupyter.logging.level': 'verbose',
'jupyter.logging.level': 'debug',
'python.logging.level': 'debug',
'files.autoSave': 'off',
'python.experiments.enabled': true,

Просмотреть файл

@ -180,6 +180,7 @@ mockedVSCode.NotebookRendererScript = vscodeMocks.vscMockExtHostedTypes.Notebook
mockedVSCode.NotebookEdit = vscodeMocks.vscMockExtHostedTypes.NotebookEdit;
mockedVSCode.NotebookRange = vscodeMocks.vscMockExtHostedTypes.NotebookRange;
mockedVSCode.QuickPickItemKind = vscodeMocks.vscMockExtHostedTypes.QuickPickItemKind;
(mockedVSCode as any).LogLevel = vscodeMocks.vscMockExtHostedTypes.LogLevel;
(mockedVSCode.NotebookCellData as any) = vscodeMocks.vscMockExtHostedTypes.NotebookCellData;
(mockedVSCode as any).NotebookCellKind = vscodeMocks.vscMockExtHostedTypes.NotebookCellKind;
(mockedVSCode as any).NotebookCellRunState = vscodeMocks.vscMockExtHostedTypes.NotebookCellRunState;

Просмотреть файл

@ -9,7 +9,7 @@ export function getDefaultSettings(): IJupyterExtraSettings {
const result: Partial<IJupyterExtraSettings> = {
experiments: { enabled: true, optInto: [], optOutFrom: [] },
logging: {
level: 'off'
level: 5 // Not used in react side, should be removed later.
},
jupyterLaunchTimeout: 10,
jupyterLaunchRetries: 3,