Skip to content

Commit b81b11b

Browse files
committed
initial
0 parents  commit b81b11b

26 files changed

+4596
-0
lines changed

.eslintrc.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module.exports = {
2+
parser: "@typescript-eslint/parser",
3+
plugins: ["@typescript-eslint"],
4+
extends: [
5+
"plugin:@typescript-eslint/recommended",
6+
"prettier/@typescript-eslint",
7+
"plugin:prettier/recommended"
8+
],
9+
parserOptions: {
10+
ecmaVersion: 2018,
11+
sourceType: "module"
12+
},
13+
rules: {
14+
"no-console": 2,
15+
"prettier/prettier": "error",
16+
"@typescript-eslint/explicit-member-accessibility": [
17+
2,
18+
{
19+
accessibility: "no-public"
20+
}
21+
],
22+
"@typescript-eslint/no-unused-vars": 2,
23+
"@typescript-eslint/indent": 0,
24+
"@typescript-eslint/interface-name-prefix": 2,
25+
"@typescript-eslint/no-explicit-any": 1,
26+
"@typescript-eslint/interface-name-prefix": 0,
27+
"@typescript-eslint/explicit-function-return-type": "off",
28+
"@typescript-eslint/no-non-null-assertion": "off",
29+
"@typescript-eslint/no-use-before-define": "off"
30+
}
31+
}

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Dependency directory
2+
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
3+
node_modules
4+
5+
**/.DS_Store
6+
*.log

.npmignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.vscode
2+
node_modules
3+
src
4+
.gitignore
5+
.eslintrc.js
6+
tsconfig.json
7+
.prettierrc
8+
jest.config.js
9+
yarn.lock

.prettierrc

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
printWidth: 80
2+
parser: typescript
3+
tabWidth: 4
4+
semi: false

.vscode/settings.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Place your settings in this file to overwrite default and user settings.
2+
{
3+
// Configure glob patterns for excluding files and folders.
4+
"files.exclude": {
5+
"**/.git": true,
6+
"**/.DS_Store": true,
7+
"**/*.js": {"when": "$(basename).ts"}
8+
},
9+
"eslint.enable": false
10+
}

.vscode/tasks.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"version": "0.1.0",
3+
"command": "npm",
4+
"isShellCommand": true,
5+
"args": ["run", "watch"],
6+
"showOutput": "silent",
7+
"isBackground": true,
8+
"problemMatcher": "$tsc-watch"
9+
}

LICENSE

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
vscode-extension-analytics
2+
3+
The MIT License (MIT)
4+
5+
Copyright (c) 2019 Pavel Vlasov.
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.

README.md

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# [vscode-extension-analytics](https://www.npmjs.com/package/vscode-extension-analytics)
2+
This module provides a consistent way for first-party extensions to report analytics and telemetry
3+
with different analytics providers. The module respects the user's decision about whether or
4+
not to send telemetry data.
5+
6+
This module mostly a fork of [vscode-extension-telemetry](https://github.com/Microsoft/vscode-extension-telemetry)
7+
8+
# install
9+
`npm install vscode-extension-analytics`
10+
11+
# usage
12+
```javascript
13+
const vscode = require('vscode');
14+
const {AnalyticsProvider, AnalyticsEvent} = require('vscode-extension-analytics');
15+
16+
// all events will be prefixed with this event name
17+
const extensionId = '<your extension unique name>';
18+
19+
// extension version will be reported as a property with each event
20+
const extensionVersion = '<your extension version>';
21+
22+
// see analytics interface in src/base-client.ts
23+
const client = new AnalyticsClient();
24+
25+
// telemetry reporter
26+
let analyticsProvider;
27+
28+
function activate(context: vscode.ExtensionContext) {
29+
...
30+
// create analytics provider on extension activation
31+
analyticsProvider = new AnalyticsProvider(extensionId, extensionVersion, client);
32+
// ensure it gets property disposed
33+
context.subscriptions.push(analyticsProvider);
34+
...
35+
}
36+
37+
function deactivate() {
38+
// This will ensure all pending events get flushed
39+
analyticsProvider.dispose();
40+
}
41+
42+
...
43+
// send event any time after activation
44+
analyticsProvider.sendEvent(new AnalyticsEvent('opened', {attribute: 'value'}));
45+
46+
```
47+
48+
# common properties
49+
- `common.extname`
50+
- `common.extversion`
51+
- `common.vscodemachineid`
52+
- `common.vscodesessionid`
53+
- `common.vscodeversion`
54+
- `common.os`
55+
- `common.platformversion`
56+
57+
# License
58+
[MIT](LICENSE)

jest.config.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
roots: [
3+
"<rootDir>/src",
4+
],
5+
testMatch: ["**/__tests__/**/?(*.)+(spec|test).+(ts|js)"],
6+
modulePathIgnorePatterns: ["node_modules"],
7+
preset: "ts-jest",
8+
testEnvironment: "node",
9+
moduleNameMapper: {
10+
"vscode": "<rootDir>/src/__mocks__/vscode.js"
11+
}
12+
}

out/analytics.d.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { IAnalyticsClient } from "./base-client";
2+
import { AnalyticsEvent, Exception } from "./events";
3+
export declare class AnalyticsReporter {
4+
private extensionId;
5+
private extensionVersion;
6+
private analyticsClient;
7+
private userOptIn;
8+
private readonly configListener;
9+
private static TELEMETRY_CONFIG_ID;
10+
private static TELEMETRY_CONFIG_ENABLED_ID;
11+
private logStream;
12+
private commonAttributes;
13+
constructor(extensionId: string, extensionVersion: string, client: IAnalyticsClient);
14+
private updateUserOptIn;
15+
private initialiseAnalyticsClient;
16+
private getCommonAttributes;
17+
sendEvent(event: AnalyticsEvent): void;
18+
sendException(exception: Exception): void;
19+
dispose(): Promise<void>;
20+
}

out/analytics.js

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
"use strict";
2+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3+
return new (P || (P = Promise))(function (resolve, reject) {
4+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6+
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7+
step((generator = generator.apply(thisArg, _arguments || [])).next());
8+
});
9+
};
10+
var __generator = (this && this.__generator) || function (thisArg, body) {
11+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13+
function verb(n) { return function (v) { return step([n, v]); }; }
14+
function step(op) {
15+
if (f) throw new TypeError("Generator is already executing.");
16+
while (_) try {
17+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18+
if (y = 0, t) op = [op[0] & 2, t.value];
19+
switch (op[0]) {
20+
case 0: case 1: t = op; break;
21+
case 4: _.label++; return { value: op[1], done: false };
22+
case 5: _.label++; y = op[1]; op = [0]; continue;
23+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
24+
default:
25+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29+
if (t[2]) _.ops.pop();
30+
_.trys.pop(); continue;
31+
}
32+
op = body.call(thisArg, _);
33+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35+
}
36+
};
37+
Object.defineProperty(exports, "__esModule", { value: true });
38+
var fs = require("fs");
39+
var os = require("os");
40+
var path = require("path");
41+
var vscode = require("vscode");
42+
var AnalyticsReporter = /** @class */ (function () {
43+
function AnalyticsReporter(extensionId, extensionVersion, client) {
44+
var _this = this;
45+
this.userOptIn = false;
46+
this.commonAttributes = {};
47+
var logFilePath = process.env["VSCODE_LOGS"] || "";
48+
if (logFilePath &&
49+
extensionId &&
50+
process.env["VSCODE_LOG_LEVEL"] === "trace") {
51+
logFilePath = path.join(logFilePath, extensionId + ".txt");
52+
this.logStream = fs.createWriteStream(logFilePath, {
53+
flags: "a",
54+
encoding: "utf8",
55+
autoClose: true
56+
});
57+
}
58+
this.extensionId = extensionId;
59+
this.extensionVersion = extensionVersion;
60+
this.analyticsClient = client;
61+
this.updateUserOptIn();
62+
this.configListener = vscode.workspace.onDidChangeConfiguration(function () {
63+
return _this.updateUserOptIn();
64+
});
65+
}
66+
AnalyticsReporter.prototype.updateUserOptIn = function () {
67+
var config = vscode.workspace.getConfiguration(AnalyticsReporter.TELEMETRY_CONFIG_ID);
68+
this.userOptIn = config.get(AnalyticsReporter.TELEMETRY_CONFIG_ENABLED_ID, true);
69+
if (this.userOptIn) {
70+
this.initialiseAnalyticsClient();
71+
}
72+
else {
73+
this.dispose();
74+
}
75+
};
76+
AnalyticsReporter.prototype.initialiseAnalyticsClient = function () {
77+
this.commonAttributes = this.getCommonAttributes();
78+
this.analyticsClient.initialise();
79+
};
80+
// __GDPR__COMMON__ "common.os" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
81+
// __GDPR__COMMON__ "common.platformversion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
82+
// __GDPR__COMMON__ "common.extname" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
83+
// __GDPR__COMMON__ "common.extversion" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
84+
// __GDPR__COMMON__ "common.vscodemachineid" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
85+
// __GDPR__COMMON__ "common.vscodesessionid" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
86+
// __GDPR__COMMON__ "common.vscodeversion" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
87+
AnalyticsReporter.prototype.getCommonAttributes = function () {
88+
var commonAttributes = {};
89+
commonAttributes["common.os"] = os.platform();
90+
commonAttributes["common.platformversion"] = (os.release() || "").replace(/^(\d+)(\.\d+)?(\.\d+)?(.*)/, "$1$2$3");
91+
commonAttributes["common.extname"] = this.extensionId;
92+
commonAttributes["common.extversion"] = this.extensionVersion;
93+
if (vscode && vscode.env) {
94+
commonAttributes["common.vscodemachineid"] = vscode.env.machineId;
95+
commonAttributes["common.vscodesessionid"] = vscode.env.sessionId;
96+
commonAttributes["common.vscodeversion"] = vscode.version;
97+
}
98+
return commonAttributes;
99+
};
100+
AnalyticsReporter.prototype.sendEvent = function (event) {
101+
if (this.userOptIn && this.analyticsClient) {
102+
event.update(this.commonAttributes);
103+
this.analyticsClient.sendEvent(event);
104+
if (this.logStream) {
105+
this.logStream.write("telemetry/" + event.getName() + " " + JSON.stringify(event.toJSON()) + "\n");
106+
}
107+
}
108+
};
109+
AnalyticsReporter.prototype.sendException = function (exception) {
110+
if (this.userOptIn) {
111+
exception.update(this.commonAttributes);
112+
this.analyticsClient.sendException(exception);
113+
if (this.logStream) {
114+
this.logStream.write("telemetry/" + exception.getName() + " " + exception.getMessage() + " " + JSON.stringify(exception.toJSON()) + "\n");
115+
}
116+
}
117+
};
118+
AnalyticsReporter.prototype.dispose = function () {
119+
return __awaiter(this, void 0, void 0, function () {
120+
var flushEventsToLogger, flushEventsToAI;
121+
var _this = this;
122+
return __generator(this, function (_a) {
123+
switch (_a.label) {
124+
case 0:
125+
this.configListener.dispose();
126+
flushEventsToLogger = new Promise(function (resolve) {
127+
if (_this.logStream) {
128+
_this.logStream.on("finish", resolve);
129+
_this.logStream.end();
130+
}
131+
else {
132+
return resolve(void 0);
133+
}
134+
});
135+
flushEventsToAI = new Promise(function (resolve) {
136+
if (_this.analyticsClient) {
137+
return _this.analyticsClient.flush();
138+
}
139+
else {
140+
resolve(void 0);
141+
}
142+
});
143+
return [4 /*yield*/, Promise.all([flushEventsToAI, flushEventsToLogger])];
144+
case 1:
145+
_a.sent();
146+
return [2 /*return*/];
147+
}
148+
});
149+
});
150+
};
151+
AnalyticsReporter.TELEMETRY_CONFIG_ID = "telemetry";
152+
AnalyticsReporter.TELEMETRY_CONFIG_ENABLED_ID = "enableTelemetry";
153+
return AnalyticsReporter;
154+
}());
155+
exports.AnalyticsReporter = AnalyticsReporter;

out/base-client.d.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { AnalyticsEvent, Exception } from "./events";
2+
export interface IAnalyticsClient {
3+
initialise(): void;
4+
sendEvent(event: AnalyticsEvent): void;
5+
sendException(exception: Exception): void;
6+
flush(): Promise<void>;
7+
}

out/base-client.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"use strict";
2+
Object.defineProperty(exports, "__esModule", { value: true });

out/events.d.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
declare type Primitive = string | number | null | void;
2+
interface PrimitiveHash {
3+
[key: string]: Primitive;
4+
}
5+
declare type Attribute = Primitive | Primitive[] | PrimitiveHash | PrimitiveHash[];
6+
export interface Attributes {
7+
[key: string]: Attribute;
8+
}
9+
export declare class AnalyticsEvent {
10+
action: string;
11+
attributes: Attributes;
12+
constructor(action: string, attributes: Attributes);
13+
update(attributes: Attributes): void;
14+
getName(): string;
15+
toJSON(): {
16+
action: string;
17+
attributes: Attributes;
18+
};
19+
}
20+
export declare class Exception {
21+
error: Error;
22+
attributes: Attributes;
23+
constructor(error: Error, attributes: Attributes);
24+
update(attributes: Attributes): void;
25+
getName(): string;
26+
getMessage(): string;
27+
toJSON(): {
28+
error: string;
29+
message: string;
30+
attributes: Attributes;
31+
stack: string | undefined;
32+
};
33+
}
34+
export {};

0 commit comments

Comments
 (0)