Separate exeriments from telemetry (fixes #29339)

This commit is contained in:
Christof Marti
2017-07-03 11:45:05 -07:00
parent ac78ebd870
commit 3dcc354df7
11 changed files with 85 additions and 143 deletions

View File

@@ -33,7 +33,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeybindingsRegistry, IKeybindingItem } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
import { Menu } from 'vs/platform/actions/common/menu';
import { ITelemetryService, ITelemetryExperiments, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { ResolvedKeybinding, Keybinding, createKeybinding, SimpleKeybinding } from 'vs/base/common/keyCodes';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { OS } from 'vs/base/common/platform';
@@ -513,10 +513,6 @@ export class StandaloneTelemetryService implements ITelemetryService {
public getTelemetryInfo(): TPromise<ITelemetryInfo> {
return null;
}
public getExperiments(): ITelemetryExperiments {
return null;
}
}
export class SimpleWorkspaceContextService implements IWorkspaceContextService {

View File

@@ -0,0 +1,74 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
export interface ITelemetryExperiments {
}
const defaultExperiments: ITelemetryExperiments = {
};
export function loadExperiments(accessor?: ServicesAccessor): ITelemetryExperiments {
// shortcut since there are currently no experiments (should introduce separate service to load only once)
if (!accessor) {
return {};
}
const storageService = accessor.get(IStorageService);
const configurationService = accessor.get(IConfigurationService);
let {
} = splitExperimentsRandomness(storageService);
return applyOverrides(defaultExperiments, configurationService);
}
function applyOverrides(experiments: ITelemetryExperiments, configurationService: IConfigurationService): ITelemetryExperiments {
const experimentsConfig = getExperimentsOverrides(configurationService);
Object.keys(experiments).forEach(key => {
if (key in experimentsConfig) {
experiments[key] = experimentsConfig[key];
}
});
return experiments;
}
function splitExperimentsRandomness(storageService: IStorageService): ITelemetryExperiments {
const random1 = getExperimentsRandomness(storageService);
const [random2, /* showTaskDocumentation */] = splitRandom(random1);
const [random3, /* openUntitledFile */] = splitRandom(random2);
const [random4, /* mergeQuickLinks */] = splitRandom(random3);
// tslint:disable-next-line:no-unused-variable (https://github.com/Microsoft/TypeScript/issues/16628)
const [random5, /* enableWelcomePage */] = splitRandom(random4);
return {
};
}
function getExperimentsRandomness(storageService: IStorageService) {
const key = 'experiments.randomness';
let valueString = storageService.get(key);
if (!valueString) {
valueString = Math.random().toString();
storageService.store(key, valueString);
}
return parseFloat(valueString);
}
function splitRandom(random: number): [number, boolean] {
const scaled = random * 2;
const i = Math.floor(scaled);
return [scaled - i, i === 1];
}
function getExperimentsOverrides(configurationService: IConfigurationService): ITelemetryExperiments {
const config: any = configurationService.getConfiguration('telemetry');
return config && config.experiments || {};
}

View File

@@ -21,10 +21,6 @@ export interface ITelemetryData {
[key: string]: any;
}
export interface ITelemetryExperiments {
mergeQuickLinks: boolean;
}
export interface ITelemetryService {
_serviceBrand: any;
@@ -38,6 +34,4 @@ export interface ITelemetryService {
getTelemetryInfo(): TPromise<ITelemetryInfo>;
isOptedIn: boolean;
getExperiments(): ITelemetryExperiments;
}

View File

@@ -7,8 +7,8 @@
import { localize } from 'vs/nls';
import { escapeRegExpCharacters } from 'vs/base/common/strings';
import { ITelemetryService, ITelemetryInfo, ITelemetryExperiments, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryAppender, defaultExperiments } from 'vs/platform/telemetry/common/telemetryUtils';
import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils';
import { optional } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
@@ -22,7 +22,6 @@ export interface ITelemetryServiceConfig {
commonProperties?: TPromise<{ [name: string]: any }>;
piiPaths?: string[];
userOptIn?: boolean;
experiments?: ITelemetryExperiments;
}
export class TelemetryService implements ITelemetryService {
@@ -36,7 +35,6 @@ export class TelemetryService implements ITelemetryService {
private _commonProperties: TPromise<{ [name: string]: any; }>;
private _piiPaths: string[];
private _userOptIn: boolean;
private _experiments: ITelemetryExperiments;
private _disposables: IDisposable[] = [];
private _cleanupPatterns: [RegExp, string][] = [];
@@ -49,7 +47,6 @@ export class TelemetryService implements ITelemetryService {
this._commonProperties = config.commonProperties || TPromise.as({});
this._piiPaths = config.piiPaths || [];
this._userOptIn = typeof config.userOptIn === 'undefined' ? true : config.userOptIn;
this._experiments = config.experiments || defaultExperiments;
// static cleanup patterns for:
// #1 `file:///DANGEROUS/PATH/resources/app/Useful/Information`
@@ -81,10 +78,6 @@ export class TelemetryService implements ITelemetryService {
return this._userOptIn;
}
getExperiments(): ITelemetryExperiments {
return this._experiments;
}
getTelemetryInfo(): TPromise<ITelemetryInfo> {
return this._commonProperties.then(values => {
// well known properties

View File

@@ -12,17 +12,10 @@ import URI from 'vs/base/common/uri';
import { ConfigurationSource, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IKeybindingService, KeybindingSource } from 'vs/platform/keybinding/common/keybinding';
import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService, ITelemetryExperiments, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
export const defaultExperiments: ITelemetryExperiments = {
mergeQuickLinks: false,
};
import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
export const NullTelemetryService = {
_serviceBrand: undefined,
_experiments: defaultExperiments,
publicLog(eventName: string, data?: ITelemetryData) {
return TPromise.as<void>(null);
},
@@ -33,67 +26,9 @@ export const NullTelemetryService = {
sessionId: 'someValue.sessionId',
machineId: 'someValue.machineId'
});
},
getExperiments(): ITelemetryExperiments {
return this._experiments;
}
};
export function loadExperiments(accessor: ServicesAccessor): ITelemetryExperiments {
// const storageService = accessor.get(IStorageService);
const configurationService = accessor.get(IConfigurationService);
// let {
// } = splitExperimentsRandomness(storageService);
return applyOverrides(defaultExperiments, configurationService);
}
function applyOverrides(experiments: ITelemetryExperiments, configurationService: IConfigurationService): ITelemetryExperiments {
const experimentsConfig = getExperimentsOverrides(configurationService);
Object.keys(experiments).forEach(key => {
if (key in experimentsConfig) {
experiments[key] = experimentsConfig[key];
}
});
return experiments;
}
// tslint:disable-next-line:no-unused-variable
function splitExperimentsRandomness(storageService: IStorageService): ITelemetryExperiments {
const random1 = getExperimentsRandomness(storageService);
const [random2, /* showTaskDocumentation */] = splitRandom(random1);
const [random3, /* openUntitledFile */] = splitRandom(random2);
const [random4, mergeQuickLinks] = splitRandom(random3);
// tslint:disable-next-line:no-unused-variable (https://github.com/Microsoft/TypeScript/issues/16628)
const [random5, /* enableWelcomePage */] = splitRandom(random4);
return {
mergeQuickLinks,
};
}
function getExperimentsRandomness(storageService: IStorageService) {
const key = 'experiments.randomness';
let valueString = storageService.get(key);
if (!valueString) {
valueString = Math.random().toString();
storageService.store(key, valueString);
}
return parseFloat(valueString);
}
function splitRandom(random: number): [number, boolean] {
const scaled = random * 2;
const i = Math.floor(scaled);
return [scaled - i, i === 1];
}
function getExperimentsOverrides(configurationService: IConfigurationService): ITelemetryExperiments {
const config: any = configurationService.getConfiguration('telemetry');
return config && config.experiments || {};
}
export interface ITelemetryAppender {
log(eventName: string, data: any): void;
}

View File

@@ -6,7 +6,7 @@
import { notImplemented } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITelemetryService, ITelemetryInfo, ITelemetryExperiments } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { MainContext, MainThreadTelemetryShape } from './extHost.protocol';
@@ -26,10 +26,6 @@ export class RemoteTelemetryService implements ITelemetryService {
throw notImplemented();
}
getExperiments(): ITelemetryExperiments {
throw notImplemented();
}
getTelemetryInfo(): TPromise<ITelemetryInfo> {
return this._proxy.$getTelemetryInfo();
}

View File

@@ -22,7 +22,8 @@ import pkg from 'vs/platform/node/package';
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
import { Workbench, IWorkbenchStartedInfo } from 'vs/workbench/electron-browser/workbench';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService, configurationTelemetry, loadExperiments, lifecycleTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import { NullTelemetryService, configurationTelemetry, lifecycleTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import { loadExperiments } from 'vs/platform/telemetry/common/experiments';
import { ITelemetryAppenderChannel, TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { IdleMonitor, UserStatus } from 'vs/platform/telemetry/browser/idleMonitor';
@@ -218,7 +219,7 @@ export class WorkbenchShell {
customKeybindingsCount: info.customKeybindingsCount,
theme: this.themeService.getColorTheme().id,
language: platform.language,
experiments: this.telemetryService.getExperiments(),
experiments: loadExperiments(),
pinnedViewlets: info.pinnedViewlets,
restoredViewlet: info.restoredViewlet,
restoredEditors: info.restoredEditors.length,
@@ -287,8 +288,7 @@ export class WorkbenchShell {
const config: ITelemetryServiceConfig = {
appender: new TelemetryAppenderClient(channel),
commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version),
piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath],
experiments: instantiationService.invokeFunction(loadExperiments)
piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath]
};
const telemetryService = instantiationService.createInstance(TelemetryService, config);
@@ -305,7 +305,6 @@ export class WorkbenchShell {
disposables.push(telemetryService, errorTelemetry, listener, idleMonitor);
} else {
NullTelemetryService._experiments = instantiationService.invokeFunction(loadExperiments);
this.telemetryService = NullTelemetryService;
}

View File

@@ -72,13 +72,6 @@ export default () => `
<li class="showInteractivePlayground"><button data-href="command:workbench.action.showInteractivePlayground"><h3 class="caption">${escape(localize('welcomePage.interactivePlayground', "Interactive playground"))}</h3> <span class="detail">${escape(localize('welcomePage.interactivePlaygroundDescription', "Try essential editor features out in a short walkthrough"))}</span></button></li>
</ul>
</div>
<div class="section quickLinks">
<h2 class="caption">${escape(localize('welcomePage.quickLinks', "Quick links"))}</h2>
<ul>
<li class="keybindingsReference"><button data-href="command:workbench.action.keybindingsReference"><h3 class="caption">${escape(localize('welcomePage.keybindingsReference', "Keyboard shortcuts reference"))}</h3> <span class="detail">${escape(localize('welcomePage.keybindingsReferenceDescription', "A printable PDF with the most common keyboard shortcuts"))}</span></button></li>
<li class="openGlobalSettings"><button data-href="command:workbench.action.openGlobalSettings"><h3 class="caption">${escape(localize('welcomePage.configureSettings', "Configure settings"))}</h3> <span class="detail">${escape(localize('welcomePage.configureSettingsDescription', "Unlock the full power of VS Code by tweaking the settings"))}</span></button></li>
</ul>
</div>
</div>
</div>
</div>

View File

@@ -106,16 +106,6 @@ export class WelcomePageAction extends Action {
}
}
const reorderedQuickLinks = [
'showInterfaceOverview',
'selectTheme',
'showRecommendedKeymapExtensions',
'showCommands',
'keybindingsReference',
'openGlobalSettings',
'showInteractivePlayground',
];
interface ExtensionSuggestion {
name: string;
id: string;
@@ -271,24 +261,6 @@ class WelcomePage {
});
}).then(null, onUnexpectedError);
const customize = container.querySelector('.commands .section.customize');
const learn = container.querySelector('.commands .section.learn');
const quickLinks = container.querySelector('.commands .section.quickLinks');
if (this.telemetryService.getExperiments().mergeQuickLinks) {
const ul = quickLinks.querySelector('ul');
reorderedQuickLinks.forEach(clazz => {
const link = container.querySelector(`.commands .${clazz}`);
if (link) {
ul.appendChild(link);
}
});
customize.remove();
learn.remove();
container.querySelector('.keybindingsReferenceLink').remove();
} else {
quickLinks.remove();
}
this.addExtensionList(container, '.extensionPackList', extensionPacks, extensionPackStrings);
this.addExtensionList(container, '.keymapList', keymapExtensions, keymapStrings);

View File

@@ -11,8 +11,7 @@ import { IWorkspaceContextService, LegacyWorkspace } from 'vs/platform/workspace
import { createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { ISearchService } from 'vs/platform/search/common/search';
import { ITelemetryService, ITelemetryInfo, ITelemetryExperiments } from 'vs/platform/telemetry/common/telemetry';
import { defaultExperiments } from 'vs/platform/telemetry/common/telemetryUtils';
import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import * as minimist from 'minimist';
@@ -177,8 +176,4 @@ class TestTelemetryService implements ITelemetryService {
machineId: 'someValue.machineId'
});
}
public getExperiments(): ITelemetryExperiments {
return defaultExperiments;
}
};

View File

@@ -12,8 +12,7 @@ import { IWorkspaceContextService, LegacyWorkspace } from 'vs/platform/workspace
import { createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { ISearchService, IQueryOptions } from 'vs/platform/search/common/search';
import { ITelemetryService, ITelemetryInfo, ITelemetryExperiments } from 'vs/platform/telemetry/common/telemetry';
import { defaultExperiments } from 'vs/platform/telemetry/common/telemetryUtils';
import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import * as minimist from 'minimist';
@@ -166,8 +165,4 @@ class TestTelemetryService implements ITelemetryService {
machineId: 'someValue.machineId'
});
}
public getExperiments(): ITelemetryExperiments {
return defaultExperiments;
}
};