mirror of
https://github.com/microsoft/vscode.git
synced 2026-08-23 15:34:20 +01:00
report user and workspace modified configurations (#202489)
This commit is contained in:
@@ -655,7 +655,6 @@ export class StandaloneConfigurationService implements IConfigurationService {
|
||||
if (changedKeys.length > 0) {
|
||||
const configurationChangeEvent = new ConfigurationChangeEvent({ keys: changedKeys, overrides: [] }, previous, this._configuration);
|
||||
configurationChangeEvent.source = ConfigurationTarget.MEMORY;
|
||||
configurationChangeEvent.sourceConfig = null;
|
||||
this._onDidChangeConfiguration.fire(configurationChangeEvent);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +68,6 @@ export interface IConfigurationChangeEvent {
|
||||
readonly change: IConfigurationChange;
|
||||
|
||||
affectsConfiguration(configuration: string, overrides?: IConfigurationOverrides): boolean;
|
||||
|
||||
// Following data is used for telemetry
|
||||
readonly sourceConfig: any;
|
||||
}
|
||||
|
||||
export interface IConfigurationValue<T> {
|
||||
|
||||
@@ -1087,7 +1087,6 @@ export class ConfigurationChangeEvent implements IConfigurationChangeEvent {
|
||||
|
||||
readonly affectedKeys = new Set<string>();
|
||||
source!: ConfigurationTarget;
|
||||
sourceConfig: any;
|
||||
|
||||
constructor(readonly change: IConfigurationChange, private readonly previous: { workspace?: Workspace; data: IConfigurationData } | undefined, private readonly currentConfiguraiton: Configuration, private readonly currentWorkspace?: Workspace) {
|
||||
for (const key of change.keys) {
|
||||
|
||||
@@ -159,19 +159,8 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
|
||||
private trigger(configurationChange: IConfigurationChange, previous: IConfigurationData, source: ConfigurationTarget): void {
|
||||
const event = new ConfigurationChangeEvent(configurationChange, { data: previous }, this.configuration);
|
||||
event.source = source;
|
||||
event.sourceConfig = this.getTargetConfiguration(source);
|
||||
this._onDidChangeConfiguration.fire(event);
|
||||
}
|
||||
|
||||
private getTargetConfiguration(target: ConfigurationTarget): any {
|
||||
switch (target) {
|
||||
case ConfigurationTarget.DEFAULT:
|
||||
return this.configuration.defaults.contents;
|
||||
case ConfigurationTarget.USER:
|
||||
return this.configuration.localUserConfiguration.contents;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigurationEditing {
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { cloneAndChange, safeStringify } from 'vs/base/common/objects';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ConfigurationTarget, ConfigurationTargetToString, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
|
||||
@@ -81,33 +79,6 @@ export interface URIDescriptor {
|
||||
path?: string;
|
||||
}
|
||||
|
||||
export function configurationTelemetry(telemetryService: ITelemetryService, configurationService: IConfigurationService): IDisposable {
|
||||
// Debounce the event by 1000 ms and merge all affected keys into one event
|
||||
const debouncedConfigService = Event.debounce(configurationService.onDidChangeConfiguration, (last, cur) => {
|
||||
const newAffectedKeys: ReadonlySet<string> = last ? new Set([...last.affectedKeys, ...cur.affectedKeys]) : cur.affectedKeys;
|
||||
return { ...cur, affectedKeys: newAffectedKeys };
|
||||
}, 1000, true);
|
||||
|
||||
return debouncedConfigService(event => {
|
||||
if (event.source !== ConfigurationTarget.DEFAULT) {
|
||||
type UpdateConfigurationClassification = {
|
||||
owner: 'lramos15, sbatten';
|
||||
comment: 'Event which fires when user updates settings';
|
||||
configurationSource: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'What configuration file was updated i.e user or workspace' };
|
||||
configurationKeys: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'What configuration keys were updated' };
|
||||
};
|
||||
type UpdateConfigurationEvent = {
|
||||
configurationSource: string;
|
||||
configurationKeys: string[];
|
||||
};
|
||||
telemetryService.publicLog2<UpdateConfigurationEvent, UpdateConfigurationClassification>('updateConfiguration', {
|
||||
configurationSource: ConfigurationTargetToString(event.source),
|
||||
configurationKeys: Array.from(event.affectedKeys)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not we support logging telemetry.
|
||||
* This checks if the product is capable of collecting telemetry but not whether or not it can send it
|
||||
|
||||
@@ -28,8 +28,6 @@ import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
|
||||
import { IPaneCompositeBarOptions } from 'vs/workbench/browser/parts/paneCompositeBar';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Action2, IMenuService, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { Separator } from 'vs/base/common/actions';
|
||||
import { ToggleActivityBarVisibilityActionId } from 'vs/workbench/browser/actions/layoutActions';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -79,8 +77,6 @@ export class SidebarPart extends AbstractPaneCompositePart {
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@IMenuService menuService: IMenuService,
|
||||
) {
|
||||
super(
|
||||
@@ -114,14 +110,6 @@ export class SidebarPart extends AbstractPaneCompositePart {
|
||||
}));
|
||||
|
||||
this.registerActions();
|
||||
|
||||
lifecycleService.when(LifecyclePhase.Eventually).then(() => {
|
||||
telemetryService.publicLog2<{ location: string }, {
|
||||
owner: 'sandy081';
|
||||
location: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Locaiton where the activity bar is shown' };
|
||||
comment: 'This is used to know where activity bar is shown in the workbench.';
|
||||
}>('activityBar:location', { location: configurationService.getValue(LayoutSettings.ACTIVITY_BAR_LOCATION) });
|
||||
});
|
||||
}
|
||||
|
||||
private onDidChangeActivityBarLocation(): void {
|
||||
|
||||
@@ -804,14 +804,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||
urlService.registerHandler(this);
|
||||
|
||||
this.whenInitialized = this.initialize();
|
||||
|
||||
lifecycleService.when(LifecyclePhase.Eventually).then(() => {
|
||||
telemetryService.publicLog2<{ mode: string }, {
|
||||
owner: 'sandy081';
|
||||
mode: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Auto Update Mode' };
|
||||
comment: 'This is used to know if extensions are getting auto updated or not';
|
||||
}>('extensions:autoupdate', { mode: `${this.getAutoUpdateValue()}` });
|
||||
});
|
||||
}
|
||||
|
||||
private async initialize(): Promise<void> {
|
||||
|
||||
@@ -269,7 +269,6 @@ export class NotebookOptions extends Disposable {
|
||||
source: ConfigurationTarget.DEFAULT,
|
||||
affectedKeys: new Set([NotebookSetting.insertToolbarLocation]),
|
||||
change: { keys: [NotebookSetting.insertToolbarLocation], overrides: [] },
|
||||
sourceConfig: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
|
||||
import { language } from 'vs/base/common/platform';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
|
||||
import { configurationTelemetry, TelemetryTrustedValue } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { TelemetryTrustedValue } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ITextFileService, ITextFileSaveEvent, ITextFileResolveEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { extname, basename, isEqual, isEqualOrParent } from 'vs/base/common/resources';
|
||||
@@ -126,9 +126,6 @@ export class TelemetryContribution extends Disposable implements IWorkbenchContr
|
||||
// Error Telemetry
|
||||
this._register(new ErrorTelemetry(telemetryService));
|
||||
|
||||
// Configuration Telemetry
|
||||
this._register(configurationTelemetry(telemetryService, configurationService));
|
||||
|
||||
// Files Telemetry
|
||||
this._register(textFileService.files.onDidResolve(e => this.onTextFileModelResolved(e)));
|
||||
this._register(textFileService.files.onDidSave(e => this.onTextFileModelSaved(e)));
|
||||
|
||||
@@ -37,7 +37,7 @@ import { delta, distinct, equals as arrayEquals } from 'vs/base/common/arrays';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
|
||||
import { isUndefined } from 'vs/base/common/types';
|
||||
import { isBoolean, isNumber, isString, isUndefined } from 'vs/base/common/types';
|
||||
import { localize } from 'vs/nls';
|
||||
import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy';
|
||||
@@ -47,6 +47,7 @@ import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/envir
|
||||
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
import { runWhenWindowIdle } from 'vs/base/browser/dom';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
function getLocalUserConfigurationScopes(userDataProfile: IUserDataProfile, hasRemote: boolean): ConfigurationScope[] | undefined {
|
||||
return (userDataProfile.isDefault || userDataProfile.useDefaultFlags?.settings)
|
||||
@@ -1018,7 +1019,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||
}
|
||||
|
||||
if (overrides?.overrideIdentifiers?.length && overrides.overrideIdentifiers.length > 1) {
|
||||
const configurationModel = this.getConfigurationModel(editableConfigurationTarget, overrides.resource);
|
||||
const configurationModel = this.getConfigurationModelForEditableConfigurationTarget(editableConfigurationTarget, overrides.resource);
|
||||
if (configurationModel) {
|
||||
const overrideIdentifiers = overrides.overrideIdentifiers.sort();
|
||||
const existingOverrides = configurationModel.overrides.find(override => arrayEquals([...override.identifiers].sort(), overrideIdentifiers));
|
||||
@@ -1052,7 +1053,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||
}
|
||||
}
|
||||
|
||||
private getConfigurationModel(target: EditableConfigurationTarget, resource?: URI | null): ConfigurationModel | undefined {
|
||||
private getConfigurationModelForEditableConfigurationTarget(target: EditableConfigurationTarget, resource?: URI | null): ConfigurationModel | undefined {
|
||||
switch (target) {
|
||||
case EditableConfigurationTarget.USER_LOCAL: return this._configuration.localUserConfiguration;
|
||||
case EditableConfigurationTarget.USER_REMOTE: return this._configuration.remoteUserConfiguration;
|
||||
@@ -1061,6 +1062,16 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||
}
|
||||
}
|
||||
|
||||
getConfigurationModel(target: ConfigurationTarget, resource?: URI | null): ConfigurationModel | undefined {
|
||||
switch (target) {
|
||||
case ConfigurationTarget.USER_LOCAL: return this._configuration.localUserConfiguration;
|
||||
case ConfigurationTarget.USER_REMOTE: return this._configuration.remoteUserConfiguration;
|
||||
case ConfigurationTarget.WORKSPACE: return this._configuration.workspaceConfiguration;
|
||||
case ConfigurationTarget.WORKSPACE_FOLDER: return resource ? this._configuration.folderConfigurations.get(resource) : undefined;
|
||||
default: return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private deriveConfigurationTargets(key: string, value: any, inspect: IConfigurationValue<any>): ConfigurationTarget[] {
|
||||
if (equals(value, inspect.value)) {
|
||||
return [];
|
||||
@@ -1095,23 +1106,10 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
||||
}
|
||||
const configurationChangeEvent = new ConfigurationChangeEvent(change, previous, this._configuration, this.workspace);
|
||||
configurationChangeEvent.source = target;
|
||||
configurationChangeEvent.sourceConfig = this.getTargetConfiguration(target);
|
||||
this._onDidChangeConfiguration.fire(configurationChangeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private getTargetConfiguration(target: ConfigurationTarget): any {
|
||||
switch (target) {
|
||||
case ConfigurationTarget.DEFAULT:
|
||||
return this._configuration.defaults.contents;
|
||||
case ConfigurationTarget.USER:
|
||||
return this._configuration.userConfiguration.contents;
|
||||
case ConfigurationTarget.WORKSPACE:
|
||||
return this._configuration.workspaceConfiguration.contents;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
private toEditableConfigurationTarget(target: ConfigurationTarget, key: string): EditableConfigurationTarget | null {
|
||||
if (target === ConfigurationTarget.USER) {
|
||||
if (this.remoteUserConfiguration) {
|
||||
@@ -1322,6 +1320,70 @@ class ResetConfigurationDefaultsOverridesCache extends Disposable implements IWo
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigurationTelemetryContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private readonly configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private readonly configurationService: WorkspaceService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
) {
|
||||
super();
|
||||
|
||||
const { user, workspace } = configurationService.keys();
|
||||
for (const key of user) {
|
||||
this.reportConfiguration(key, ConfigurationTarget.USER_LOCAL);
|
||||
}
|
||||
for (const key of workspace) {
|
||||
this.reportConfiguration(key, ConfigurationTarget.WORKSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private reportConfiguration(key: string, target: ConfigurationTarget): void {
|
||||
type UpdateConfigurationClassification = {
|
||||
owner: 'sandy081';
|
||||
comment: 'Event which fires for updated configurations';
|
||||
source: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'What configuration file was updated i.e user or workspace' };
|
||||
key: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'What configuration key was updated' };
|
||||
value?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Value of the key that was updated' };
|
||||
};
|
||||
type UpdateConfigurationEvent = {
|
||||
source: string;
|
||||
key: string;
|
||||
value?: any;
|
||||
};
|
||||
this.telemetryService.publicLog2<UpdateConfigurationEvent, UpdateConfigurationClassification>('updateConfiguration', {
|
||||
source: ConfigurationTargetToString(target),
|
||||
key,
|
||||
value: this.getValueToReport(key, target)
|
||||
});
|
||||
}
|
||||
|
||||
private getValueToReport(key: string, target: ConfigurationTarget): any {
|
||||
const schema = this.configurationRegistry.getConfigurationProperties()[key];
|
||||
if (!schema) {
|
||||
return undefined;
|
||||
}
|
||||
const configurationModel = this.configurationService.getConfigurationModel(target);
|
||||
const value = configurationModel?.getValue(key);
|
||||
if (isNumber(value) || isBoolean(value)) {
|
||||
return value;
|
||||
}
|
||||
if (isString(value)) {
|
||||
if (schema.enum?.includes(value)) {
|
||||
return value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
if (value.every(v => isNumber(v) || isBoolean(v) || (isString(v) && schema.enum?.includes(v)))) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateExperimentalSettingsDefaults extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private readonly processedExperimentalSettings = new Set<string>();
|
||||
@@ -1364,6 +1426,7 @@ const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegist
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RegisterConfigurationSchemasContribution, LifecyclePhase.Restored);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(ResetConfigurationDefaultsOverridesCache, LifecyclePhase.Eventually);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(UpdateExperimentalSettingsDefaults, LifecyclePhase.Ready);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(ConfigurationTelemetryContribution, LifecyclePhase.Eventually);
|
||||
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||
configurationRegistry.registerConfiguration({
|
||||
|
||||
Reference in New Issue
Block a user