Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(feature): knowledge hub Telemetry Setup #68

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
ef57919
chore: telemetry setup
aakankshagupta1994 Apr 13, 2023
7f65078
chore: telemetry setup
aakankshagupta1994 Apr 17, 2023
fd152cf
chore: telemetry changes for tutorials
aakankshagupta1994 Apr 17, 2023
ed457a0
chore: lint changes
aakankshagupta1994 Apr 17, 2023
e8cb3e4
chore: removed action-map file
aakankshagupta1994 Apr 17, 2023
bf12dfc
chore: updated pipeline.yml
aakankshagupta1994 Apr 18, 2023
b84b920
chore: open tutorial broswer-telemetry.ts file
aakankshagupta1994 Apr 18, 2023
84a8b53
chore: updated telemetry properties action
aakankshagupta1994 Apr 18, 2023
a4915f4
chore: test telemetry changes
aakankshagupta1994 Apr 18, 2023
39927bd
chore: removed apihost from package.nls.json
aakankshagupta1994 Apr 18, 2023
930a773
Merge remote-tracking branch 'origin/main' into chore/renovate/telemetry
aakankshagupta1994 Apr 18, 2023
ff96ded
chore: added logic for recording blogs
aakankshagupta1994 Apr 18, 2023
b013be5
chore: lint fixes
aakankshagupta1994 Apr 18, 2023
eab2f0c
chore: removed dead code
aakankshagupta1994 Apr 18, 2023
d8def10
chore: updated test-cases
aakankshagupta1994 Apr 24, 2023
172b57f
chore: added test cases
aakankshagupta1994 Apr 24, 2023
98d06ca
Merge remote-tracking branch 'origin/main' into chore/renovate/telemetry
aakankshagupta1994 Apr 25, 2023
59384cf
chore: updated review comments
aakankshagupta1994 Apr 25, 2023
4d67662
chore: other type error fixes
aakankshagupta1994 Apr 25, 2023
2ed54ac
chore: lint fix
aakankshagupta1994 Apr 25, 2023
3777116
chore: added test cases
aakankshagupta1994 Apr 25, 2023
b0ce881
chore: review comments fix
aakankshagupta1994 Apr 26, 2023
4bbaa2c
chore: secret logic from .env
aakankshagupta1994 May 8, 2023
1bc47dc
chore: lint fix
aakankshagupta1994 May 8, 2023
2f7e18b
Merge remote-tracking branch 'origin/main' into chore/renovate/telemetry
aakankshagupta1994 May 8, 2023
014783a
chore: updated test-cases
aakankshagupta1994 May 8, 2023
341b4d3
chore: sonar big fix
aakankshagupta1994 May 8, 2023
a1653e6
chore: update dotenv support for telemetry
kranthie-sap May 16, 2023
ff43be0
Merge remote-tracking branch 'origin/main' into chore/renovate/telemetry
aakankshagupta1994 May 16, 2023
b284716
Merge branch 'chore/renovate/telemetry' of https://github.com/SAP/kno…
aakankshagupta1994 May 16, 2023
1726910
chore: updated test-cases
aakankshagupta1994 May 16, 2023
c63a84c
chore: review comments fix
aakankshagupta1994 May 16, 2023
20d1322
chore: installed and updated uuid path
aakankshagupta1994 May 16, 2023
cb17d75
chore: lint fix
aakankshagupta1994 May 16, 2023
3a2cd31
chore: review comments
aakankshagupta1994 May 16, 2023
e2af57a
chore: lint fix
aakankshagupta1994 May 16, 2023
d8e4361
chore: debug texts
aakankshagupta1994 May 16, 2023
5869b17
chore: debug texts
aakankshagupta1994 May 16, 2023
1efd06e
chore: removed debug texts
aakankshagupta1994 May 16, 2023
17ccb55
chore: lint fix
aakankshagupta1994 May 17, 2023
189ae42
chore: added test cases
aakankshagupta1994 May 18, 2023
1727a91
chore: added test cases
aakankshagupta1994 May 18, 2023
98aaa65
feat: refactoring telemetry logic
aakankshagupta1994 Jun 1, 2023
7df3f78
Merge remote-tracking branch 'origin/main' into chore/renovate/telemetry
aakankshagupta1994 Jun 1, 2023
33c2d07
feat: lint fixes
aakankshagupta1994 Jun 1, 2023
cded02d
feat: updated pnpm-lock file
aakankshagupta1994 Jun 1, 2023
3c23be5
feat: lint fix
aakankshagupta1994 Jun 1, 2023
a088ae2
feat: increased test-coverage
aakankshagupta1994 Jun 1, 2023
204b4e0
feat: review comments
aakankshagupta1994 Jun 6, 2023
2818afd
Merge remote-tracking branch 'origin/main' into chore/renovate/telemetry
aakankshagupta1994 Jun 6, 2023
f373855
feat: lint fix
aakankshagupta1994 Jun 6, 2023
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
4 changes: 4 additions & 0 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ jobs:
node-version: ${{ matrix.node-version }}
- name: Install pnpm modules
run: pnpm install
- name: Create a .env file in ide-extension package
run: |
touch packages/ide-extension/.env
echo KHE_TELEMETRY_INSTRUMENTATION_KEY=${{ secrets.INSTRUMENTATION_KEY }} >> packages/ide-extension/.env
- name: Run build
run: pnpm run build
- name: Run linting
Expand Down
30 changes: 15 additions & 15 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "Knowledge Hub extension - Launch Knowledge Hub extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--log=debug", "--extensionDevelopmentPath=${workspaceFolder}/packages/ide-extension/"],
"outFiles": ["${workspaceFolder}/pacakges/ide-extension/dist/**/*.js"],
"preLaunchTask": "extension-watch",
"postDebugTask": "Terminate All Tasks"
},
{
"name": "Knowledge Hub extension - webapp: Run Current Jest File",
"name": "core: Run current jest file",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
Expand All @@ -25,10 +15,20 @@
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
},
"cwd": "${workspaceFolder}/packages/webapp"
"cwd": "${workspaceFolder}/packages/core"
},
{
"name": "Knowledge Hub extension - ide-extension: Run Current Jest File",
"name": "ide-extension: Launch extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--log=debug", "--extensionDevelopmentPath=${workspaceFolder}/packages/ide-extension/"],
"outFiles": ["${workspaceFolder}/pacakges/ide-extension/dist/**/*.js"],
"preLaunchTask": "extension-watch",
"postDebugTask": "Terminate All Tasks"
},
{
"name": "ide-extension: Run current jest file",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
Expand All @@ -41,7 +41,7 @@
"cwd": "${workspaceFolder}/packages/ide-extension"
},
{
"name": "Knowledge Hub extension - core: Run Current Jest File",
"name": "webapp: Run current jest file",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
Expand All @@ -51,7 +51,7 @@
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
},
"cwd": "${workspaceFolder}/packages/core"
"cwd": "${workspaceFolder}/packages/webapp"
}
]
}
2 changes: 1 addition & 1 deletion packages/ide-extension/esbuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const buildConfig = {
'.svg': 'file'
},
platform: 'node',
target: 'node12.22',
target: 'node16.1',
external: [
'vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
],
Expand Down
24 changes: 20 additions & 4 deletions packages/ide-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@
"onCommand:sap.ux.knowledgeHub.openKnowledgeHub"
],
"contributes": {
"configuration": {
"id": "sap.ux.knowledgeHub",
"type": "object",
"title": "%configuration.title%",
"properties": {
"sap.ux.knowledgeHub.telemetryEnabled": {
"type": "boolean",
"description": "%configuration.telemetryEnabled%",
"default": true,
"scope": "window"
}
}
},
"commands": [
{
"command": "sap.ux.knowledgeHub.openKnowledgeHub",
Expand All @@ -55,15 +68,18 @@
"devDependencies": {
"@sap/knowledge-hub-extension-core": "workspace:*",
"@sap/knowledge-hub-extension-types": "workspace:*",
"@types/uuid": "9.0.1",
aakankshagupta1994 marked this conversation as resolved.
Show resolved Hide resolved
"@types/vscode": "1.39.0",
"@vscode/vsce": "2.19.0",
"applicationinsights": "2.5.1",
"axios": "1.3.4",
"dotenv": "16.0.3",
"esbuild": "0.15.12",
"esbuild-plugin-copy": "2.1.0",
"i18next": "22.4.15",
"jsdom": "21.1.0",
"vsce": "2.15.0",
"vscode-uri": "3.0.7",
"axios": "1.3.4",
"qs": "6.11.1"
"qs": "6.11.1",
"vscode-uri": "3.0.7"
},
"galleryBanner": {
"color": "#00195A",
Expand Down
1 change: 1 addition & 0 deletions packages/ide-extension/package.nls.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"knowledgeHub.displayName": "Knowledge Hub extension by SAP",
"knowledgeHub.description": "Knowledge Hub extension by SAP",
"configuration.telemetryEnabled": "If enabled, telemetry events to improve extension quality will be recorded",
"commands.knowledgeHub.category": "SAP",
"commands.knowledgeHub.openKnowledgeHub.title": "Open Knowledge Hub"
}
7 changes: 6 additions & 1 deletion packages/ide-extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import type { ExtensionContext } from 'vscode';
import { KnowledgeHubPanel } from './panels/knowledgeHubPanel';
import { logString } from './logger/logger';
import { initI18n } from './i18n';

import { initTelemetry } from './telemetry';
/**
* Activate function is called by VSCode when the extension gets active.
*
* @param {ExtensionContext} context - context from VSCode
*/
export async function activate(context: ExtensionContext): Promise<void> {
try {
context.subscriptions.push(initTelemetry());
} catch (error) {
logString(`Error during initialization of telemetry: ${(error as Error)?.message}`);
}
// Initialize i18next
await initI18n();

Expand Down
6 changes: 5 additions & 1 deletion packages/ide-extension/src/panels/knowledgeHubPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import type { WebviewPanel, ExtensionContext } from 'vscode';
import { Uri, ViewColumn, window } from 'vscode';
import i18next from 'i18next';

import { RESTART_WEBVIEW } from '@sap/knowledge-hub-extension-types';
import { RESTART_WEBVIEW, LOG_TELEMETRY_EVENT } from '@sap/knowledge-hub-extension-types';

import { MessageHandler } from '../knowledge-hub/messageHandler';
import { AppSession } from '../knowledge-hub/appSession';
import { getHtml, getWebviewUri } from '../utils/web';
import { Storage } from '../utils/storage';
import { errorInstance } from '../utils/error';
import { trackAction } from '../telemetry';

/**
* A class to handle the knowledge hub extension panel.
Expand Down Expand Up @@ -96,6 +97,9 @@ export class KnowledgeHubPanel {
this.panel.dispose();
this.panel = this.createKnowledgeHubWebview();
}
if (action.type === LOG_TELEMETRY_EVENT) {
await trackAction(action);
}
});

return knowledgeHubWebView;
Expand Down
1 change: 1 addition & 0 deletions packages/ide-extension/src/telemetry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { initTelemetry, setCommonProperties, trackAction, trackEvent } from './telemetry';
152 changes: 152 additions & 0 deletions packages/ide-extension/src/telemetry/telemetry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { platform, arch, release } from 'os';
import { env, workspace } from 'vscode';
import type { Disposable } from 'vscode';
import { TelemetryClient } from 'applicationinsights';
import { logString } from '../logger/logger';
import packageJson from '../../package.json';
import type { TelemetryEvent, TelemetryReporter, TelemetryUIEventProps } from './types';
import {
FILTERS_BLOGS_TAGS,
FILTERS_TUTORIALS_TAGS,
OPEN_TUTORIAL,
OPEN_BLOG
} from '@sap/knowledge-hub-extension-types';
import { config as dotenvConfig } from 'dotenv';
import { join } from 'path';
import { v4 as uuidv4 } from 'uuid';

// Telemetry reporter client
let reporter: TelemetryReporter | undefined;

/**
* Initialize telemetry.
*
* @returns - telemetry reporter
*/
export function initTelemetry(): TelemetryReporter {
if (!reporter) {
dotenvConfig({ path: join(__dirname, '../', `.env`) });
const instrumentationKey = process.env.KHE_TELEMETRY_INSTRUMENTATION_KEY;
if (!instrumentationKey) {
logString('Instrumentation key missing in .env file');
}
const enabled = updateTelemetryStatus();
const client = new TelemetryClient(instrumentationKey);
client.channel.setUseDiskRetryCaching(true);
client.context.tags[client.context.keys.userId] = env.machineId;
client.context.tags[client.context.keys.sessionId] = uuidv4();
client.context.tags[client.context.keys.cloudRole] = env.appName;

const disposables: Disposable[] = [];
disposables.push(workspace.onDidChangeConfiguration(() => updateTelemetryStatus()));
reporter = {
client,
enabled,
dispose: () => {
disposables.forEach((d) => d.dispose());
reporter = undefined;
}
};
}
return reporter;
}

/**
* Update the telemetry setting by reading configuration.
*
* @returns - status of telemetry setting, true: enabled; false: disabled
*/
function updateTelemetryStatus(): boolean {
const enabled = !!workspace.getConfiguration('sap.ux.knowledgeHub').get('telemetryEnabled');
if (reporter) {
reporter.enabled = enabled;
}
return enabled;
}

/**
* Set common properties which will be added to every telemetry event.
* If called without properties, all common properties are removed.
*
* @param properties - name/value pair of properties (optional)
* @param properties.ide - development environment VSCODE or SBAS
* @param properties.sbasdevSpace - SBAS devspace
*/
export function setCommonProperties(properties?: { ide: 'VSCODE' | 'SBAS'; sbasdevSpace: string }) {
if (reporter) {
reporter.commonProperties = properties
? {
'cmn.appstudio': properties.ide === 'SBAS' ? 'true' : 'false',
'cmn.devspace': properties.sbasdevSpace,
'cmn.os': platform(),
'cmn.nodeArch': arch(),
'cmn.platformversion': (release() || '').replace(/^(\d+)(\.\d+)?(\.\d+)?(.*)/, '$1$2$3'),
'cmn.extname': packageJson.name,
'cmn.extversion': packageJson.version
}
: undefined;
}
}

/**
* Track an even using telemetry.
*
* @param event - telemetry event
*/
export async function trackEvent(event: TelemetryEvent): Promise<void> {
if (!reporter?.enabled) {
return;
}
try {
const name = `${packageJson.name}/${event.name}`;
const properties = propertyValuesToString({ ...event.properties, ...(reporter.commonProperties || {}) });
reporter.client.trackEvent({ name, properties });
} catch (error) {
logString(`Error sending telemetry event '${event.name}': ${(error as Error).message}`);
}
}

/**
* Map specified redux actions to to telemetry events and track them.
*
* @param action - action that occurred
*/
export async function trackAction(action: any): Promise<void> {
if (!reporter?.enabled) {
return;
}
try {
const properties: TelemetryUIEventProps = {
action: '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one seems unnecessary here.

title: action.title,
primaryTag: action.primaryTag
};

if (action.source === OPEN_TUTORIAL) {
properties.action = typeof FILTERS_TUTORIALS_TAGS;
await trackEvent({ name: 'KHUB_OPEN_TUTORIAL', properties });
} else if (action.source === OPEN_BLOG) {
properties.action = typeof FILTERS_BLOGS_TAGS;
await trackEvent({ name: 'KHUB_OPEN_BLOGS', properties });
}
} catch (error) {
logString(`Error sending telemetry action '${action?.payload?.action?.type}': ${(error as Error).message}`);
}
}

/**
* Ensure all property values are strings. While type TelemetryEventProperties defines the values
* as string | number | any, the call LogTelemetryEvent() throws an exception if a non-string
* property value is passed.
*
* @param properties - key/value map of properties
* @returns - key/value map where all values are strings
*/
function propertyValuesToString(properties: { [key: string]: any }): { [key: string]: string } {
for (const property in properties) {
if (typeof properties[property] !== 'string') {
properties[property] = properties[property].toString();
}
}
return properties;
}
Loading