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

feat: add telemetry around new bot creation #7508

Merged
merged 19 commits into from
Apr 30, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,14 @@ export function CreateBotV2(props: CreateBotProps) {
</div>
</div>
<DialogFooter>
<Link href={templateRequestUrl} styles={{ root: { fontSize: '12px', float: 'left' } }} target="_blank">
<Link
href={templateRequestUrl}
styles={{ root: { fontSize: '12px', float: 'left' } }}
target="_blank"
onClick={() => {
TelemetryClient.track('NeedAnotherTemplateCLicked');
pavolum marked this conversation as resolved.
Show resolved Hide resolved
}}
>
<FontIcon iconName="ChatInviteFriend" style={{ marginRight: '5px' }} />
{formatMessage('Need another template? Send us a request')}
</Link>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import { useRecoilValue } from 'recoil';

import { DialogCreationCopy } from '../../../constants';
import { getAliasFromPayload, isElectron } from '../../../utils/electronUtil';
import { userHasNodeInstalledState } from '../../../recoilModel';
import { creationFlowTypeState, userHasNodeInstalledState } from '../../../recoilModel';
import { InstallDepModal } from '../../InstallDepModal';
import TelemetryClient from '../../../telemetry/TelemetryClient';

import { CreateBotV2 } from './CreateBot';

Expand All @@ -40,6 +41,7 @@ export function CreateOptionsV2(props: CreateOptionsProps) {
const { templates, onDismiss, onNext, onJumpToOpenModal, fetchReadMe } = props;
const [showNodeModal, setShowNodeModal] = useState(false);
const userHasNode = useRecoilValue(userHasNodeInstalledState);
const creationFlowType = useRecoilValue(creationFlowTypeState);

useEffect(() => {
// open bot directly if alias exist.
Expand All @@ -65,6 +67,10 @@ export function CreateOptionsV2(props: CreateOptionsProps) {
return;
}
}
TelemetryClient.track('NewBotDialogOpened', {
isSkillBot: creationFlowType === 'Skill',
fromAbsHandoff: false,
});
setIsOpenCreateModal(true);
}, [props.location?.search]);
const dialogWrapperProps = DialogCreationCopy.CREATE_OPTIONS;
Expand All @@ -89,7 +95,7 @@ export function CreateOptionsV2(props: CreateOptionsProps) {
},
};

const options: IChoiceGroupOption[] = [
const getOptions = (): IChoiceGroupOption[] => [
{ key: 'Create', text: formatMessage('Create a new bot') },
{ key: 'Connect', text: formatMessage('Connect to an existing bot') },
];
Expand All @@ -100,6 +106,10 @@ export function CreateOptionsV2(props: CreateOptionsProps) {

const handleJumpToNext = () => {
if (option === 'Create') {
TelemetryClient.track('NewBotDialogOpened', {
isSkillBot: false,
fromAbsHandoff: true,
});
setIsOpenCreateModal(true);
} else {
onJumpToOpenModal(props.location?.search);
Expand All @@ -121,7 +131,7 @@ export function CreateOptionsV2(props: CreateOptionsProps) {
dialogType={DialogTypes.Customer}
onDismiss={onDismiss}
>
<ChoiceGroup required defaultSelectedKey="B" options={options} onChange={handleChange} />
<ChoiceGroup required defaultSelectedKey="B" options={getOptions()} onChange={handleChange} />
pavolum marked this conversation as resolved.
Show resolved Hide resolved
<DialogFooter>
<PrimaryButton data-testid="NextStepButton" text={formatMessage('Open')} onClick={handleJumpToNext} />
<DefaultButton text={formatMessage('Cancel')} onClick={onDismiss} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ const CreationFlowV2: React.FC<CreationFlowProps> = () => {
path="create/:runtimeLanguage/:templateId"
updateFolder={updateFolder}
onCurrentPathUpdate={updateCurrentPath}
onDismiss={handleDismiss}
onDismiss={() => {
TelemetryClient.track('CreationCancelled');
benbrown marked this conversation as resolved.
Show resolved Hide resolved
handleDismiss();
}}
onSubmit={handleSubmit}
/>
<DefineConversationV2
Expand All @@ -190,14 +193,20 @@ const CreationFlowV2: React.FC<CreationFlowProps> = () => {
path="create/:templateId"
updateFolder={updateFolder}
onCurrentPathUpdate={updateCurrentPath}
onDismiss={handleDismiss}
onDismiss={() => {
TelemetryClient.track('CreationCancelled');
handleDismiss();
}}
onSubmit={handleSubmit}
/>
<CreateOptionsV2
fetchReadMe={fetchReadMe}
path="create"
templates={templateProjects}
onDismiss={handleDismiss}
onDismiss={() => {
TelemetryClient.track('CreationCancelled');
handleDismiss();
}}
onJumpToOpenModal={handleJumpToOpenModal}
onNext={handleCreateNext}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import querystring from 'query-string';
import { FontWeights } from '@uifabric/styling';
import { DialogWrapper, DialogTypes } from '@bfc/ui-shared';
import { useRecoilValue } from 'recoil';
import { csharpFeedKey, functionsRuntimeKey, nodeFeedKey, QnABotTemplateId } from '@bfc/shared';
import { csharpFeedKey, FeedType, functionsRuntimeKey, nodeFeedKey, QnABotTemplateId } from '@bfc/shared';
import { RuntimeType, webAppRuntimeKey } from '@bfc/shared';
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import camelCase from 'lodash/camelCase';
Expand All @@ -29,6 +29,7 @@ import { ImportSuccessNotificationWrapper } from '../../ImportModal/ImportSucces
import { dispatcherState, templateProjectsState } from '../../../recoilModel';
import { LocationSelectContent } from '../LocationSelectContent';
import { getAliasFromPayload, Profile } from '../../../utils/electronUtil';
import TelemetryClient from '../../../telemetry/TelemetryClient';

// -------------------- Styles -------------------- //

Expand Down Expand Up @@ -293,6 +294,12 @@ const DefineConversationV2: React.FC<DefineConversationProps> = (props) => {
dataToSubmit.alias = await getAliasFromPayload(source, payload);
}
}
TelemetryClient.track('creationExecuted', {
pavolum marked this conversation as resolved.
Show resolved Hide resolved
runtimeChoice: dataToSubmit?.runtimeType,
runtimeLanguage: dataToSubmit?.runtimeLanguage as FeedType,
isPva: isImported,
isAbs: !!dataToSubmit?.source,
});
onSubmit({ ...dataToSubmit }, templateId || '');
},
[hasErrors, formData]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ export const PublishProfileDialog: React.FC<PublishProfileDialogProps> = (props)

// require tenant id to be set by plugin (handles multiple tenant scenario)
if (!tenantId) {
TelemetryClient.track('ProvisioningProfileCreateFailure', { message: 'azure tenant not set' });
const notification = createNotification({
type: 'error',
title: formatMessage('Error provisioning.'),
Expand Down
3 changes: 3 additions & 0 deletions Composer/packages/client/src/pages/publish/PublishDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { TextField } from 'office-ui-fabric-react/lib/TextField';
import formatMessage from 'format-message';
import { CheckboxVisibility, DetailsList } from 'office-ui-fabric-react/lib/DetailsList';

import TelemetryClient from '../../telemetry/TelemetryClient';

import { BotStatus } from './type';

export const PublishDialog = (props) => {
Expand Down Expand Up @@ -86,6 +88,7 @@ export const PublishDialog = (props) => {
setShowItems(cleanedItems);
};
const submit = async () => {
TelemetryClient.track('PublishStartBtnClick');
props.onDismiss();
await props.onSubmit(showItems);
cleanComments();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ export const provisionDispatcher = () => {
notification.id
);
} catch (error) {
TelemetryClient.track('ProvisioningProfileCreateFailure', {
message: error.response?.data || 'Error when provision target',
pavolum marked this conversation as resolved.
Show resolved Hide resolved
});

// set notification
const notification = createNotification(
getProvisionFailureNotification(error.response?.data || 'Error when provision target')
Expand Down Expand Up @@ -164,6 +168,9 @@ export const provisionDispatcher = () => {
if (response.data.status !== 500) {
notification = getProvisionPendingNotification(response.data.message);
} else {
TelemetryClient.track('ProvisioningProfileCreateFailure', {
message: response.data.message,
});
notification = getProvisionFailureNotification(response.data.message);
isCleanTimer = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import * as qnaUtil from '../../utils/qnaUtil';
import { ClientStorage } from '../../utils/storage';
import { RuntimeOutputData } from '../types';
import { checkIfFunctionsMissing, missingFunctionsError } from '../../utils/runtimeErrors';
import TelemetryClient from '../../telemetry/TelemetryClient';

import { BotStatus, Text } from './../../constants';
import httpClient from './../../utils/httpUtil';
Expand All @@ -43,6 +44,7 @@ export const publishStorage = new ClientStorage(window.sessionStorage, 'publish'

export const publisherDispatcher = () => {
const publishFailure = async ({ set }: CallbackInterface, title: string, error, target, projectId: string) => {
TelemetryClient.track('PublishFailure', { message: error });
pavolum marked this conversation as resolved.
Show resolved Hide resolved
if (target.name === defaultPublishConfig.name) {
set(botStatusState(projectId), BotStatus.failed);
set(botBuildTimeErrorState(projectId), { ...error, title });
Expand All @@ -59,6 +61,7 @@ export const publisherDispatcher = () => {
};

const publishSuccess = async ({ set }: CallbackInterface, projectId: string, data: PublishResult, target) => {
TelemetryClient.track('PublishSuccess');
const { endpointURL, status } = data;
if (target.name === defaultPublishConfig.name) {
if (status === PUBLISH_SUCCESS && endpointURL) {
Expand Down
27 changes: 24 additions & 3 deletions Composer/packages/server/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@
"add_alternative_phrasing_17e0304c": {
"message": "+ Add alternative phrasing"
},
"add_an_existing_bot_5a9cc5b1": {
"message": "Add an existing bot"
},
"add_app_id_and_password_164e0fdb": {
"message": "Add App ID and Password"
},
Expand Down Expand Up @@ -431,6 +434,12 @@
"azure_functions_5e23be5c": {
"message": "Azure Functions"
},
"azure_functions_required_2a035b48": {
"message": "Azure Functions required"
},
"azure_functions_runtime_not_installed_bc24e100": {
"message": "Azure Functions runtime not installed."
},
"azure_web_app_d834cb4c": {
"message": "Azure Web App"
},
Expand Down Expand Up @@ -698,6 +707,9 @@
"composer_logo_ba2048a0": {
"message": "Composer Logo"
},
"composer_needs_azure_functions_36138382": {
"message": "Composer needs Azure Functions"
},
"composer_needs_net_core_sdk_46e2a8ae": {
"message": "Composer needs .NET Core SDK"
},
Expand Down Expand Up @@ -1910,6 +1922,9 @@
"insert_template_reference_bb33720e": {
"message": "Insert template reference"
},
"install_azure_functions_d607f182": {
"message": "Install Azure Functions"
},
"install_error_a9319839": {
"message": "Install Error"
},
Expand Down Expand Up @@ -2621,6 +2636,9 @@
"onboarding_8407871c": {
"message": "Onboarding"
},
"once_you_publish_your_bot_to_azure_you_will_be_rea_93048067": {
"message": "Once you publish your bot to Azure you will be ready to add connections."
},
"ondialogevents_types_3dc569b5": {
"message": "OnDialogEvents Types"
},
Expand Down Expand Up @@ -2894,6 +2912,9 @@
"publish_to_dev_ops_3b8f5a2f": {
"message": "Publish to Dev Ops"
},
"publish_your_bot_9099e323": {
"message": "Publish your bot"
},
"publish_your_bot_to_azure_and_manage_published_bot_67751ca9": {
"message": "Publish your bot to Azure and manage published bots here."
},
Expand Down Expand Up @@ -3191,9 +3212,6 @@
"save_11a80ec3": {
"message": "Save"
},
"save_as_9e0cf70b": {
"message": "Save as"
},
"save_your_skill_manifest_63bf5f26": {
"message": "Save your skill manifest"
},
Expand Down Expand Up @@ -3833,6 +3851,9 @@
"to_perform_provisioning_and_publishing_actions_com_a2c54389": {
"message": "To perform provisioning and publishing actions, Composer requires access to your Azure and MS Graph accounts. Paste access tokens from the az command line tool using the commands highlighted below."
},
"to_run_this_bot_composer_needs_azure_functions_cor_bbbd0e7": {
"message": "To run this bot, Composer needs Azure Functions Core Tools."
},
"to_run_this_bot_composer_needs_net_core_sdk_d1551038": {
"message": "To run this bot, Composer needs .NET Core SDK."
},
Expand Down
16 changes: 15 additions & 1 deletion Composer/packages/types/src/telemetry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { FeedType, RuntimeType } from './creation';
import { TelemetrySettings } from './settings';

export type ServerSettings = Partial<{ telemetry: TelemetrySettings }>;
Expand Down Expand Up @@ -120,6 +121,10 @@ type ResourcesItem = {
};

type PublishingEvents = {
CreateProvisionStarted: { newResourceGroup: boolean };
PublishStartBtnClick: undefined;
PublishSuccess: undefined;
PublishFailure: { message: string };
NewPublishingProfileStarted: undefined;
NewPublishingProfileSaved: { type: string; msAppId?: string; subscriptionId?: string };
PublishingProfileStarted: { target: string; projectId: string; msAppId?: string; subscriptionId?: string };
Expand All @@ -132,6 +137,14 @@ type PublishingEvents = {
ProvisionCancel: undefined;
ProvisionShowHandoff: undefined;
ProvisionAddResourcesCancel: undefined;
ProvisioningProfileCreateFailure: { message: string };
};

type CreationEvents = {
NewBotDialogOpened: { fromAbsHandoff: boolean; isSkillBot: boolean };
CreationCancelled: undefined;
NeedAnotherTemplateCLicked: undefined;
pavolum marked this conversation as resolved.
Show resolved Hide resolved
creationExecuted: { runtimeChoice: RuntimeType; runtimeLanguage: FeedType; isPva: boolean; isAbs: boolean };
pavolum marked this conversation as resolved.
Show resolved Hide resolved
};

type AppSettingsEvents = {
Expand Down Expand Up @@ -238,7 +251,8 @@ export type TelemetryEvents = ApplicationEvents &
WebChatEvents &
LuEditorEvents &
OrchestratorEvents &
PropertyEditorEvents;
PropertyEditorEvents &
CreationEvents;

export type TelemetryEventName = keyof TelemetryEvents;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,7 @@ export const AzureProvisionDialog: React.FC = () => {
text={formatMessage('Create')}
onClick={() => {
const selectedResources = formData.requiredResources.concat(formData.enabledResources);
telemetryClient?.track('CreateProvisionStarted', { newResourceGroup: isNewResourceGroup });
onSubmit({
tenantId: formData.tenantId,
subscription: formData.subscriptionId,
Expand Down