mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-02-12 02:58:32 -05:00
Adds basic telemetry
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { commands, Disposable, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode';
|
import { commands, Disposable, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode';
|
||||||
import { BuiltInCommands } from '../constants';
|
import { BuiltInCommands } from '../constants';
|
||||||
|
import { Telemetry } from '../telemetry';
|
||||||
|
|
||||||
export type Commands = 'gitlens.closeUnchangedFiles' | 'gitlens.copyMessageToClipboard' | 'gitlens.copyShaToClipboard' |
|
export type Commands = 'gitlens.closeUnchangedFiles' | 'gitlens.copyMessageToClipboard' | 'gitlens.copyShaToClipboard' |
|
||||||
'gitlens.diffDirectory' | 'gitlens.diffWithBranch' | 'gitlens.diffWithNext' | 'gitlens.diffWithPrevious' | 'gitlens.diffLineWithPrevious' | 'gitlens.diffWithWorking' | 'gitlens.diffLineWithWorking' |
|
'gitlens.diffDirectory' | 'gitlens.diffWithBranch' | 'gitlens.diffWithNext' | 'gitlens.diffWithPrevious' | 'gitlens.diffLineWithPrevious' | 'gitlens.diffWithWorking' | 'gitlens.diffLineWithWorking' |
|
||||||
@@ -54,6 +55,7 @@ export abstract class Command extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _execute(...args: any[]): any {
|
protected _execute(...args: any[]): any {
|
||||||
|
Telemetry.trackEvent(this.command);
|
||||||
return this.execute(...args);
|
return this.execute(...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +76,7 @@ export abstract class EditorCommand extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _execute(editor: TextEditor, edit: TextEditorEdit, ...args: any[]): any {
|
private _execute(editor: TextEditor, edit: TextEditorEdit, ...args: any[]): any {
|
||||||
|
Telemetry.trackEvent(this.command);
|
||||||
return this.execute(editor, edit, ...args);
|
return this.execute(editor, edit, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,3 +32,6 @@ export const WorkspaceState = {
|
|||||||
RepoPath: 'repoPath' as WorkspaceState,
|
RepoPath: 'repoPath' as WorkspaceState,
|
||||||
SuppressGitVersionWarning: 'suppressGitVersionWarning' as WorkspaceState
|
SuppressGitVersionWarning: 'suppressGitVersionWarning' as WorkspaceState
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ExtensionId = 'eamodio.gitlens';
|
||||||
|
export const ApplicationInsightsKey = 'a9c302f8-6483-4d01-b92c-c159c799c679';
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
import { Objects } from './system';
|
||||||
import { commands, ExtensionContext, extensions, languages, Uri, window, workspace } from 'vscode';
|
import { commands, ExtensionContext, extensions, languages, Uri, window, workspace } from 'vscode';
|
||||||
import { BlameabilityTracker } from './blameabilityTracker';
|
import { BlameabilityTracker } from './blameabilityTracker';
|
||||||
import { BlameActiveLineController } from './blameActiveLineController';
|
import { BlameActiveLineController } from './blameActiveLineController';
|
||||||
@@ -14,18 +15,20 @@ import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
|||||||
import { ShowLastQuickPickCommand, ShowQuickBranchHistoryCommand, ShowQuickCurrentBranchHistoryCommand, ShowQuickCommitDetailsCommand, ShowQuickCommitFileDetailsCommand, ShowQuickFileHistoryCommand, ShowQuickRepoStatusCommand} from './commands';
|
import { ShowLastQuickPickCommand, ShowQuickBranchHistoryCommand, ShowQuickCurrentBranchHistoryCommand, ShowQuickCommitDetailsCommand, ShowQuickCommitFileDetailsCommand, ShowQuickFileHistoryCommand, ShowQuickRepoStatusCommand} from './commands';
|
||||||
import { ToggleCodeLensCommand } from './commands';
|
import { ToggleCodeLensCommand } from './commands';
|
||||||
import { Keyboard } from './commands';
|
import { Keyboard } from './commands';
|
||||||
import { IAdvancedConfig, IBlameConfig } from './configuration';
|
import { IConfig } from './configuration';
|
||||||
import { BuiltInCommands, WorkspaceState } from './constants';
|
import { ApplicationInsightsKey, BuiltInCommands, ExtensionId, WorkspaceState } from './constants';
|
||||||
import { GitContentProvider } from './gitContentProvider';
|
import { GitContentProvider } from './gitContentProvider';
|
||||||
import { Git, GitService } from './gitService';
|
import { Git, GitService } from './gitService';
|
||||||
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
|
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
|
||||||
import { Logger } from './logger';
|
import { Logger } from './logger';
|
||||||
|
import { Telemetry } from './telemetry';
|
||||||
|
|
||||||
// this method is called when your extension is activated
|
// this method is called when your extension is activated
|
||||||
export async function activate(context: ExtensionContext) {
|
export async function activate(context: ExtensionContext) {
|
||||||
Logger.configure(context);
|
Logger.configure(context);
|
||||||
|
Telemetry.configure(ApplicationInsightsKey);
|
||||||
|
|
||||||
const gitlens = extensions.getExtension('eamodio.gitlens');
|
const gitlens = extensions.getExtension(ExtensionId);
|
||||||
const gitlensVersion = gitlens.packageJSON.version;
|
const gitlensVersion = gitlens.packageJSON.version;
|
||||||
|
|
||||||
// Workspace not using a folder. No access to git repo.
|
// Workspace not using a folder. No access to git repo.
|
||||||
@@ -38,10 +41,10 @@ export async function activate(context: ExtensionContext) {
|
|||||||
const rootPath = workspace.rootPath.replace(/\\/g, '/');
|
const rootPath = workspace.rootPath.replace(/\\/g, '/');
|
||||||
Logger.log(`GitLens(v${gitlensVersion}) active: ${rootPath}`);
|
Logger.log(`GitLens(v${gitlensVersion}) active: ${rootPath}`);
|
||||||
|
|
||||||
const config = workspace.getConfiguration('gitlens');
|
const config = workspace.getConfiguration('').get<IConfig>('gitlens');
|
||||||
const gitPath = config.get<IAdvancedConfig>('advanced').git;
|
const gitPath = config.advanced.git;
|
||||||
|
|
||||||
configureCssCharacters(config.get<IBlameConfig>('blame'));
|
configureCssCharacters(config.blame);
|
||||||
|
|
||||||
let repoPath: string;
|
let repoPath: string;
|
||||||
try {
|
try {
|
||||||
@@ -59,6 +62,12 @@ export async function activate(context: ExtensionContext) {
|
|||||||
const gitVersion = Git.gitInfo().version;
|
const gitVersion = Git.gitInfo().version;
|
||||||
Logger.log(`Git version: ${gitVersion}`);
|
Logger.log(`Git version: ${gitVersion}`);
|
||||||
|
|
||||||
|
const telemetryContext: { [id: string]: any } = Object.create(null);
|
||||||
|
telemetryContext.name = ExtensionId;
|
||||||
|
telemetryContext.version = gitlensVersion;
|
||||||
|
telemetryContext.git_version = gitVersion;
|
||||||
|
Telemetry.setContext(telemetryContext);
|
||||||
|
|
||||||
notifyOnUnsupportedGitVersion(context, gitVersion);
|
notifyOnUnsupportedGitVersion(context, gitVersion);
|
||||||
notifyOnNewGitLensVersion(context, gitlensVersion);
|
notifyOnNewGitLensVersion(context, gitlensVersion);
|
||||||
|
|
||||||
@@ -110,6 +119,8 @@ export async function activate(context: ExtensionContext) {
|
|||||||
context.subscriptions.push(new ShowQuickFileHistoryCommand(git));
|
context.subscriptions.push(new ShowQuickFileHistoryCommand(git));
|
||||||
context.subscriptions.push(new ShowQuickRepoStatusCommand(git, repoPath));
|
context.subscriptions.push(new ShowQuickRepoStatusCommand(git, repoPath));
|
||||||
context.subscriptions.push(new ToggleCodeLensCommand(git));
|
context.subscriptions.push(new ToggleCodeLensCommand(git));
|
||||||
|
|
||||||
|
Telemetry.trackEvent('initialized', Objects.flatten(config, 'config', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method is called when your extension is deactivated
|
// this method is called when your extension is deactivated
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { ExtensionContext, OutputChannel, window, workspace } from 'vscode';
|
import { ExtensionContext, OutputChannel, window, workspace } from 'vscode';
|
||||||
import { IAdvancedConfig } from './configuration';
|
import { IAdvancedConfig } from './configuration';
|
||||||
|
import { Telemetry } from './telemetry';
|
||||||
|
|
||||||
const ConfigurationName = 'gitlens';
|
const ConfigurationName = 'gitlens';
|
||||||
const OutputChannelName = 'GitLens';
|
const OutputChannelName = 'GitLens';
|
||||||
@@ -58,6 +59,8 @@ export class Logger {
|
|||||||
if (level !== OutputLevel.Silent) {
|
if (level !== OutputLevel.Silent) {
|
||||||
output.appendLine([ex, ...params].join(' '));
|
output.appendLine([ex, ...params].join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Telemetry.trackException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static warn(message?: any, ...params: any[]): void {
|
static warn(message?: any, ...params: any[]): void {
|
||||||
|
|||||||
@@ -12,4 +12,48 @@ export namespace Objects {
|
|||||||
yield [key, o[key]];
|
yield [key, o[key]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function flatten(o: any, prefix: string = '', stringify: boolean = false): { [key: string]: any } {
|
||||||
|
let flattened = Object.create(null);
|
||||||
|
_flatten(flattened, prefix, o, stringify);
|
||||||
|
return flattened;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _flatten(flattened: { [key: string]: any }, key: string, value: any, stringify: boolean = false) {
|
||||||
|
if (Object(value) !== value) {
|
||||||
|
if (stringify) {
|
||||||
|
if (value == null) {
|
||||||
|
flattened[key] = null;
|
||||||
|
}
|
||||||
|
else if (typeof value === 'string') {
|
||||||
|
flattened[key] = value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
flattened[key] = JSON.stringify(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
flattened[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Array.isArray(value)) {
|
||||||
|
let len = value.length;
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
_flatten(flattened, `${key}[${i}]`, value[i], stringify);
|
||||||
|
}
|
||||||
|
if (len === 0) {
|
||||||
|
flattened[key] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let isEmpty = true;
|
||||||
|
for (let p in value) {
|
||||||
|
isEmpty = false;
|
||||||
|
_flatten(flattened, key ? `${key}.${p}` : p, value[p], stringify);
|
||||||
|
}
|
||||||
|
if (isEmpty && key) {
|
||||||
|
flattened[key] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
105
src/telemetry.ts
Normal file
105
src/telemetry.ts
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
'use strict';
|
||||||
|
import { Disposable, workspace } from 'vscode';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as appInsights from 'applicationinsights';
|
||||||
|
import * as os from 'os';
|
||||||
|
|
||||||
|
let _reporter: TelemetryReporter;
|
||||||
|
|
||||||
|
export class Telemetry extends Disposable {
|
||||||
|
|
||||||
|
static configure(key: string) {
|
||||||
|
_reporter = new TelemetryReporter(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static setContext(context?: { [key: string]: string }) {
|
||||||
|
_reporter && _reporter.setContext(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static trackEvent(name: string, properties?: { [key: string]: string }, measurements?: { [key: string]: number; }) {
|
||||||
|
_reporter && _reporter.trackEvent(name, properties, measurements);
|
||||||
|
}
|
||||||
|
|
||||||
|
static trackException(ex: Error) {
|
||||||
|
_reporter && _reporter.trackException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TelemetryReporter extends Disposable {
|
||||||
|
|
||||||
|
private _client: typeof appInsights.client;
|
||||||
|
private _context: { [key: string]: string };
|
||||||
|
private _disposable: Disposable;
|
||||||
|
private _enabled: boolean;
|
||||||
|
|
||||||
|
constructor(key: string) {
|
||||||
|
super(() => this.dispose());
|
||||||
|
|
||||||
|
appInsights.setup(key)
|
||||||
|
.setAutoCollectConsole(false)
|
||||||
|
.setAutoCollectExceptions(false)
|
||||||
|
.setAutoCollectPerformance(false)
|
||||||
|
.setAutoCollectRequests(false);
|
||||||
|
|
||||||
|
(appInsights as any).setAutoCollectDependencies(false)
|
||||||
|
.setOfflineMode(true);
|
||||||
|
|
||||||
|
this._client = appInsights.start().client;
|
||||||
|
|
||||||
|
this.setContext();
|
||||||
|
this._stripPII(appInsights.client);
|
||||||
|
|
||||||
|
this._onConfigurationChanged();
|
||||||
|
|
||||||
|
const subscriptions: Disposable[] = [];
|
||||||
|
|
||||||
|
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
|
||||||
|
|
||||||
|
this._disposable = Disposable.from(...subscriptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
this._disposable && this._disposable.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
setContext(context?: { [key: string]: string }) {
|
||||||
|
if (!this._context) {
|
||||||
|
this._context = Object.create(null);
|
||||||
|
|
||||||
|
// Add vscode properties
|
||||||
|
this._context.code_language = vscode.env.language;
|
||||||
|
this._context.code_version = vscode.version;
|
||||||
|
|
||||||
|
// Add os properties
|
||||||
|
this._context.os = os.platform();
|
||||||
|
this._context.os_version = os.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context) {
|
||||||
|
Object.assign(this._context, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this._client.commonProperties, this._context);
|
||||||
|
}
|
||||||
|
|
||||||
|
trackEvent(name: string, properties?: { [key: string]: string }, measurements?: { [key: string]: number; }) {
|
||||||
|
if (!this._enabled) return;
|
||||||
|
this._client.trackEvent(name, properties, measurements);
|
||||||
|
}
|
||||||
|
|
||||||
|
trackException(ex: Error) {
|
||||||
|
if (!this._enabled) return;
|
||||||
|
this._client.trackException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onConfigurationChanged() {
|
||||||
|
this._enabled = workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _stripPII(client: typeof appInsights.client) {
|
||||||
|
if (client && client.context && client.context.keys && client.context.tags) {
|
||||||
|
const machineNameKey = client.context.keys.deviceMachineName;
|
||||||
|
client.context.tags[machineNameKey] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user