Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
47 changes: 47 additions & 0 deletions src/ariaTelemetryReporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { TelemetryReporter } from '@vscode/extension-telemetry';
import packageJson from '../package.json';

// packageJson is mocked away as null in some tests, so read it defensively.
const packageInfo = packageJson as { publisher?: string; name?: string } | null;
const extensionIdPrefix = packageInfo && packageInfo.publisher && packageInfo.name
? `${packageInfo.publisher}.${packageInfo.name}/`
: '';

// The 1DS collector drops event names containing '/' and rewrites '-' and '.'
// to '_'. VS Code prefixes every gated event with '<publisher>.<name>/', so the
// prefix alone is enough to have an event discarded.
export function sanitizeEventName(eventName: string): string {
const withoutPrefix = eventName.startsWith(extensionIdPrefix)
? eventName.slice(extensionIdPrefix.length)
: eventName;

return withoutPrefix
.replace(/[^a-zA-Z0-9]/g, '_')
.replace(/_{2,}/g, '_')
.replace(/^_+|_+$/g, '')
.slice(0, 98);
}

function sanitizeSenderEventNames(reporter: unknown): void {
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */
const sender = (reporter as any)?.telemetrySender;
if (!sender || typeof sender.sendEventData !== 'function') {
return;
}

const sendEventData = sender.sendEventData.bind(sender) as (eventName: string, data: unknown) => void;
sender.sendEventData = (eventName: string, data: unknown): void => {
sendEventData(sanitizeEventName(eventName), data);
};
/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */
}

export class AriaTelemetryReporter extends TelemetryReporter {
constructor(key: string) {
super(key);
sanitizeSenderEventNames(this);
}
}
3 changes: 2 additions & 1 deletion src/cdpTargetsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { fixRemoteWebSocket, getListOfTargets, getRemoteEndpointSettings, IRemot
import { IncomingMessage } from 'http';
import * as https from 'https';
import { LaunchConfigManager } from './launchConfigManager';
import { sendTaxonomyEvent } from './telemetryTaxonomy';

export class CDPTargetsProvider implements vscode.TreeDataProvider<CDPTarget> {
readonly onDidChangeTreeData: vscode.Event<CDPTarget | null>;
Expand Down Expand Up @@ -60,7 +61,7 @@ export class CDPTargetsProvider implements vscode.TreeDataProvider<CDPTarget> {
}
}
} else {
this.telemetryReporter.sendTelemetryEvent('view/error/no_json_array');
sendTaxonomyEvent(this.telemetryReporter, { area: 'view', feature: 'targets', action: 'list', outcome: 'error', detail: 'no_json_array' });
}

// Sort the targets by type and then title, but keep 'page' types at the top
Expand Down
29 changes: 17 additions & 12 deletions src/devtoolsPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { ErrorReporter } from './errorReporter';
import { ErrorCodes } from './common/errorCodes';
import { ScreencastPanel } from './screencastPanel';
import { providedHeadlessDebugConfig } from './launchConfigManager';
import { sendTaxonomyErrorEvent, sendTaxonomyEvent } from './telemetryTaxonomy';

export class DevToolsPanel {
private readonly config: IRuntimeConfig;
Expand Down Expand Up @@ -192,7 +193,7 @@ export class DevToolsPanel {
if (this.timeStart !== null) {
const timeEnd = performance.now();
const sessionTime = timeEnd - this.timeStart;
this.telemetryReporter.sendTelemetryEvent('websocket/dispose', undefined, {sessionTime});
sendTaxonomyEvent(this.telemetryReporter, { area: 'websocket', feature: 'connection', action: 'dispose' }, undefined, {sessionTime});
this.timeStart = null;
}

Expand All @@ -215,7 +216,7 @@ export class DevToolsPanel {
case 'open':
case 'close':
case 'error':
this.telemetryReporter.sendTelemetryEvent(`websocket/${e}`);
sendTaxonomyEvent(this.telemetryReporter, { area: 'websocket', feature: 'connection', action: e, outcome: e === 'error' ? 'error' : 'success' });
break;
}
if (this.collectConsoleMessages && message && message.includes('Runtime.consoleAPICalled')) {
Expand All @@ -235,8 +236,9 @@ export class DevToolsPanel {

private onSocketReady() {
// Report success telemetry
this.telemetryReporter.sendTelemetryEvent(
this.panelSocket.isConnectedToTarget ? 'websocket/reconnect' : 'websocket/connect');
sendTaxonomyEvent(
this.telemetryReporter,
{ area: 'websocket', feature: 'connection', action: this.panelSocket.isConnectedToTarget ? 'reconnect' : 'connect' });
this.timeStart = performance.now();
}

Expand Down Expand Up @@ -307,8 +309,9 @@ export class DevToolsPanel {
case 'performance': {
const measures: ITelemetryMeasures = {};
measures[`${telemetry.name}.duration`] = telemetry.data;
this.telemetryReporter.sendTelemetryEvent(
`devtools/${telemetry.name}`,
sendTaxonomyEvent(
this.telemetryReporter,
{ area: 'devtools', feature: telemetry.name, action: 'measure' },
undefined,
measures);
break;
Expand All @@ -317,17 +320,19 @@ export class DevToolsPanel {
case 'enumerated': {
const properties: ITelemetryProps = {};
properties[`${telemetry.name}.actionCode`] = telemetry.data.toString();
this.telemetryReporter.sendTelemetryEvent(
`devtools/${telemetry.name}`,
sendTaxonomyEvent(
this.telemetryReporter,
{ area: 'devtools', feature: telemetry.name, action: 'enumerate' },
properties);
break;
}

case 'error': {
const properties: ITelemetryProps = {};
properties[`${telemetry.name}.info`] = JSON.stringify(telemetry.data);
this.telemetryReporter.sendTelemetryErrorEvent(
`devtools/${telemetry.name}`,
sendTaxonomyErrorEvent(
this.telemetryReporter,
{ area: 'devtools', feature: telemetry.name, action: 'report' },
properties);
break;
}
Expand Down Expand Up @@ -377,7 +382,7 @@ export class DevToolsPanel {

private async onSocketOpenInEditor(message: string) {
// Report usage telemetry
this.telemetryReporter.sendTelemetryEvent('extension/openInEditor', {
sendTaxonomyEvent(this.telemetryReporter, { area: 'extension', feature: 'editor', action: 'openInEditor' }, {
sourceMaps: `${this.config.sourceMaps}`,
});

Expand Down Expand Up @@ -461,7 +466,7 @@ export class DevToolsPanel {
this.fallbackChain = this.determineVersionFallback();
} else {
if (this.currentRevision) {
this.telemetryReporter.sendTelemetryEvent('websocket/failedConnection', {revision: this.currentRevision});
sendTaxonomyEvent(this.telemetryReporter, { area: 'websocket', feature: 'connection', action: 'connect', outcome: 'error', detail: 'failedConnection' }, {revision: this.currentRevision});
}

// We failed trying to retrieve the specified revision
Expand Down
Loading
Loading