Skip to content

Commit

Permalink
Runtime log for skills (#7030)
Browse files Browse the repository at this point in the history
  • Loading branch information
srinaath authored Apr 16, 2021
1 parent d3ae3e2 commit ef8eb11
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const BotProjectSettings: React.FC<RouteComponentProps<{ projectId: string; skil

const onRenderHeaderContent = () => {
return formatMessage(
'This Page contains detailed information about your bot. For security reasons, they are hidden by default. To test your bot or publish to Azure, you may need to provide these settings'
'This Page contains detailed information about your bot. For security reasons, they are hidden by default. To test your bot or publish to Azure, you may need to provide these settings.'
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,102 @@
/** @jsx jsx */
import { jsx } from '@emotion/core';
import { Split } from '@geoffcox/react-splitter';
import { useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useRecoilValue } from 'recoil';
import formatMessage from 'format-message';

import { renderThinSplitter } from '../../../../../components/Split/ThinSplitter';
import { rootBotProjectIdSelector } from '../../../../../recoilModel';
import {
botProjectIdsState,
botProjectSpaceLoadedState,
dispatcherState,
rootBotProjectIdSelector,
} from '../../../../../recoilModel';
import { DebugPanelTabHeaderProps } from '../types';
import httpClient from '../../../../../utils/httpUtil';
import { checkIfDotnetVersionMissing, missingDotnetVersionError } from '../../../../../utils/runtimeErrors';
import { BotStartError } from '../../../../../recoilModel/types';
import { Text } from '../../../../../constants';

import { BotProjectsFilter } from './BotProjectsFilter';
import { RuntimeOutputLog } from './RuntimeOutputLog';
import { BotProjectsFilter } from './BotProjectsFilter';

const genericErrorMessage = () => {
return {
message: 'Runtime Log',
summary: formatMessage('Error occurred trying to fetch runtime standard output'),
};
};

export const OutputsTabContent: React.FC<DebugPanelTabHeaderProps> = ({ isActive }) => {
const rootBotId = useRecoilValue(rootBotProjectIdSelector);
const [currentProjectId, setProjectId] = useState(rootBotId ?? '');
const runtimeTrafficChannel = useRef<Record<string, WebSocket> | null>(null);
const projectIds = useRecoilValue(botProjectIdsState);
const { setRuntimeStandardOutputData, setApplicationLevelError } = useRecoilValue(dispatcherState);
const botProjectSolutionLoaded = useRecoilValue(botProjectSpaceLoadedState);

useEffect(() => {
const setupLogConnection = async () => {
projectIds.forEach(async (projectId) => {
try {
const runtimeStreamUrl = await httpClient.get(`/publish/runtimeLogUrl/${projectId}`);

const socket = new WebSocket(runtimeStreamUrl.data);

if (socket) {
socket.onmessage = (event) => {
const data: { standardError: string; standardOutput: string } = JSON.parse(event.data);

let standardError: BotStartError | null = null;
if (data.standardError) {
const isDotnetError = checkIfDotnetVersionMissing({
message: data.standardError ?? '',
});

if (isDotnetError) {
standardError = {
title: Text.DOTNETFAILURE,
...missingDotnetVersionError,
};
} else {
standardError = {
title: Text.BOTRUNTIMEERROR,
message: data.standardError,
};
}
}

setRuntimeStandardOutputData(projectId, {
standardError,
standardOutput: data.standardOutput,
});
};
runtimeTrafficChannel.current = {
...runtimeTrafficChannel.current,
[projectId]: socket,
};
}
} catch (ex) {
setApplicationLevelError(genericErrorMessage());
}
});
};

if (!runtimeTrafficChannel.current && botProjectSolutionLoaded) {
setupLogConnection();
}

return () => {
if (runtimeTrafficChannel.current) {
for (const projectId in runtimeTrafficChannel.current) {
runtimeTrafficChannel.current[projectId].close();
}
}
runtimeTrafficChannel.current = null;
};
}, [botProjectSolutionLoaded]);

return (
<div
css={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,10 @@ import { useRecoilValue } from 'recoil';
import { default as AnsiUp } from 'ansi_up';
import { useEffect, useRef } from 'react';
import sanitizeHtml from 'sanitize-html';
import formatMessage from 'format-message';

import { botBuildTimeErrorState, dispatcherState, runtimeStandardOutputDataState } from '../../../../../recoilModel';
import { botBuildTimeErrorState, runtimeStandardOutputDataState } from '../../../../../recoilModel';
import { getDefaultFontSettings } from '../../../../../recoilModel/utils/fontUtil';
import httpClient from '../../../../../utils/httpUtil';
import { ErrorCallout } from '../../../../../components/BotRuntimeController/ErrorCallout';
import { checkIfDotnetVersionMissing, missingDotnetVersionError } from '../../../../../utils/runtimeErrors';
import { BotStartError } from '../../../../../recoilModel/types';
import { Text } from '../../../../../constants';

const genericErrorMessage = () => {
return {
message: 'Runtime Log',
summary: formatMessage('Error occurred trying to fetch runtime standard output'),
};
};

const ansiUp = new AnsiUp();
const DEFAULT_FONT_SETTINGS = getDefaultFontSettings();
Expand All @@ -35,68 +23,15 @@ const createMarkup = (txt: string) => {
export const RuntimeOutputLog: React.FC<{ projectId: string }> = ({ projectId }) => {
const runtimeData = useRecoilValue(runtimeStandardOutputDataState(projectId));
const botBuildErrors = useRecoilValue(botBuildTimeErrorState(projectId));
const { setRuntimeStandardOutputData, setApplicationLevelError } = useRecoilValue(dispatcherState);

const runtimeLogsContainerRef = useRef<HTMLDivElement | null>(null);

const runtimeTrafficChannel = useRef<WebSocket | null>(null);

useEffect(() => {
if (runtimeLogsContainerRef?.current) {
runtimeLogsContainerRef.current.scrollTop = runtimeLogsContainerRef.current.scrollHeight;
}
}, [runtimeData]);

useEffect(() => {
const setupLogConnection = async () => {
try {
const runtimeStreamUrl = await httpClient.get(`/publish/runtimeLogUrl/${projectId}`);

runtimeTrafficChannel.current = new WebSocket(runtimeStreamUrl.data);

if (runtimeTrafficChannel.current) {
runtimeTrafficChannel.current.onmessage = (event) => {
const data: { standardError: string; standardOutput: string } = JSON.parse(event.data);

let standardError: BotStartError | null = null;
if (data.standardError) {
const isDotnetError = checkIfDotnetVersionMissing({
message: data.standardError ?? '',
});

if (isDotnetError) {
standardError = {
title: Text.DOTNETFAILURE,
...missingDotnetVersionError,
};
} else {
standardError = {
title: Text.BOTRUNTIMEERROR,
message: data.standardError,
};
}
}
setRuntimeStandardOutputData(projectId, {
standardError,
standardOutput: data.standardOutput,
});
};
}
} catch (ex) {
setApplicationLevelError(genericErrorMessage());
}
};

if (!runtimeTrafficChannel.current) {
setupLogConnection();
}

return () => {
runtimeTrafficChannel.current?.close();
runtimeTrafficChannel.current = null;
};
}, []);

return (
<div
ref={runtimeLogsContainerRef}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ import { act } from '@testing-library/react';

import httpClient from '../../../utils/httpUtil';
import { renderWithRecoil } from '../../../../__tests__/testUtils/renderWithRecoil';
import { botBuildTimeErrorState } from '../../../recoilModel';
import { RuntimeOutputLog } from '../DebugPanel/TabExtensions/RuntimeOutputLog/RuntimeOutputLog';
import {
botBuildTimeErrorState,
botProjectIdsState,
botProjectSpaceLoadedState,
projectMetaDataState,
} from '../../../recoilModel';
import { OutputsTabContent } from '../DebugPanel/TabExtensions/RuntimeOutputLog/OutputTabContent';
const projectId = '123-avw';

jest.mock('../../../utils/httpUtil');
Expand All @@ -24,7 +29,7 @@ const standardOut = `/Users/tester/Desktop/conversational_core_3/conversational_
Content root path: /Users/tester/Desktop/conversational_core_3/conversational_core_3
`;

describe('<RuntimeLog />', () => {
describe('<OutputTabContent />', () => {
let mockWSServer;
beforeAll(() => {
const url = `ws://localhost:1234/test/${projectId}`;
Expand All @@ -38,9 +43,17 @@ describe('<RuntimeLog />', () => {
mockWSServer = null;
});

describe('<RuntimeLog />', () => {
describe('<OutputTabContent />', () => {
it('should render Runtime logs', async () => {
const { findByTestId } = renderWithRecoil(<RuntimeOutputLog projectId={projectId} />);
const { findByTestId } = renderWithRecoil(<OutputsTabContent isActive />, ({ set }) => {
set(botProjectIdsState, [projectId]);
set(projectMetaDataState(projectId), {
isRootBot: true,
isRemote: false,
});
set(botProjectSpaceLoadedState, true);
});

await mockWSServer.connected;
act(() => {
const stringified = JSON.stringify({
Expand All @@ -53,7 +66,14 @@ describe('<RuntimeLog />', () => {
});

it('should render Runtime standard errors', async () => {
const { findByText } = renderWithRecoil(<RuntimeOutputLog projectId={projectId} />);
const { findByText } = renderWithRecoil(<OutputsTabContent isActive />, ({ set }) => {
set(botProjectIdsState, [projectId]);
set(projectMetaDataState(projectId), {
isRootBot: true,
isRemote: false,
});
set(botProjectSpaceLoadedState, true);
});
await mockWSServer.connected;
act(() => {
const stringified = JSON.stringify({
Expand All @@ -66,7 +86,13 @@ describe('<RuntimeLog />', () => {
});

it('should render Runtime errors', async () => {
const { findByText } = renderWithRecoil(<RuntimeOutputLog projectId={projectId} />, ({ set }) => {
const { findByText } = renderWithRecoil(<OutputsTabContent isActive />, ({ set }) => {
set(botProjectIdsState, [projectId]);
set(projectMetaDataState(projectId), {
isRootBot: true,
isRemote: false,
});
set(botProjectSpaceLoadedState, true);
set(botBuildTimeErrorState(projectId), {
message: '.NET 3.1 needs to be installed',
title: '.NET runtime error',
Expand Down
6 changes: 3 additions & 3 deletions Composer/packages/electron-server/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@
"initializing_4e34f7d": {
"message": "Initializing..."
},
"learn_more_about_bot_framework_2daca065": {
"message": "Learn More About Bot Framework"
"learn_more_about_bot_framework_f5fe280b": {
"message": "Learn more about Bot Framework"
},
"minimize_4f999e30": {
"message": "Minimize"
Expand Down Expand Up @@ -122,4 +122,4 @@
"zoom_out_dc7d60d2": {
"message": "Zoom Out"
}
}
}

0 comments on commit ef8eb11

Please sign in to comment.