From a7000885acca69f52a0c7f301a44835f3f8f100e Mon Sep 17 00:00:00 2001 From: Ram Fattah <38049078+ramfattah@users.noreply.github.com> Date: Wed, 23 Mar 2022 17:43:37 -0700 Subject: [PATCH] port: [#4163] log multi-choice options in App Insights (#4164) * bug fix: log multi-choice options in App Insights * unit test --- .../etc/botbuilder-dialogs-adaptive.api.md | 2 + .../src/input/choiceInput.ts | 25 +++++++++ .../src/input/inputDialog.ts | 21 ++++++-- .../tests/choiceInputDialog.test.js | 54 +++++++++++++++++++ 4 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 libraries/botbuilder-dialogs-adaptive/tests/choiceInputDialog.test.js diff --git a/libraries/botbuilder-dialogs-adaptive/etc/botbuilder-dialogs-adaptive.api.md b/libraries/botbuilder-dialogs-adaptive/etc/botbuilder-dialogs-adaptive.api.md index 8add771995..656441172e 100644 --- a/libraries/botbuilder-dialogs-adaptive/etc/botbuilder-dialogs-adaptive.api.md +++ b/libraries/botbuilder-dialogs-adaptive/etc/botbuilder-dialogs-adaptive.api.md @@ -501,6 +501,7 @@ export class ChoiceInput extends InputDialog implements ChoiceInputConfiguration outputFormat: EnumExpression; recognizerOptions?: ObjectExpression; style: EnumExpression; + protected trackGeneratorResultEvent(dc: DialogContext, activityTemplate: TemplateInterface, DialogStateManager>, msg: Partial): void; } // @public (undocumented) @@ -1275,6 +1276,7 @@ export abstract class InputDialog extends Dialog implements InputDialogConfigura prompt: TemplateInterface, DialogStateManager>; property: StringExpression; resumeDialog(dc: DialogContext, _reason: DialogReason, _result?: any): Promise; + protected trackGeneratorResultEvent(dc: DialogContext, activityTemplate: TemplateInterface, DialogStateManager>, msg: Partial): void; // (undocumented) static TURN_COUNT_PROPERTY: string; unrecognizedPrompt: TemplateInterface, DialogStateManager>; diff --git a/libraries/botbuilder-dialogs-adaptive/src/input/choiceInput.ts b/libraries/botbuilder-dialogs-adaptive/src/input/choiceInput.ts index 5b3110c784..8d5f5eeb9e 100644 --- a/libraries/botbuilder-dialogs-adaptive/src/input/choiceInput.ts +++ b/libraries/botbuilder-dialogs-adaptive/src/input/choiceInput.ts @@ -26,11 +26,14 @@ import { Converter, ConverterFactory, DialogContext, + DialogStateManager, FindChoicesOptions, ListStyle, PromptCultureModels, recognizeChoices, + TemplateInterface, } from 'botbuilder-dialogs'; +import { TelemetryLoggerConstants } from '../telemetryLoggerConstants'; export enum ChoiceOutputFormat { value = 'value', @@ -129,6 +132,28 @@ export class ChoiceInput extends InputDialog implements ChoiceInputConfiguration } } + /** + * {@inheritDoc InputDialog.trackGeneratorResultEvent} + */ + protected trackGeneratorResultEvent( + dc: DialogContext, + activityTemplate: TemplateInterface, DialogStateManager>, + msg: Partial + ): void { + const options = dc.state.getValue(ChoiceInput.OPTIONS_PROPERTY); + const properties = { + template: activityTemplate, + result: msg, + choices: options?.choices ? options.choices : '', + context: TelemetryLoggerConstants.InputDialogResultEvent, + }; + + this.telemetryClient.trackEvent({ + name: TelemetryLoggerConstants.GeneratorResultEvent, + properties: properties, + }); + } + /** * @protected * Method which processes options. diff --git a/libraries/botbuilder-dialogs-adaptive/src/input/inputDialog.ts b/libraries/botbuilder-dialogs-adaptive/src/input/inputDialog.ts index 76b101c497..08030ce9ee 100644 --- a/libraries/botbuilder-dialogs-adaptive/src/input/inputDialog.ts +++ b/libraries/botbuilder-dialogs-adaptive/src/input/inputDialog.ts @@ -382,16 +382,31 @@ export abstract class InputDialog extends Dialog implements InputDialogConfigura msg.inputHint = InputHints.ExpectingInput; } + this.trackGeneratorResultEvent(dc, template, msg); + + return msg; + } + + /** + * @protected + * Track GeneratorResultEvent telemetry event with InputDialogResultEvent context. + * @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation. + * @param activityTemplate used to create the Activity. + * @param msg The Partial [Activity](xref:botframework-schema.Activity) which will be sent. + */ + protected trackGeneratorResultEvent( + dc: DialogContext, + activityTemplate: TemplateInterface, DialogStateManager>, + msg: Partial + ): void { this.telemetryClient.trackEvent({ name: TelemetryLoggerConstants.GeneratorResultEvent, properties: { - template: template, + template: activityTemplate, result: msg, context: TelemetryLoggerConstants.InputDialogResultEvent, }, }); - - return msg; } /** diff --git a/libraries/botbuilder-dialogs-adaptive/tests/choiceInputDialog.test.js b/libraries/botbuilder-dialogs-adaptive/tests/choiceInputDialog.test.js new file mode 100644 index 0000000000..65e446c6a1 --- /dev/null +++ b/libraries/botbuilder-dialogs-adaptive/tests/choiceInputDialog.test.js @@ -0,0 +1,54 @@ +const { ok, strictEqual } = require('assert'); +const { createTelemetryClientAndStub } = require('./telemetryUtils'); +const { ConversationState, MemoryStorage, TestAdapter } = require('botbuilder'); +const { DialogManager, DialogSet, ChoicePrompt, ListStyle } = require('botbuilder-dialogs'); +const { ChoiceInput, TelemetryLoggerConstants, ActivityTemplate, ChoiceSet } = require('../lib'); +const { ObjectExpression, BoolExpression } = require('adaptive-expressions'); + +describe('ChoiceInput multi-choices properties', function () { + this.timeout(3000); + let telemetryName; + let telemetryProperties; + const captureTelemetryAction = (eventData) => { + telemetryName = eventData.name; + telemetryProperties = eventData.properties; + }; + // Create telemetryClient and trackEventStub + const [telemetryClient, trackEventStub] = createTelemetryClientAndStub(captureTelemetryAction); + + // Setup dialog manager + const storage = new MemoryStorage(); + const conversationState = new ConversationState(storage); + const dialogState = conversationState.createProperty('dialog'); + const dialogs = new DialogSet(dialogState); + const choicePrompt = new ChoicePrompt('prompt'); + choicePrompt.style = ListStyle.none; + dialogs.add(choicePrompt); + const dm = new DialogManager(); + dm.conversationState = conversationState; + + // Setup inputDialog dialog + const dialog = new ChoiceInput(); + dialog.prompt = new ActivityTemplate('testTemplate'); + dialog.alwaysPrompt = true; + + // set up prompt choices + const choiceSet = new ChoiceSet([{ value: 'test1' }, { value: 'test2' }, { value: 'test3' }]); + dialog.choices = new ObjectExpression(choiceSet); + dialog.alwaysPrompt = new BoolExpression(true); + dialog._telemetryClient = telemetryClient; + dm.rootDialog = dialog; + + it('Log ChoiceInput choices properties', async function () { + // Send initial activity + const adapter = new TestAdapter(async (turnContext) => { + await dm.onTurn(turnContext); + + // assert telemetry result + strictEqual(telemetryName, TelemetryLoggerConstants.GeneratorResultEvent); + strictEqual(telemetryProperties.choices, choiceSet); + ok(trackEventStub.calledOnce); + }); + await adapter.send('test').sendConversationUpdate().startTest(); + }); +});