Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { LuEditor, inlineModePlaceholder } from '@bfc/code-editor';

import { TriggerFormData, TriggerFormDataErrors } from '../../utils/dialogUtil';
import { isRegExRecognizerType, isLUISnQnARecognizerType, isPVARecognizerType } from '../../utils/dialogValidator';
import TelemetryClient from '../../telemetry/TelemetryClient';

import { intentStyles } from './styles';
import { validateEventName, validateIntentName, getLuDiagnostics, validateRegExPattern } from './validators';
Expand Down Expand Up @@ -108,6 +109,7 @@ export function resolveTriggerWidget(
luFeatures: {},
}}
placeholder={inlineModePlaceholder}
telemetryClient={TelemetryClient}
value={formData.triggerPhrases}
onChange={onTriggerPhrasesChange}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ const CodeEditor: React.FC<CodeEditorProps> = (props) => {
path: lspServerPath,
}}
placeholder={defaultQnAPlaceholder}
telemetryClient={TelemetryClient}
value={content}
onChange={onChangeContent}
onChangeSettings={handleSettingsChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { LuFile } from '@bfc/shared';

import { localeState, settingsState } from '../../recoilModel/atoms';
import { userSettingsState, dispatcherState, luFilesSelectorFamily } from '../../recoilModel';
import TelemetryClient from '../../telemetry/TelemetryClient';

import { DiffCodeEditor } from './diff-editor';

Expand Down Expand Up @@ -155,6 +156,7 @@ const CodeEditor: React.FC<CodeEditorProps> = (props) => {
}}
luFile={file}
luOption={luOption}
telemetryClient={TelemetryClient}
value={content}
onChange={onChange}
onChangeSettings={handleSettingsChange}
Expand All @@ -174,6 +176,7 @@ const CodeEditor: React.FC<CodeEditorProps> = (props) => {
options={{
readOnly: true,
}}
telemetryClient={TelemetryClient}
value={defaultLangContent}
onChange={() => {}}
/>
Expand Down
22 changes: 22 additions & 0 deletions Composer/packages/client/src/telemetry/AggregateClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export const AggregateClient = (...loggers) => {
const drain = () => {
loggers.forEach((logger) => logger?.drain());
};

const logPageView = (eventName, url, properties) => {
loggers.forEach((logger) => logger.logPageView(eventName, url, properties));
};

const trackEvent = (eventName, properties) => {
loggers.forEach((logger) => logger.trackEvent(eventName, properties));
};

return {
drain,
logPageView,
trackEvent,
};
};
3 changes: 2 additions & 1 deletion Composer/packages/client/src/telemetry/TelemetryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { LogData, TelemetryEventName, TelemetryEvents, TelemetrySettings } from '@bfc/shared';

import { AggregateClient } from './AggregateClient';
import AppInsightsClient from './AppInsightsClient';
import ConsoleClient from './ConsoleClient';

Expand Down Expand Up @@ -44,7 +45,7 @@ export default class TelemetryClient {
if (process.env.NODE_ENV !== 'development') {
return AppInsightsClient;
} else {
return ConsoleClient;
return AggregateClient(AppInsightsClient, ConsoleClient);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ export const useInitializeLogger = () => {
ipcRenderer?.on('session-update', (_event, name) => {
switch (name) {
case 'session-started':
TelemetryClient.track('SessionStarted', { os: window.navigator.platform });
TelemetryClient.track('SessionStarted', {
os: window.navigator.platform,
height: screen.height,
width: screen.width,
devicePixelRatio: window.devicePixelRatio,
});
break;
case 'session-ended':
TelemetryClient.track('SessionEnded');
Expand Down
12 changes: 9 additions & 3 deletions Composer/packages/electron-server/src/main.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 os from 'os';
import { join, resolve } from 'path';

import { AppUpdaterSettings, UserSettings } from '@bfc/shared';
Expand Down Expand Up @@ -163,9 +164,14 @@ async function loadServer() {
getARMTokenForTenant: OneAuthService.getARMTokenForTenant.bind(OneAuthService),
getTenants: OneAuthService.getTenants.bind(OneAuthService),
logOut: OneAuthService.signOut.bind(OneAuthService),
machineId,
sessionId,
composerVersion: app.getVersion(),
telemetryData: {
composerVersion: app.getVersion(),
machineId,
sessionId,
architecture: os.arch(),
cpus: os.cpus().length,
memory: os.totalmem(),
},
});
log(`Server started at port: ${serverPort}`);
}
Expand Down
12 changes: 9 additions & 3 deletions Composer/packages/lib/code-editor/src/LuEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { LuFile } from '@botframework-composer/types';
import { LuFile, TelemetryClient } from '@botframework-composer/types';
import styled from '@emotion/styled';
import { EditorDidMount, Monaco } from '@monaco-editor/react';
import { FluentTheme, NeutralColors } from '@uifabric/fluent-theme';
Expand Down Expand Up @@ -76,6 +76,7 @@ export interface LULSPEditorProps extends BaseEditorProps {
}
| string;
toolbarHidden?: boolean;
telemetryClient: TelemetryClient;
onNavigateToLuPage?: (luFileId: string, luSectionId?: string) => void;
}

Expand Down Expand Up @@ -135,6 +136,7 @@ const LuEditor: React.FC<LULSPEditorProps> = (props) => {
onInit: onInitProp,
placeholder = defaultPlaceholder,
helpURL = LU_HELP,
telemetryClient,
...restProps
} = props;
const luServer = languageServer || defaultLUServer;
Expand Down Expand Up @@ -239,7 +241,7 @@ const LuEditor: React.FC<LULSPEditorProps> = (props) => {
if (luEdits?.scrollLine) {
editor.revealLineInCenter(luEdits?.scrollLine);
}

telemetryClient.track('LUEditorToolbarEntityDefinitionAdded', { entityType });
editor.focus();
}
}
Expand All @@ -248,11 +250,15 @@ const LuEditor: React.FC<LULSPEditorProps> = (props) => {
);

const insertEntity = useCallback(
(entityName: string) => {
(entityName: string, entityType: string, source: 'toolbar' | 'floatingMenu' = 'toolbar') => {
if (editor) {
const edits = computeInsertLuEntityEdits(entityName, editor);
if (edits) {
editor.executeEdits('toolbarMenu', edits);
telemetryClient.track('LUEditorToolbarEntityTagAdded', {
entityType: entityType !== 'prebuilt' ? entityType : entityName,
source,
});
editor.focus();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const buttonStyles = {
};

type Props = {
onInsertEntity: (entityName: string) => void;
onInsertEntity: (entityName: string, eventType: string) => void;
labelingMenuVisible: boolean;
insertEntityDisabled: boolean;
tagEntityDisabled: boolean;
Expand All @@ -47,7 +47,7 @@ export const InsertEntityButton = React.memo((props: Props) => {
(_, item?: IContextualMenuItem) => {
const entity = item?.data as LuEntity;
if (entity) {
onInsertEntity(entity.Name);
onInsertEntity(entity.Name, entity.Type);
}
},
[onInsertEntity]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type Props = {
luFile?: LuFile;
labelingMenuVisible: boolean;
onDefineEntity: (entityType: ToolbarLuEntityType, entityName?: string) => void;
onInsertEntity: (entityName: string) => void;
onInsertEntity: (entityName: string, entityType: string) => void;
};

export const LuEditorToolbar = React.memo((props: Props) => {
Expand Down
4 changes: 2 additions & 2 deletions Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Props = {
editor: any;
luFile?: LuFile;
onMenuToggled?: (visible: boolean) => void;
onInsertEntity: (entityName: string) => void;
onInsertEntity: (entityName: string, entityType: string, method: 'toolbar' | 'floatingMenu') => void;
};

export const LuLabelingMenu = ({ editor, luFile, onMenuToggled, onInsertEntity }: Props) => {
Expand Down Expand Up @@ -79,7 +79,7 @@ export const LuLabelingMenu = ({ editor, luFile, onMenuToggled, onInsertEntity }
(_, item?: IContextualMenuItem) => {
const entity = item?.data as LuEntity;
if (entity) {
onInsertEntity(entity.Name);
onInsertEntity(entity.Name, entity.Type, 'floatingMenu');
}
setMenuTargetElm(null);
},
Expand Down
24 changes: 20 additions & 4 deletions Composer/packages/server/src/services/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ const getTelemetryContext = () => {
const electronContext = useElectronContext();

if (electronContext) {
const { sessionId, machineId, composerVersion } = electronContext;
const {
telemetryData: { composerVersion, sessionId, machineId, architecture, cpus, memory },
} = electronContext;
const { telemetry = {} } = SettingsService.getSettings();
return { sessionId, userId: machineId, telemetry, composerVersion };
return { sessionId, userId: machineId, telemetry, composerVersion, architecture, cpus, memory };
}

return {};
Expand All @@ -38,8 +40,8 @@ if (instrumentationKey) {
.setAutoCollectRequests(true);
// do not collect the user's machine name
AppInsights.defaultClient.context.tags[AppInsights.defaultClient.context.keys.cloudRoleInstance] = '';
AppInsights.defaultClient.addTelemetryProcessor((envelope: AppInsights.Contracts.Envelope, context): boolean => {
const { sessionId, telemetry, composerVersion, userId } = getTelemetryContext();
AppInsights.defaultClient.addTelemetryProcessor((envelope: AppInsights.Contracts.Envelope): boolean => {
const { sessionId, telemetry, composerVersion, userId, architecture, cpus, memory } = getTelemetryContext();

if (!telemetry?.allowDataCollection) {
return false;
Expand Down Expand Up @@ -70,6 +72,20 @@ if (instrumentationKey) {
data.baseData.properties.composerVersion = composerVersion;
}

if (data.baseData.name === 'SessionStarted') {
if (architecture) {
data.baseData.properties.architecture = architecture;
}

if (cpus !== undefined) {
data.baseData.properties.cpus = cpus;
}

if (memory !== undefined) {
data.baseData.properties.memory = memory;
}
}

// remove PII
for (const property of piiProperties) {
if (data.baseData.properties[property] !== undefined) {
Expand Down
11 changes: 8 additions & 3 deletions Composer/packages/server/src/utility/electronContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ export type ElectronContext = {
getARMTokenForTenant: (tenantId: string) => Promise<string>;
getTenants: () => Promise<AzureTenant[]>;
logOut: () => void;
machineId: string;
sessionId: string;
composerVersion: string;
telemetryData: {
composerVersion: string;
machineId: string;
sessionId: string;
architecture: string;
cpus: number;
memory: number;
};
};

let context;
Expand Down
10 changes: 8 additions & 2 deletions Composer/packages/types/src/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type PackageManagerEvents = {
};

type SessionEvents = {
SessionStarted: { os: string };
SessionStarted: { os: string; height: number; width: number; devicePixelRatio: number };
SessionEnded: undefined;
NavigateTo: { sectionName: string; url: string };
};
Expand Down Expand Up @@ -135,6 +135,11 @@ type LgEditorEvents = {
};
};

type LuEditorEvents = {
LUEditorToolbarEntityTagAdded: { entityType: string; source: 'toolbar' | 'floatingMenu' };
LUEditorToolbarEntityDefinitionAdded: { entityType: string };
};

type WebChatEvents = {
WebChatPaneOpened: undefined;
WebChatPaneClosed: undefined;
Expand Down Expand Up @@ -185,7 +190,8 @@ export type TelemetryEvents = ApplicationEvents &
AppSettingsEvents &
PageView &
LgEditorEvents &
WebChatEvents;
WebChatEvents &
LuEditorEvents;

export type TelemetryEventName = keyof TelemetryEvents;

Expand Down
1 change: 1 addition & 0 deletions Composer/packages/ui-plugins/luis/src/LuisIntentEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const LuisIntentEditor: React.FC<FieldProps<string>> = (props) => {
luFile={luFile}
luOption={{ fileId: luFile.id, sectionId: luIntent.Name, projectId, luFeatures }}
placeholder={placeholder || inlineModePlaceholder}
telemetryClient={shellApi.telemetryClient}
value={luIntent.Body}
onChange={commitChanges}
onChangeSettings={handleSettingsChange}
Expand Down