diff --git a/src/vs/platform/telemetry/common/telemetry.ts b/src/vs/platform/telemetry/common/telemetry.ts index 568a6e7d050..672a9efa5aa 100644 --- a/src/vs/platform/telemetry/common/telemetry.ts +++ b/src/vs/platform/telemetry/common/telemetry.ts @@ -5,6 +5,9 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; +import { guessMimeTypes } from 'vs/base/common/mime'; +import paths = require('vs/base/common/paths'); +import URI from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -146,4 +149,9 @@ export function anonymize(input: string): string { r += ch; } return r; +} + +export function telemetryURIDescriptor(uri: URI): any { + const fsPath = uri && uri.fsPath; + return fsPath ? { mimeType: guessMimeTypes(fsPath).join(', '), ext: paths.extname(fsPath), path: anonymize(fsPath) } : {}; } \ No newline at end of file diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 2a45200232c..4130c6b7539 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -6,6 +6,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import Event, { Emitter } from 'vs/base/common/event'; +import * as objects from 'vs/base/common/objects'; import types = require('vs/base/common/types'); import URI from 'vs/base/common/uri'; import { IEditor, ICommonCodeEditor, IEditorViewState, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/editorCommon'; @@ -15,6 +16,7 @@ import { IEditorGroupService } from 'vs/workbench/services/group/common/groupSer import { SyncDescriptor, AsyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; import { IModel } from 'vs/editor/common/editorCommon'; +import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetry'; export enum ConfirmResult { SAVE, @@ -199,6 +201,15 @@ export abstract class EditorInput implements IEditorInput { return null; } + /** + * Returns a descriptor suitable for telemetry events or null if none is available. + * + * Subclasses should extend if they can contribute. + */ + public getTelemetryDescriptor(): any { + return { typeId: this.getTypeId() }; + } + /** * Returns a type of EditorModel that represents the resolved input. Subclasses should * override to provide a meaningful model. The optional second argument allows to specify @@ -339,6 +350,12 @@ export abstract class UntitledEditorInput extends EditorInput implements IEncodi abstract getEncoding(): string; abstract setEncoding(encoding: string, mode: EncodingMode): void; + + public getTelemetryDescriptor(): any { + const descriptor = super.getTelemetryDescriptor(); + descriptor.resource = telemetryURIDescriptor(this.getResource()); + return descriptor; + } } /** @@ -378,6 +395,11 @@ export abstract class BaseDiffEditorInput extends EditorInput { public revert(): TPromise { return this._modifiedInput.revert(); } + + public getTelemetryDescriptor(): any { + const descriptor = this._modifiedInput.getTelemetryDescriptor(); + return objects.assign(descriptor, super.getTelemetryDescriptor()); + } } export interface ITextEditorModel extends IEditorModel { diff --git a/src/vs/workbench/common/editor/editorStacksModel.ts b/src/vs/workbench/common/editor/editorStacksModel.ts index 7e3de8c11f3..91f6ff99986 100644 --- a/src/vs/workbench/common/editor/editorStacksModel.ts +++ b/src/vs/workbench/common/editor/editorStacksModel.ts @@ -15,6 +15,7 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { Registry } from 'vs/platform/platform'; import { Position, Direction } from 'vs/platform/editor/common/editor'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; export interface GroupEvent extends IGroupEvent { @@ -693,6 +694,7 @@ export class EditorStacksModel implements IEditorStacksModel { private _onEditorDisposed: Emitter; private _onEditorDirty: Emitter; private _onEditorLabelChange: Emitter; + private _onEditorOpened: Emitter; private _onEditorClosed: Emitter; private _onModelChanged: Emitter; @@ -700,7 +702,8 @@ export class EditorStacksModel implements IEditorStacksModel { private restoreFromStorage: boolean, @IStorageService private storageService: IStorageService, @ILifecycleService private lifecycleService: ILifecycleService, - @IInstantiationService private instantiationService: IInstantiationService + @IInstantiationService private instantiationService: IInstantiationService, + @ITelemetryService private telemetryService: ITelemetryService ) { this.toDispose = []; @@ -717,6 +720,7 @@ export class EditorStacksModel implements IEditorStacksModel { this._onEditorDisposed = new Emitter(); this._onEditorDirty = new Emitter(); this._onEditorLabelChange = new Emitter(); + this._onEditorOpened = new Emitter(); this._onEditorClosed = new Emitter(); this.toDispose.push(this._onGroupOpened, this._onGroupClosed, this._onGroupActivated, this._onGroupDeactivated, this._onGroupMoved, this._onGroupRenamed, this._onModelChanged, this._onEditorDisposed, this._onEditorDirty, this._onEditorLabelChange, this._onEditorClosed); @@ -768,6 +772,10 @@ export class EditorStacksModel implements IEditorStacksModel { return this._onEditorLabelChange.event; } + public get onEditorOpened(): Event { + return this._onEditorOpened.event; + } + public get onEditorClosed(): Event { return this._onEditorClosed.event; } @@ -1093,6 +1101,10 @@ export class EditorStacksModel implements IEditorStacksModel { const unbind: IDisposable[] = []; unbind.push(group.onEditorsStructureChanged(editor => this._onModelChanged.fire({ group, editor, structural: true }))); unbind.push(group.onEditorStateChanged(editor => this._onModelChanged.fire({ group, editor }))); + unbind.push(group.onEditorOpened(editor => { + this.handleOnEditorOpened(editor); + this._onEditorOpened.fire({ editor, group }); + })); unbind.push(group.onEditorClosed(event => { this.handleOnEditorClosed(event); this._onEditorClosed.fire(event); @@ -1109,6 +1121,12 @@ export class EditorStacksModel implements IEditorStacksModel { return group; } + private handleOnEditorOpened(editor: EditorInput): void { + if (this.telemetryService) { + this.telemetryService.publicLog('editorOpened', editor.getTelemetryDescriptor()); + } + } + private handleOnEditorClosed(event: GroupEvent): void { const editor = event.editor; @@ -1125,6 +1143,10 @@ export class EditorStacksModel implements IEditorStacksModel { }); } } + + if (this.telemetryService) { + this.telemetryService.publicLog('editorClosed', editor.getTelemetryDescriptor()); + } } public isOpen(resource: URI): boolean; diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index 0af33cf092b..54a29e1c0f3 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput, ITextEditorModel } from 'vs/workbench/common/editor'; import URI from 'vs/base/common/uri'; +import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetry'; import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; @@ -63,6 +64,12 @@ export class ResourceEditorInput extends EditorInput { } } + public getTelemetryDescriptor(): any { + const descriptor = super.getTelemetryDescriptor(); + descriptor.resource = telemetryURIDescriptor(this.resource); + return descriptor; + } + public resolve(refresh?: boolean): TPromise { // Use Cached Model diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 4d4e2a57d19..2e33f0b686d 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -10,6 +10,7 @@ import { EncodingMode, EditorInput, IFileEditorInput, IWorkbenchEditorConfigurat import { IFilesConfiguration } from 'vs/platform/files/common/files'; import { FileStat } from 'vs/workbench/parts/files/common/explorerViewModel'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { telemetryURIDescriptor } from 'vs/platform/telemetry/common/telemetry'; /** * Explorer viewlet id. @@ -49,6 +50,12 @@ export abstract class FileEditorInput extends EditorInput implements IFileEditor public abstract setEncoding(encoding: string, mode: EncodingMode): void; public abstract getEncoding(): string; + + public getTelemetryDescriptor(): any { + const descriptor = super.getTelemetryDescriptor(); + descriptor.resource = telemetryURIDescriptor(this.getResource()); + return descriptor; + } } export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEditorConfiguration {