Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/client/extensionActivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Commands, PYTHON, PYTHON_LANGUAGE, STANDARD_OUTPUT_CHANNEL, UseProposed
import { registerTypes as installerRegisterTypes } from './common/installer/serviceRegistry';
import { traceError } from './common/logger';
import { registerTypes as platformRegisterTypes } from './common/platform/serviceRegistry';
import { IFileSystem } from './common/platform/types';
import { registerTypes as processRegisterTypes } from './common/process/serviceRegistry';
import { registerTypes as commonRegisterTypes } from './common/serviceRegistry';
import {
Expand Down Expand Up @@ -57,6 +58,7 @@ import { registerTypes as providersRegisterTypes } from './providers/serviceRegi
import { activateSimplePythonRefactorProvider } from './providers/simpleRefactorProvider';
import { TerminalProvider } from './providers/terminalProvider';
import { ISortImportsEditingProvider } from './providers/types';
import { setExtensionInstallTelemetryProperties } from './telemetry/extensionInstallTelemetry';
import { registerTypes as commonRegisterTerminalTypes } from './terminals/serviceRegistry';
import { ICodeExecutionManager, ITerminalAutoActivation } from './terminals/types';
import { TEST_OUTPUT_CHANNEL } from './testing/common/constants';
Expand Down Expand Up @@ -104,6 +106,10 @@ async function activateLegacy(
platformRegisterTypes(serviceManager);
processRegisterTypes(serviceManager);

// We need to setup this property before any telemetry is sent
const fs = serviceManager.get<IFileSystem>(IFileSystem);
await setExtensionInstallTelemetryProperties(fs);

const applicationEnv = serviceManager.get<IApplicationEnvironment>(IApplicationEnvironment);
const enableProposedApi = applicationEnv.packageJson.enableProposedApi;
serviceManager.addSingletonInstance<boolean>(UseProposedApi, enableProposedApi);
Expand Down
36 changes: 36 additions & 0 deletions src/client/telemetry/extensionInstallTelemetry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import * as path from 'path';
import { setSharedProperty } from '.';
import { IFileSystem } from '../common/platform/types';
import { EXTENSION_ROOT_DIR } from '../constants';

/**
* Sets shared telemetry property about where the extension was installed from
* currently we only detect installations from the Python coding pack installer.
* Those installations get the 'pythonCodingPack'. Otherwise assume the default
* case as 'MarketPlace'.
*
*/
export async function setExtensionInstallTelemetryProperties(fs: IFileSystem) {
// Look for PythonCodingPack file under `%USERPROFILE%/.vscode/extensions`
// folder. If that file exists treat this extension as installed from coding
// pack.
//
// Use parent of EXTENSION_ROOT_DIR to access %USERPROFILE%/.vscode/extensions
// If you use join (%USERPROFILE%, .vscode, extensions), then if user has both
// ~/.vscode and ~./vscode-insiders, and launches Python extension via VS Code
// insiders, it will look for ~/.vscode/extensions/PythonCodingPack which is
// wrong. This is a rare scenario, and it can be easily avoided by using parent
// of EXTENSION_ROOT_DIR. If you use EXTENSION_ROOT_DIR then, in the case of
// VS Code insiders it will be, ~/.vscode-insiders/extensions/. That folder will
// NOT have PythonCodingPack file and we can treat the insiders case as MarkerPlace.
Comment thread
karthiknadig marked this conversation as resolved.
Resolved
const fileToCheck = path.join(path.dirname(EXTENSION_ROOT_DIR), 'PythonCodingPack');
Comment thread
karthiknadig marked this conversation as resolved.
Resolved
if (await fs.fileExists(fileToCheck)) {
setSharedProperty('installSource', 'pythonCodingPack');
} else {
// We did not file the `PythonCodingPack` file, assume market place install.
setSharedProperty('installSource', 'marketPlace');
}
}
6 changes: 6 additions & 0 deletions src/client/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,12 @@ export interface ISharedPropertyMapping {
* For every DS telemetry we would like to know the type of Notebook Editor used when doing something.
*/
['ds_notebookeditor']: undefined | 'old' | 'custom' | 'native';

/**
* For every telemetry event from the extension we want to make sure we can associate it with install
* source. We took this approach to work around very limiting query performance issues.
*/
['installSource']: undefined | 'marketPlace' | 'pythonCodingPack';
}

// Map all events to their properties
Expand Down
28 changes: 28 additions & 0 deletions src/test/telemetry/extensionInstallTelemetery.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as sinon from 'sinon';
import { anyString, instance, mock, when } from 'ts-mockito';
import { FileSystem } from '../../client/common/platform/fileSystem';
import { IFileSystem } from '../../client/common/platform/types';
import * as Telemetry from '../../client/telemetry';
import { setExtensionInstallTelemetryProperties } from '../../client/telemetry/extensionInstallTelemetry';

suite('Extension Install Telemetry', () => {
let fs: IFileSystem;
let telemetryPropertyStub: sinon.SinonStub;
setup(() => {
fs = mock(FileSystem);
telemetryPropertyStub = sinon.stub(Telemetry, 'setSharedProperty');
});
teardown(() => {
telemetryPropertyStub.restore();
});
test('PythonCodingPack exists', async () => {
when(fs.fileExists(anyString())).thenResolve(true);
await setExtensionInstallTelemetryProperties(instance(fs));
telemetryPropertyStub.calledOnceWithExactly('installSource', 'pythonCodingPack');
});
test('PythonCodingPack does not exists', async () => {
when(fs.fileExists(anyString())).thenResolve(false);
await setExtensionInstallTelemetryProperties(instance(fs));
telemetryPropertyStub.calledOnceWithExactly('installSource', 'markerPlace');
Comment thread
karthiknadig marked this conversation as resolved.
Resolved
});
});