diff --git a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts index b64192c62d6..b623b9754a0 100644 --- a/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts @@ -8,6 +8,11 @@ import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IUserDataSyncLogService, IUserDataSyncService, SyncStatus, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; + +type AutoSyncTriggerClassification = { + source: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; +}; export class UserDataAutoSyncService extends Disposable implements IUserDataAutoSyncService { @@ -25,6 +30,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto @IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService, @IUserDataSyncLogService private readonly logService: IUserDataSyncLogService, @IAuthenticationTokenService private readonly authTokenService: IAuthenticationTokenService, + @ITelemetryService private readonly telemetryService: ITelemetryService, ) { super(); this.updateEnablement(false, true); @@ -32,7 +38,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this._register(Event.any(authTokenService.onDidChangeToken)(() => this.updateEnablement(true, true))); this._register(Event.any(userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true, true))); this._register(this.userDataSyncEnablementService.onDidChangeEnablement(() => this.updateEnablement(true, false))); - this._register(this.userDataSyncEnablementService.onDidChangeResourceEnablement(() => this.triggerAutoSync())); + this._register(this.userDataSyncEnablementService.onDidChangeResourceEnablement(() => this.triggerAutoSync(['resourceEnablement']))); } private async updateEnablement(stopIfDisabled: boolean, auto: boolean): Promise { @@ -99,7 +105,8 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this.successiveFailures = 0; } - async triggerAutoSync(): Promise { + async triggerAutoSync(sources: string[]): Promise { + sources.forEach(source => this.telemetryService.publicLog2<{ source: string }, AutoSyncTriggerClassification>('sync/triggerAutoSync', { source })); if (this.enabled) { return this.syncDelayer.trigger(() => { this.logService.info('Auto Sync: Triggered.'); diff --git a/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts index 23bd81b6526..79589c43e4f 100644 --- a/src/vs/platform/userDataSync/common/userDataSync.ts +++ b/src/vs/platform/userDataSync/common/userDataSync.ts @@ -278,7 +278,7 @@ export interface IUserDataSyncService { readonly conflictsSources: SyncSource[]; readonly onDidChangeConflicts: Event; - readonly onDidChangeLocal: Event; + readonly onDidChangeLocal: Event; readonly onSyncErrors: Event<[SyncSource, UserDataSyncError][]>; readonly lastSyncTime: number | undefined; @@ -299,7 +299,7 @@ export const IUserDataAutoSyncService = createDecorator; - triggerAutoSync(): Promise; + triggerAutoSync(sources: string[]): Promise; } export const IUserDataSyncUtilService = createDecorator('IUserDataSyncUtilService'); diff --git a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts index 04c8649a703..a2b8c25e64d 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncIpc.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts @@ -86,7 +86,7 @@ export class UserDataAutoSyncChannel implements IServerChannel { call(context: any, command: string, args?: any): Promise { switch (command) { - case 'triggerAutoSync': return this.service.triggerAutoSync(); + case 'triggerAutoSync': return this.service.triggerAutoSync(args[0]); } throw new Error('Invalid call'); } diff --git a/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts index 07203267160..4d0a2619afe 100644 --- a/src/vs/platform/userDataSync/common/userDataSyncService.ts +++ b/src/vs/platform/userDataSync/common/userDataSyncService.ts @@ -34,7 +34,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; - readonly onDidChangeLocal: Event; + readonly onDidChangeLocal: Event; private _conflictsSources: SyncSource[] = []; get conflictsSources(): SyncSource[] { return this._conflictsSources; } @@ -74,7 +74,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ } this._lastSyncTime = this.storageService.getNumber(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL, undefined); - this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal)); + this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeLocal, () => s.source))); } async pull(): Promise { diff --git a/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts index 770865e5e26..6fa694e1d27 100644 --- a/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts +++ b/src/vs/platform/userDataSync/electron-browser/userDataAutoSyncService.ts @@ -8,6 +8,7 @@ import { Event } from 'vs/base/common/event'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { UserDataAutoSyncService as BaseUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataAutoSyncService'; import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @@ -17,15 +18,15 @@ export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @IElectronService electronService: IElectronService, @IUserDataSyncLogService logService: IUserDataSyncLogService, @IAuthenticationTokenService authTokenService: IAuthenticationTokenService, + @ITelemetryService telemetryService: ITelemetryService, ) { - super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService); + super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService, telemetryService); - // Sync immediately if there is a local change. - this._register(Event.debounce(Event.any( - electronService.onWindowFocus, - electronService.onWindowOpen, + this._register(Event.debounce(Event.any( + Event.map(electronService.onWindowFocus, () => 'windowFocus'), + Event.map(electronService.onWindowOpen, () => 'windowOpen'), userDataSyncService.onDidChangeLocal, - ), () => undefined, 500)(() => this.triggerAutoSync())); + ), (last, source) => last ? [...last, source] : [source], 1000)(sources => this.triggerAutoSync(sources))); } } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts index 3caeb60f404..7e035fddbce 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataAutoSyncService.ts @@ -10,6 +10,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { UserDataSyncTrigger } from 'vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @@ -20,15 +21,15 @@ export class UserDataAutoSyncService extends BaseUserDataAutoSyncService { @IAuthenticationTokenService authTokenService: IAuthenticationTokenService, @IInstantiationService instantiationService: IInstantiationService, @IHostService hostService: IHostService, + @ITelemetryService telemetryService: ITelemetryService, ) { - super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService); + super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService, telemetryService); - // Sync immediately if there is a local change. - this._register(Event.debounce(Event.any( - userDataSyncService.onDidChangeLocal, + this._register(Event.debounce(Event.any( + Event.map(hostService.onDidChangeFocus, () => 'windowFocus'), instantiationService.createInstance(UserDataSyncTrigger).onDidTriggerSync, - hostService.onDidChangeFocus - ), () => undefined, 500)(() => this.triggerAutoSync())); + userDataSyncService.onDidChangeLocal, + ), (last, source) => last ? [...last, source] : [source], 1000)(sources => this.triggerAutoSync(sources))); } } diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 0a54cd4b5b4..8bf9147ddcb 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -163,7 +163,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo this.registerActions(); this.initializeActiveAccount().then(_ => { if (!isWeb) { - this._register(instantiationService.createInstance(UserDataSyncTrigger).onDidTriggerSync(() => userDataAutoSyncService.triggerAutoSync())); + this._register(instantiationService.createInstance(UserDataSyncTrigger).onDidTriggerSync(source => userDataAutoSyncService.triggerAutoSync([source]))); } }); diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts index 43b93c20ab2..1642cd210a4 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts @@ -16,8 +16,8 @@ import { IViewlet } from 'vs/workbench/common/viewlet'; export class UserDataSyncTrigger extends Disposable { - private readonly _onDidTriggerSync: Emitter = this._register(new Emitter()); - readonly onDidTriggerSync: Event = this._onDidTriggerSync.event; + private readonly _onDidTriggerSync: Emitter = this._register(new Emitter()); + readonly onDidTriggerSync: Event = this._onDidTriggerSync.event; constructor( @IEditorService editorService: IEditorService, @@ -25,37 +25,44 @@ export class UserDataSyncTrigger extends Disposable { @IViewletService viewletService: IViewletService, ) { super(); - this._register(Event.debounce(Event.any( - Event.filter(editorService.onDidActiveEditorChange, () => this.isUserDataEditorInput(editorService.activeEditor)), - Event.filter(viewletService.onDidViewletOpen, viewlet => this.isUserDataViewlet(viewlet)) - ), () => undefined, 500)(() => this._onDidTriggerSync.fire())); + this._register(Event.any( + Event.map(editorService.onDidActiveEditorChange, () => this.getUserDataEditorInputSource(editorService.activeEditor)), + Event.map(viewletService.onDidViewletOpen, viewlet => this.getUserDataViewletSource(viewlet)) + )(source => { + if (source) { + this._onDidTriggerSync.fire(source); + } + })); } - private isUserDataViewlet(viewlet: IViewlet): boolean { - return viewlet.getId() === VIEWLET_ID; + private getUserDataViewletSource(viewlet: IViewlet): string | undefined { + if (viewlet.getId() === VIEWLET_ID) { + return 'extensionsViewlet'; + } + return undefined; } - private isUserDataEditorInput(editorInput: IEditorInput | undefined): boolean { + private getUserDataEditorInputSource(editorInput: IEditorInput | undefined): string | undefined { if (!editorInput) { - return false; + return undefined; } if (editorInput instanceof SettingsEditor2Input) { - return true; + return 'settingsEditor'; } if (editorInput instanceof PreferencesEditorInput) { - return true; + return 'settingsEditor'; } if (editorInput instanceof KeybindingsEditorInput) { - return true; + return 'keybindingsEditor'; } const resource = editorInput.resource; if (isEqual(resource, this.workbenchEnvironmentService.settingsResource)) { - return true; + return 'settingsEditor'; } if (isEqual(resource, this.workbenchEnvironmentService.keybindingsResource)) { - return true; + return 'keybindingsEditor'; } - return false; + return undefined; } } diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts index 4dc5de8bc46..88ee0dcb78f 100644 --- a/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataAutoSyncService.ts @@ -24,8 +24,8 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto this.channel = sharedProcessService.getChannel('userDataAutoSync'); } - triggerAutoSync(): Promise { - return this.channel.call('triggerAutoSync'); + triggerAutoSync(sources: string[]): Promise { + return this.channel.call('triggerAutoSync', [sources]); } } diff --git a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts index 2b495a43dc9..b3ec8ffeb95 100644 --- a/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts +++ b/src/vs/workbench/services/userDataSync/electron-browser/userDataSyncService.ts @@ -22,7 +22,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; - get onDidChangeLocal(): Event { return this.channel.listen('onDidChangeLocal'); } + get onDidChangeLocal(): Event { return this.channel.listen('onDidChangeLocal'); } private _conflictsSources: SyncSource[] = []; get conflictsSources(): SyncSource[] { return this._conflictsSources; }