mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-01-15 01:25:42 -05:00
Adds basic telemetry
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
import { commands, Disposable, TextEditor, TextEditorEdit, Uri, window, workspace } from 'vscode';
|
||||
import { BuiltInCommands } from '../constants';
|
||||
import { Telemetry } from '../telemetry';
|
||||
|
||||
export type Commands = 'gitlens.closeUnchangedFiles' | 'gitlens.copyMessageToClipboard' | 'gitlens.copyShaToClipboard' |
|
||||
'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 {
|
||||
Telemetry.trackEvent(this.command);
|
||||
return this.execute(...args);
|
||||
}
|
||||
|
||||
@@ -74,6 +76,7 @@ export abstract class EditorCommand extends Disposable {
|
||||
}
|
||||
|
||||
private _execute(editor: TextEditor, edit: TextEditorEdit, ...args: any[]): any {
|
||||
Telemetry.trackEvent(this.command);
|
||||
return this.execute(editor, edit, ...args);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,4 +31,7 @@ export const WorkspaceState = {
|
||||
GitLensVersion: 'gitlensVersion' as WorkspaceState,
|
||||
RepoPath: 'repoPath' 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';
|
||||
import { Objects } from './system';
|
||||
import { commands, ExtensionContext, extensions, languages, Uri, window, workspace } from 'vscode';
|
||||
import { BlameabilityTracker } from './blameabilityTracker';
|
||||
import { BlameActiveLineController } from './blameActiveLineController';
|
||||
@@ -14,18 +15,20 @@ import { ShowBlameHistoryCommand, ShowFileHistoryCommand } from './commands';
|
||||
import { ShowLastQuickPickCommand, ShowQuickBranchHistoryCommand, ShowQuickCurrentBranchHistoryCommand, ShowQuickCommitDetailsCommand, ShowQuickCommitFileDetailsCommand, ShowQuickFileHistoryCommand, ShowQuickRepoStatusCommand} from './commands';
|
||||
import { ToggleCodeLensCommand } from './commands';
|
||||
import { Keyboard } from './commands';
|
||||
import { IAdvancedConfig, IBlameConfig } from './configuration';
|
||||
import { BuiltInCommands, WorkspaceState } from './constants';
|
||||
import { IConfig } from './configuration';
|
||||
import { ApplicationInsightsKey, BuiltInCommands, ExtensionId, WorkspaceState } from './constants';
|
||||
import { GitContentProvider } from './gitContentProvider';
|
||||
import { Git, GitService } from './gitService';
|
||||
import { GitRevisionCodeLensProvider } from './gitRevisionCodeLensProvider';
|
||||
import { Logger } from './logger';
|
||||
import { Telemetry } from './telemetry';
|
||||
|
||||
// this method is called when your extension is activated
|
||||
export async function activate(context: ExtensionContext) {
|
||||
Logger.configure(context);
|
||||
Telemetry.configure(ApplicationInsightsKey);
|
||||
|
||||
const gitlens = extensions.getExtension('eamodio.gitlens');
|
||||
const gitlens = extensions.getExtension(ExtensionId);
|
||||
const gitlensVersion = gitlens.packageJSON.version;
|
||||
|
||||
// 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, '/');
|
||||
Logger.log(`GitLens(v${gitlensVersion}) active: ${rootPath}`);
|
||||
|
||||
const config = workspace.getConfiguration('gitlens');
|
||||
const gitPath = config.get<IAdvancedConfig>('advanced').git;
|
||||
const config = workspace.getConfiguration('').get<IConfig>('gitlens');
|
||||
const gitPath = config.advanced.git;
|
||||
|
||||
configureCssCharacters(config.get<IBlameConfig>('blame'));
|
||||
configureCssCharacters(config.blame);
|
||||
|
||||
let repoPath: string;
|
||||
try {
|
||||
@@ -59,6 +62,12 @@ export async function activate(context: ExtensionContext) {
|
||||
const gitVersion = Git.gitInfo().version;
|
||||
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);
|
||||
notifyOnNewGitLensVersion(context, gitlensVersion);
|
||||
|
||||
@@ -110,6 +119,8 @@ export async function activate(context: ExtensionContext) {
|
||||
context.subscriptions.push(new ShowQuickFileHistoryCommand(git));
|
||||
context.subscriptions.push(new ShowQuickRepoStatusCommand(git, repoPath));
|
||||
context.subscriptions.push(new ToggleCodeLensCommand(git));
|
||||
|
||||
Telemetry.trackEvent('initialized', Objects.flatten(config, 'config', true));
|
||||
}
|
||||
|
||||
// this method is called when your extension is deactivated
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
import { ExtensionContext, OutputChannel, window, workspace } from 'vscode';
|
||||
import { IAdvancedConfig } from './configuration';
|
||||
import { Telemetry } from './telemetry';
|
||||
|
||||
const ConfigurationName = 'gitlens';
|
||||
const OutputChannelName = 'GitLens';
|
||||
@@ -58,6 +59,8 @@ export class Logger {
|
||||
if (level !== OutputLevel.Silent) {
|
||||
output.appendLine([ex, ...params].join(' '));
|
||||
}
|
||||
|
||||
Telemetry.trackException(ex);
|
||||
}
|
||||
|
||||
static warn(message?: any, ...params: any[]): void {
|
||||
|
||||
@@ -12,4 +12,48 @@ export namespace Objects {
|
||||
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