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

Add Dialog / PageView telemetry #2145

Merged
merged 6 commits into from May 5, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion libraries/botbuilder-applicationinsights/package.json
Expand Up @@ -21,7 +21,7 @@
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"dependencies": {
"applicationinsights": "1.2.0",
"applicationinsights": "1.7.5",
"botbuilder-core": "4.1.6",
"cls-hooked": "^4.2.2"
},
Expand Down
Expand Up @@ -6,7 +6,7 @@
* Licensed under the MIT License.
*/
import * as appInsights from 'applicationinsights';
import { Activity, BotTelemetryClient, TelemetryDependency, TelemetryEvent, TelemetryException, TelemetryTrace } from 'botbuilder-core';
import { Activity, BotTelemetryClient, BotPageViewTelemetryClient, TelemetryDependency, TelemetryEvent, TelemetryException, TelemetryTrace, TelemetryPageView } from 'botbuilder-core';
import * as cls from 'cls-hooked';
import * as crypto from 'crypto';
const ns: any = cls.createNamespace('my.request');
Expand Down Expand Up @@ -61,7 +61,7 @@ export const ApplicationInsightsWebserverMiddleware: any = (req: any, res: any,
* myDialog.telemetryClient = appInsightsClient;
* ```
*/
export class ApplicationInsightsTelemetryClient implements BotTelemetryClient {
export class ApplicationInsightsTelemetryClient implements BotTelemetryClient, BotPageViewTelemetryClient {

private client: appInsights.TelemetryClient;
private config: appInsights.Configuration;
Expand Down Expand Up @@ -117,6 +117,10 @@ export class ApplicationInsightsTelemetryClient implements BotTelemetryClient {
this.defaultClient.trackTrace(telemetry as appInsights.Contracts.TraceTelemetry);
}

public trackPageView(telemetry: TelemetryPageView): void {
this.defaultClient.trackPageView(telemetry as appInsights.Contracts.PageViewTelemetry);
}

public flush(): void {
this.defaultClient.flush();
}
Expand Down
42 changes: 40 additions & 2 deletions libraries/botbuilder-core/src/botTelemetryClient.ts
Expand Up @@ -27,6 +27,10 @@ export interface BotTelemetryClient {
flush();
}

export interface BotPageViewTelemetryClient {
trackPageView(telemetry: TelemetryPageView);
}

export interface TelemetryDependency {
dependencyTypeName: string;
target: string;
Expand Down Expand Up @@ -57,11 +61,21 @@ export interface TelemetryTrace {
severityLevel?: Severity;
}

export class NullTelemetryClient implements BotTelemetryClient {
export interface TelemetryPageView {
name: string;
properties?: {[key: string]: string};
metrics?: {[key: string]: number };
}

export class NullTelemetryClient implements BotTelemetryClient, BotPageViewTelemetryClient {

constructor(settings?: any) {
// noop
}

trackPageView(telemetry: TelemetryPageView) {
// noop
}

trackDependency(telemetry: TelemetryDependency) {
// noop
Expand All @@ -74,12 +88,36 @@ export class NullTelemetryClient implements BotTelemetryClient {
trackException(telemetry: TelemetryException) {
// noop
}

trackTrace(telemetry: TelemetryTrace) {
// noop
}

flush() {
// noop
}
}

export function telemetryTrackDialogView(telemetryClient: BotTelemetryClient, dialogName: string, properties?: {[key: string]: any}, metrics?: {[key: string]: number }): void {
if (!clientSupportsTrackDialogView(telemetryClient)) {
throw new TypeError('"telemetryClient" parameter does not have methods trackPageView() or trackTrace()');
}
if (instanceOfBotPageViewTelemetryClient(telemetryClient)) {
telemetryClient.trackPageView({ name: dialogName, properties: properties, metrics: metrics });
}
else {
telemetryClient.trackTrace({ message: 'Dialog View: ' + dialogName, severityLevel: Severity.Information } );
}
}

function instanceOfBotPageViewTelemetryClient(object: any): object is BotPageViewTelemetryClient {
return 'trackPageView' in object;
}

}
function clientSupportsTrackDialogView(client: any): boolean {
if (!client) { return false; }
if (typeof client.trackPageView !== 'function' && typeof client.trackTrace !== 'function') {
return false;
}
return true;
}
46 changes: 46 additions & 0 deletions libraries/botbuilder-core/tests/botTelemetryClient.test.js
@@ -0,0 +1,46 @@
const { ok, strictEqual } = require('assert');
const { Severity, telemetryTrackDialogView } = require('../');

describe('BotTelemetryClient', function() {
this.timeout(3000);

describe('"telemetryTrackDialogView" helper', () => {
it('should call client.trackPageView if it exists', () => {
const testClient = {
trackPageView({ name, properties, metrics }) {
ok(name);
ok(properties);
ok(metrics);
}
};
const testProps = { description: 'value' };
const testMetrics = { duration: 1 };
telemetryTrackDialogView(testClient, 'dialogName', testProps, testMetrics);
});

it('should call client.trackTrace if trackPageView is not supported', () => {
const testClient = {
trackTrace({ message, severityLevel }) {
ok(message);
strictEqual(severityLevel, Severity.Information);
}
};
telemetryTrackDialogView(testClient, 'dialogName');
});

it('should throw TypeError if trackTrace and trackPageView do not exist', () => {
try {
telemetryTrackDialogView(undefined, 'dialogName');
} catch (err) {
strictEqual(err.message, '"telemetryClient" parameter does not have methods trackPageView() or trackTrace()');
}

try {
telemetryTrackDialogView({}, 'dialogName');
} catch (err) {
strictEqual(err.message, '"telemetryClient" parameter does not have methods trackPageView() or trackTrace()');
}

});
});
});
4 changes: 3 additions & 1 deletion libraries/botbuilder-dialogs/src/componentDialog.ts
Expand Up @@ -5,7 +5,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { TurnContext, BotTelemetryClient, NullTelemetryClient } from 'botbuilder-core';
import { BotTelemetryClient, NullTelemetryClient, telemetryTrackDialogView, TurnContext } from 'botbuilder-core';
import { Dialog, DialogInstance, DialogReason, DialogTurnResult, DialogTurnStatus } from './dialog';
import { DialogContext } from './dialogContext';
import { DialogContainer } from './dialogContainer';
Expand Down Expand Up @@ -81,6 +81,8 @@ export class ComponentDialog<O extends object = {}> extends DialogContainer<O> {
public async beginDialog(outerDC: DialogContext, options?: O): Promise<DialogTurnResult> {
await this.checkForVersionChange(outerDC);

telemetryTrackDialogView(this.telemetryClient, this.id);

// Start the inner dialog.
const innerDC: DialogContext = this.createChildContext(outerDC)
const turnResult: DialogTurnResult<any> = await this.onBeginDialog(innerDC, options);
Expand Down
6 changes: 4 additions & 2 deletions libraries/botbuilder-dialogs/src/waterfallDialog.ts
Expand Up @@ -5,8 +5,8 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { ActivityTypes } from 'botbuilder-core';
import { TurnContext } from 'botbuilder-core';
import { ActivityTypes, Severity } from 'botbuilder-core';
import { TurnContext, telemetryTrackDialogView } from 'botbuilder-core';
import { DialogInstance } from './dialog';
import { Dialog, DialogReason, DialogTurnResult } from './dialog';
import { DialogContext } from './dialogContext';
Expand Down Expand Up @@ -151,6 +151,8 @@ export class WaterfallDialog<O extends object = {}> extends Dialog<O> {
'InstanceId': state.values['instanceId']
}});

telemetryTrackDialogView(this.telemetryClient, this.id);

// Run the first step
return await this.runStep(dc, 0, DialogReason.beginCalled);
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -26,6 +26,7 @@
"@types/lodash": "^4.14.134",
"@typescript-eslint/eslint-plugin": "^1.10.2",
"@typescript-eslint/parser": "^1.10.2",
"applicationinsights": "^1.7.5",
"coveralls": "^3.0.4",
"eslint": "^5.16.0",
"eslint-plugin-only-warn": "^1.0.1",
Expand Down