diff --git a/src/actions/onOpenLogs.ts b/src/actions/onOpenLogs.ts index c440a3c8..33fd45a6 100644 --- a/src/actions/onOpenLogs.ts +++ b/src/actions/onOpenLogs.ts @@ -1,5 +1,5 @@ import * as T from 'typings' -import { showOutput } from '../services/testRunner/output' +import { showOutput } from '../services/logger/output' export const onOpenLogs = async (action: T.Action): Promise => { const channel = action.payload.channel diff --git a/src/actions/onRunReset.ts b/src/actions/onRunReset.ts index 4ae140a2..b82996d8 100644 --- a/src/actions/onRunReset.ts +++ b/src/actions/onRunReset.ts @@ -4,6 +4,7 @@ import Context from '../services/context/context' import reset from '../services/reset' import * as hooks from '../services/hooks' import getCommitHashByPosition from '../services/reset/lastHash' +import logger from '../services/logger' type ResetAction = { type: 'LATEST' | 'POSITION' @@ -22,7 +23,7 @@ const onRunReset = async (action: ResetAction, context: Context): Promise const branch = tutorial?.config.repo.branch if (!branch) { - console.error('No repo branch found for tutorial') + logger('Error: No repo branch found for tutorial') return } diff --git a/src/actions/onTutorialConfigContinue.ts b/src/actions/onTutorialConfigContinue.ts index 1a116c46..5ab560c9 100644 --- a/src/actions/onTutorialConfigContinue.ts +++ b/src/actions/onTutorialConfigContinue.ts @@ -8,7 +8,7 @@ import logger from '../services/logger' import { setupWebhook } from '../services/hooks/webhooks' const onTutorialConfigContinue = async (action: T.Action, context: Context): Promise => { - logger('onTutorialConfigContinue', action) + logger(`Continuing tutorial from progress: ${JSON.stringify(action.payload)}`) try { const tutorialToContinue: TT.Tutorial | null = context.tutorial.get() if (!tutorialToContinue) { diff --git a/src/channel.ts b/src/channel.ts index 994ec658..df896cdf 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -28,7 +28,14 @@ class Channel implements Channel { // action may be an object.type or plain string const actionType: string = typeof action === 'string' ? action : action.type - logger(`EXT RECEIVED: "${actionType}"`) + if (actionType === 'CLIENT_LOG') { + // logs in web client are not easily visible + // it's simpler to log to the "CodeRoad (Logs)" channel + logger(action.payload) + return + } + + logger(actionType) switch (actionType) { case 'EDITOR_STARTUP': diff --git a/src/commands.ts b/src/commands.ts index 4991ba8f..6c805cf5 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -21,15 +21,15 @@ interface CreateCommandProps { } let sendToClient = (action: T.Action): void => { - // function is replaced when webclient loads + // function is replaced when webview mounts } // This makes it easier to pass the send // function throughout the codebase export const send = (action: T.Action): void => { - logger(`EXT TO CLIENT: "${typeof action === 'string' ? action : action.type}"`) - - if (action) sendToClient(action) + // log send of event to client + logger(`${typeof action === 'string' ? action : action.type}`) + sendToClient(action) } export const createCommands = (commandProps: CreateCommandProps): { [key: string]: any } => { @@ -75,7 +75,7 @@ export const createCommands = (commandProps: CreateCommandProps): { [key: string } testRunner = createTestRunner(data, { onSuccess: (position: T.Position) => { - logger('test pass position', position) + logger(`Test pass position: ${JSON.stringify(position)}`) // send test pass message back to client channel.context.position.set({ ...position, complete: true }) send({ type: 'TEST_PASS', payload: { position: { ...position, complete: true } } }) @@ -91,7 +91,7 @@ export const createCommands = (commandProps: CreateCommandProps): { [key: string }, onRun: (position: T.Position) => { // send test run message back to client - send({ type: 'TEST_RUNNING', payload: { position } }) + send({ type: 'START_TEST', payload: { position } }) }, onLoadSubtasks: ({ summary }) => { send({ type: 'LOAD_SUBTASK_RESULTS', payload: { summary } }) diff --git a/src/environment.ts b/src/environment.ts index 65594db1..89393c94 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -10,9 +10,6 @@ export type Env = 'test' | 'local' | 'development' | 'production' // @ts-ignore export const NODE_ENV: Env = process.env.NODE_ENV || 'development' -// toggle logging -export const LOG = (process.env.CODEROAD_ENABLE_LOG || '').toLowerCase() === 'true' - // error logging tool export const INSTRUMENTATION_KEY = '6ff37c76-72f3-48e3-a1b9-d5636f519b7b' diff --git a/src/services/git/index.ts b/src/services/git/index.ts index db2afc62..73895081 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -9,14 +9,14 @@ const stashAllFiles = async (): Promise => { // stash files including untracked (eg. newly created file) const { stderr } = await exec({ command: `git stash --include-untracked` }) if (stderr) { - console.error(stderr) + logger(`Error: ${stderr}`) throw new Error('Error stashing files') } } const cherryPickCommit = async (commit: string, count = 0): Promise => { if (count > 1) { - console.warn('cherry-pick failed') + logger('cherry-pick failed') return } try { @@ -26,8 +26,8 @@ const cherryPickCommit = async (commit: string, count = 0): Promise { export async function saveCommit(message: string): Promise { const { stdout, stderr } = await exec({ command: `git commit -am '${message}'` }) if (stderr) { - console.error(stderr) + logger(`Error: ${stderr}`) throw new Error('Error saving progress to Git') } - logger(['save with commit & continue stdout', stdout]) + logger(`Commit saved: ${stdout}`) } export async function clear(): Promise { @@ -63,9 +63,9 @@ export async function clear(): Promise { if (!stderr) { return } - console.error(stderr) - } catch (error) { - console.error(error) + logger(`Error: ${stderr}`) + } catch (error: any) { + logger(`Error: ${error.message}`) } throw new Error('Error cleaning up current unsaved work') } @@ -127,7 +127,7 @@ export async function addRemote(repo: string): Promise { // validate the response is acceptable if (!alreadyExists && !successfulNewBranch) { - console.error(stderr) + logger(`Error: ${stderr}`) throw new Error('Error adding git remote') } } @@ -142,7 +142,8 @@ export async function checkRemoteExists(): Promise { // string match on remote output // TODO improve the specificity of this regex return !!stdout.match(gitOrigin) - } catch (error) { + } catch (error: any) { + logger(`Warn: ${error.message}`) return false } } @@ -168,8 +169,9 @@ export async function loadCommitHistory(): Promise { } // string match on remote output return stdout.split('\n') - } catch (error) { + } catch (error: any) { // likely no git setup or no commits + logger(`Warn: ${error.message}`) return [] } } @@ -189,8 +191,8 @@ export async function getCommitMessage(hash: string): Promise { } // string match on remote output return stdout - } catch (error) { - logger('error', error) + } catch (error: any) { + logger(`Error: ${error.message}`) // likely no git commit message found return null } @@ -204,8 +206,8 @@ export async function commitsExistsByMessage(message: string): Promise return false } return !!stdout.length - } catch (error) { - logger('error', error) + } catch (error: any) { + logger(`Error: ${error.message}`) // likely no commit found return false } diff --git a/src/services/hooks/utils/openFiles.ts b/src/services/hooks/utils/openFiles.ts index 592f14ff..d76d5211 100644 --- a/src/services/hooks/utils/openFiles.ts +++ b/src/services/hooks/utils/openFiles.ts @@ -1,5 +1,6 @@ import { join } from 'path' import * as vscode from 'vscode' +import logger from '../../logger' const openFiles = async (files: string[] = []): Promise => { if (!files.length) { @@ -16,7 +17,7 @@ const openFiles = async (files: string[] = []): Promise => { const doc = await vscode.workspace.openTextDocument(absoluteFilePath) await vscode.window.showTextDocument(doc, vscode.ViewColumn.One) } catch (error: any) { - console.log(`Failed to open file ${filePath}: ${error.message}`) + logger(`Failed to open file ${filePath}: ${error.message}`) } } } diff --git a/src/services/hooks/utils/runCommands.ts b/src/services/hooks/utils/runCommands.ts index a462d8b8..c7bd2cde 100644 --- a/src/services/hooks/utils/runCommands.ts +++ b/src/services/hooks/utils/runCommands.ts @@ -1,5 +1,6 @@ import { exec } from '../../node' import { send } from '../../../commands' +import logger from '../../logger' const runCommands = async (commands: string[] = []): Promise => { if (!commands.length) { @@ -14,9 +15,9 @@ const runCommands = async (commands: string[] = []): Promise => { let result: { stdout: string; stderr: string } try { result = await exec({ command }) - console.log(result) + logger(`Command output: ${JSON.stringify(result)}`) } catch (error: any) { - console.error(`Command failed: ${error.message}`) + logger(`Command failed: ${error.message}`) send({ type: 'COMMAND_FAIL', payload: { process: { ...process, status: 'FAIL' } } }) return } diff --git a/src/services/logger/index.ts b/src/services/logger/index.ts index 3e57e525..03f1e189 100644 --- a/src/services/logger/index.ts +++ b/src/services/logger/index.ts @@ -1,18 +1,15 @@ -import { LOG } from '../../environment' +import { getOutputChannel } from './output' export type Log = any +const logChannel = getOutputChannel('CodeRoad (Logs)') + const logger = (...messages: Log[]): void => { - if (!LOG) { - return - } - // Inside vscode, you console.log does not allow more than 1 param - // to get around it, we can log with multiple log statements for (const message of messages) { if (typeof message === 'object') { - console.log(JSON.stringify(message)) + logChannel.appendLine(message) } else { - console.log(message) + logChannel.appendLine(message) } } } diff --git a/src/services/testRunner/output.ts b/src/services/logger/output.ts similarity index 91% rename from src/services/testRunner/output.ts rename to src/services/logger/output.ts index 7e79f95f..ef1f1b69 100644 --- a/src/services/testRunner/output.ts +++ b/src/services/logger/output.ts @@ -6,7 +6,7 @@ const channels: /* */ } = {} -const getOutputChannel = (name: string): vscode.OutputChannel => { +export const getOutputChannel = (name: string): vscode.OutputChannel => { if (!channels[name]) { channels[name] = vscode.window.createOutputChannel(name) } diff --git a/src/services/node/index.ts b/src/services/node/index.ts index 325c708d..822445de 100644 --- a/src/services/node/index.ts +++ b/src/services/node/index.ts @@ -3,6 +3,7 @@ import * as fs from 'fs' import { join } from 'path' import { promisify } from 'util' import { WORKSPACE_ROOT } from '../../environment' +import logger from '../logger' const asyncExec = promisify(cpExec) const asyncRemoveFile = promisify(fs.unlink) @@ -35,13 +36,13 @@ export const removeFile = (...paths: string[]) => { export const readFile = (...paths: string[]): Promise => { const filePath = getWorkspacePath(...paths) return asyncReadFile(getWorkspacePath(...paths), 'utf8').catch((err) => { - console.warn(`Failed to read from ${filePath}: ${err.message}`) + logger(`Failed to read from ${filePath}: ${err.message}`) }) } export const writeFile = (data: any, ...paths: string[]): Promise => { const filePath = getWorkspacePath(...paths) return asyncWriteFile(filePath, data).catch((err) => { - console.warn(`Failed to write to ${filePath}: ${err.message}`) + logger(`Failed to write to ${filePath}: ${err.message}`) }) } diff --git a/src/services/reset/index.ts b/src/services/reset/index.ts index b05016da..e512a049 100644 --- a/src/services/reset/index.ts +++ b/src/services/reset/index.ts @@ -1,5 +1,5 @@ import { exec, removeFile } from '../node' - +import logger from '../logger' interface Input { hash: string branch: string @@ -17,13 +17,13 @@ const reset = async ({ branch, hash }: Input): Promise => { try { // if no git init, will initialize // otherwise re-initializes git - await exec({ command: 'git init' }).catch(console.log) + await exec({ command: 'git init' }).catch(logger) // capture current branch const hasBranch = await exec({ command: 'git branch --show-current' }) const localBranch = hasBranch.stdout // check if coderoad remote exists - const hasRemote = await exec({ command: 'git remote -v' }).catch(console.warn) + const hasRemote = await exec({ command: 'git remote -v' }).catch(logger) if (!hasRemote || !hasRemote.stdout || !hasRemote.stdout.length) { throw new Error('No remote found') } else if (!hasRemote.stdout.match(new RegExp(remote))) { @@ -64,8 +64,7 @@ const reset = async ({ branch, hash }: Input): Promise => { command: `git reset --hard ${hash}`, }) } catch (error: any) { - console.error('Error resetting') - console.error(error.message) + logger(`Error resetting: ${error.message}`) } } diff --git a/src/services/storage/index.ts b/src/services/storage/index.ts index f4ed4ac5..cb2abfbc 100644 --- a/src/services/storage/index.ts +++ b/src/services/storage/index.ts @@ -1,6 +1,7 @@ import * as vscode from 'vscode' import { readFile, writeFile } from '../node' import { SESSION_STORAGE_PATH } from '../../environment' +import logger from '../logger' // NOTE: localStorage is not available on client // and must be stored in editor @@ -46,8 +47,8 @@ class Storage { return data } } - } catch (err) { - console.warn(`Failed to read or parse session file: ${SESSION_STORAGE_PATH}/${this.filePath}.json`) + } catch (err: any) { + logger(`Failed to read or parse session file: ${SESSION_STORAGE_PATH}/${this.filePath}.json: ${err.message}`) } } const value: string | undefined = await this.storage.get(this.key) @@ -55,8 +56,8 @@ class Storage { // 2. read from local storage try { return JSON.parse(value) - } catch (err) { - console.warn(`Failed to parse session state from local storage: ${value}`) + } catch (err: any) { + logger(`Failed to parse session state from local storage: ${value}: ${err.message}`) } } // 3. fallback to the default @@ -83,7 +84,9 @@ class Storage { try { writeFile(data, SESSION_STORAGE_PATH, `${this.filePath}.json`) } catch (err: any) { - console.warn(`Failed to write coderoad session to path: ${SESSION_STORAGE_PATH}/${this.filePath}.json`) + logger( + `Failed to write coderoad session to path: ${SESSION_STORAGE_PATH}/${this.filePath}.json: ${err.message}`, + ) } } } diff --git a/src/services/telemetry/index.ts b/src/services/telemetry/index.ts index 7b5f1632..2f0ec03c 100644 --- a/src/services/telemetry/index.ts +++ b/src/services/telemetry/index.ts @@ -19,7 +19,7 @@ interface Measurements { let reporter: any export const activate = (subscribeFn: (reporter: any) => void): void => { - logger(EXTENSION_ID, VERSION, INSTRUMENTATION_KEY) + logger(`${EXTENSION_ID} v${VERSION}`) reporter = new TelemetryReporter(EXTENSION_ID, VERSION, INSTRUMENTATION_KEY) subscribeFn(reporter) } @@ -31,14 +31,12 @@ export const deactivate = (): void => { } export const onError = (error: Error, properties?: Properties, measurements?: Measurements): void => { - logger(error, properties, measurements) if (reporter) { reporter.sendTelemetryException(error, properties, measurements) } } export const onEvent = (eventName: string, properties?: Properties, measurements?: Measurements): void => { - logger(eventName, properties, measurements) if (reporter) { reporter.sendTelemetryEvent(eventName, properties, measurements) } diff --git a/src/services/testRunner/index.ts b/src/services/testRunner/index.ts index cb264665..d4538a45 100644 --- a/src/services/testRunner/index.ts +++ b/src/services/testRunner/index.ts @@ -6,7 +6,7 @@ import parser, { ParserOutput } from './parser' import parseSubtasks from './subtasks' import { debounce, throttle } from './throttle' import { onError } from '../telemetry' -import { clearOutput, addOutput } from './output' +import { clearOutput, addOutput } from '../logger/output' import { formatFailOutput } from './formatOutput' interface Callbacks { @@ -18,7 +18,6 @@ interface Callbacks { } const failChannelName = 'CodeRoad (Tests)' -const logChannelName = 'CodeRoad (Logs)' interface TestRunnerParams { position: T.Position @@ -41,12 +40,12 @@ const createTestRunner = (data: TT.Tutorial, callbacks: Callbacks): ((params: an // calculate level & step from position const level: TT.Level | null = data.levels.find((l) => l.id === position.levelId) || null if (!level) { - console.warn(`Level "${position.levelId}" not found`) + logger(`Error: Level "${position.levelId}" not found`) return } const step: TT.Step | null = level.steps.find((s) => s.id === position.stepId) || null if (!step) { - console.warn(`Step "${position.stepId}" not found`) + logger(`Error: Step "${position.stepId}" not found`) return } @@ -73,7 +72,7 @@ const createTestRunner = (data: TT.Tutorial, callbacks: Callbacks): ((params: an command = [command, testRunnerFilterArg, testFilter].join(' ') } } - logger('COMMAND', command) + logger(`COMMAND: ${command}`) result = await exec({ command, dir: testRunnerConfig.directory }) } catch (err: any) { result = { stdout: err.stdout, stderr: err.stack } @@ -85,13 +84,15 @@ const createTestRunner = (data: TT.Tutorial, callbacks: Callbacks): ((params: an return } - logger('----------------- PROCESS TEST -----------------') + logger('---------------- TEST RESULTS -----------------') const { stdout, stderr } = result const tap: ParserOutput = parser(stdout || '') - addOutput({ channel: logChannelName, text: tap.logs.join('\n'), show: false }) + if (tap.logs.length) { + logger(tap.logs.join('\n')) + } if (stderr) { if (!tap.failed.length) { diff --git a/src/services/webview/render.ts b/src/services/webview/render.ts index c7f5efc2..08719bbe 100644 --- a/src/services/webview/render.ts +++ b/src/services/webview/render.ts @@ -3,6 +3,7 @@ import * as vscode from 'vscode' import { asyncReadFile } from '../node' import { onError } from '../telemetry' import { CONTENT_SECURITY_POLICY_EXEMPTIONS } from '../../environment' +import logger from '../logger' const getNonce = (): string => { let text = '' @@ -142,8 +143,8 @@ async function render(panel: vscode.WebviewPanel, rootPath: string): Promise { return } - logger(`ROUTE: ${route}`) - logger(`POSITION: ${JSON.stringify(context.position)}`) + logger( + `ROUTE: "${route}": ${context.position?.complete ? 'Completed' : 'On'} level ${ + context.position?.levelId || 'unknown' + }, step ${context.position?.stepId || 'unknown'}`, + ) return ( diff --git a/web-app/src/components/Error/index.tsx b/web-app/src/components/Error/index.tsx index 5c1bf828..e095ef5d 100644 --- a/web-app/src/components/Error/index.tsx +++ b/web-app/src/components/Error/index.tsx @@ -5,6 +5,7 @@ import { css, jsx } from '@emotion/core' import Markdown from '../Markdown' import Button from '../../components/Button' import { Theme } from '../../styles/theme' +import logger from '../../services/logger' const styles = { container: (theme: Theme) => ({ @@ -42,7 +43,7 @@ const ErrorMarkdown = ({ error, send }: Props) => { React.useEffect(() => { if (error) { // log error - console.log(`ERROR in markdown: ${error.message}`) + logger(`ERROR in markdown: ${error.message}`) } }, [error]) diff --git a/web-app/src/components/ErrorBoundary/index.tsx b/web-app/src/components/ErrorBoundary/index.tsx index 9e2c30ba..44a66c70 100644 --- a/web-app/src/components/ErrorBoundary/index.tsx +++ b/web-app/src/components/ErrorBoundary/index.tsx @@ -9,8 +9,8 @@ class ErrorBoundary extends React.Component { // Display fallback UI this.setState({ errorMessage: error.message }) // You can also log the error to an error reporting service - logger('ERROR in component:', JSON.stringify(error)) - logger('ERROR info:', JSON.stringify(info)) + logger(`ERROR in component: ${JSON.stringify(error)}`) + logger(`ERROR info:: ${JSON.stringify(info)}`) } public render() { diff --git a/web-app/src/components/Markdown/index.tsx b/web-app/src/components/Markdown/index.tsx index ac5fcf70..2ae40345 100644 --- a/web-app/src/components/Markdown/index.tsx +++ b/web-app/src/components/Markdown/index.tsx @@ -1,11 +1,12 @@ import MarkdownIt from 'markdown-it' import Prism from 'prismjs' -import { css, jsx, InterpolationWithTheme } from '@emotion/core' +import { css, jsx } from '@emotion/core' // @ts-ignore no types for package import markdownEmoji from 'markdown-it-emoji' import * as React from 'react' // load prism styles & language support import './prism' +import logger from '../../services/logger' // markdown highlighter instance const md: MarkdownIt = new MarkdownIt({ @@ -17,8 +18,8 @@ const md: MarkdownIt = new MarkdownIt({ try { hl = Prism.highlight(str, Prism.languages[lang], lang) - } catch (error) { - console.error(error) + } catch (error: any) { + logger(`Error highlighting markdown: ${error.message}`) hl = md.utils.escapeHtml(str) } @@ -66,7 +67,7 @@ const Markdown = (props: Props) => { } catch (error) { const message = `Failed to parse markdown for ${props.children}` // TODO: onError(new Error(message)) - console.log(message) + logger(`Error: ${message}`) html = `
ERROR: Failed to parse markdown

${props.children}

diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 90607c28..e8cb5031 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react' +import logger from '../../services/logger' interface RouterProps { children: any @@ -41,7 +42,7 @@ export const Router = ({ children, route }: RouterProps) => { } const message = `No Route matches for "${JSON.stringify(route)}"` // TODO: onError(new Error(message)) - console.warn(message) + logger(`Error: ${message}`) return null } diff --git a/web-app/src/containers/SelectTutorial/LoadTutorialSummary.tsx b/web-app/src/containers/SelectTutorial/LoadTutorialSummary.tsx index 66bb5423..714a11ca 100644 --- a/web-app/src/containers/SelectTutorial/LoadTutorialSummary.tsx +++ b/web-app/src/containers/SelectTutorial/LoadTutorialSummary.tsx @@ -3,6 +3,7 @@ import { Dialog } from '@alifd/next' import useFetch from '../../services/hooks/useFetch' import * as TT from 'typings/tutorial' import LoadingPage from '../Loading' +import logger from '../../services/logger' interface Props { url: string @@ -16,7 +17,7 @@ const LoadTutorialSummary = (props: Props) => { return } if (error) { - console.log(`Failed to load tutorial summary: ${error}`) + logger(`Failed to load tutorial summary: ${error}`) return
Error loading summary
} if (!data) { diff --git a/web-app/src/containers/Tutorial/formatLevels.ts b/web-app/src/containers/Tutorial/formatLevels.ts index 724474b9..b5f6d002 100644 --- a/web-app/src/containers/Tutorial/formatLevels.ts +++ b/web-app/src/containers/Tutorial/formatLevels.ts @@ -1,5 +1,6 @@ import * as T from 'typings' import * as TT from 'typings/tutorial' +import logger from '../../services/logger' interface Input { position: T.Position @@ -61,8 +62,8 @@ const formatLevels = ({ position, levels, testStatus }: Input): Output => { // test result count and subtask count don't match // something is wrong with the tutorial // NOTE: hacky temp solution as should be caught by tutorial creators / build tools - console.error( - 'ERROR: subtasks and test results have a different number of results. This is likely an error with the tutorial or an edited test file.', + logger( + 'Error: subtasks and test results have a different number of results. This is likely an error with the tutorial or an edited test file.', ) } subtasks = step.subtasks.map((subtask: string, subtaskIndex: number) => { diff --git a/web-app/src/environment.ts b/web-app/src/environment.ts index 11e7993d..90b2ee88 100644 --- a/web-app/src/environment.ts +++ b/web-app/src/environment.ts @@ -9,7 +9,6 @@ export const DEBUG: boolean = (process.env.REACT_APP_DEBUG || '').toLowerCase() === 'true' export const VERSION: string = process.env.VERSION || 'unknown' export const NODE_ENV: string = process.env.NODE_ENV || 'development' -export const LOG: boolean = (process.env.REACT_APP_LOG || '').toLowerCase() === 'true' export const TUTORIAL_LIST_URL: string = process.env.REACT_APP_TUTORIAL_LIST_URL || '' // config variables diff --git a/web-app/src/services/listeners/index.ts b/web-app/src/services/listeners/index.ts index f415bc3a..01194d54 100644 --- a/web-app/src/services/listeners/index.ts +++ b/web-app/src/services/listeners/index.ts @@ -1,8 +1,8 @@ -import ReactDOM from 'react-dom' +import logger from '../logger' -// document listeners - -document.addEventListener('securitypolicyviolation', () => { +document.addEventListener('securitypolicyviolation', (event) => { // TODO: add error handling - console.log('Security warning for resource') + if (event.isTrusted !== true) { + logger(`Security warning for resource: ${JSON.stringify(event)}`) + } }) diff --git a/web-app/src/services/logger/index.ts b/web-app/src/services/logger/index.ts index cb0fff9c..a72f868b 100644 --- a/web-app/src/services/logger/index.ts +++ b/web-app/src/services/logger/index.ts @@ -1,20 +1,15 @@ -import { LOG } from '../../environment' +import { editor } from '../state/useStateMachine' export type Log = string | object | number | null const logger = (...messages: Log[]): void => { - if (!LOG) { - return - } - // Inside vscode, you console.log does not allow more than 1 param - // to get around it, we can log with multiple log statements - for (const message of messages) { - if (typeof message === 'object') { - console.log(JSON.stringify(message)) - } else { - console.log(message) - } - } + // logs are difficult to view in the web client. + // for debugging purposes it's easier to collect logs in the "CodeRoad (Logs)" output channel + editor.postMessage({ + type: 'CLIENT_LOG', + payload: messages, + source: 'coderoad', // filter events by source on editor side + }) } export default logger diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index cbdf8f4a..474b19e8 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -35,7 +35,7 @@ export const initPosition = assign({ export const updateStepPosition = assign({ position: (context: T.MachineContext, event: T.MachineEvent): any => { - logger('updateStepPosition', event) + logger(`updateStepPosition: ${JSON.stringify(event)})`) return event.payload.position }, }) @@ -46,19 +46,15 @@ export const updatePosition = assign({ }, }) -export const loadNext = send( - (context: T.MachineContext): T.Action => { - const level = selectors.currentLevel(context) - return getNext(context.position, level, context.tutorial?.levels || []) - }, -) +export const loadNext = send((context: T.MachineContext): T.Action => { + const level: TT.Level = selectors.currentLevel(context) + return getNext(context.position, level, context.tutorial?.levels || []) +}) -export const stepNext = send( - (context: T.MachineContext): T.Action => { - const level: TT.Level = selectors.currentLevel(context) - return getStepNext(context.position, level) - }, -) +export const stepNext = send((context: T.MachineContext): T.Action => { + const level: TT.Level = selectors.currentLevel(context) + return getStepNext(context.position, level) +}) export const reset = assign({ tutorial() { @@ -78,13 +74,13 @@ export const setError = assign({ const error: string | null | E.ErrorMessage = event.payload.error if (error) { if (typeof error === 'string') { - console.log(`ERROR: ${error}`) + logger(`ERROR: ${error}`) return error } else if (error.type) { const errorMessage = errors[error.type] const content = errorMessage || '' const message = `${content}\n\n${error.message || ''}` - console.log(`ERROR: ${message}`) + logger(`ERROR: ${message}`) return { ...error, message, diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index defe444a..8b7e5e0a 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -157,7 +157,7 @@ export const createMachine = (options: any) => { LOAD_SUBTASK_RESULTS: { actions: ['testSubtasks'], }, - TEST_RUNNING: 'TestRunning', + START_TEST: 'TestRunning', STEP_SOLUTION_LOAD: { actions: ['editorLoadSolution'], }, @@ -204,7 +204,7 @@ export const createMachine = (options: any) => { }, LevelComplete: { onEntry: ['onLevelComplete'], - onExit: ['testClear', 'incrementLevel'], + onExit: ['testClear'], on: { NEXT_LEVEL: 'LoadNext', KEY_PRESS_ENTER: 'LoadNext', diff --git a/web-app/src/services/state/useStateMachine.tsx b/web-app/src/services/state/useStateMachine.tsx index 296ce76a..37a6edac 100644 --- a/web-app/src/services/state/useStateMachine.tsx +++ b/web-app/src/services/state/useStateMachine.tsx @@ -13,24 +13,18 @@ interface Output { declare let acquireVsCodeApi: any -const editor = acquireVsCodeApi() -const editorSend = (action: T.Action) => { - logger(`TO EXT: "${action.type}"`) - return editor.postMessage({ +export const editor = acquireVsCodeApi() + +const editorSend = (action: T.Action) => + editor.postMessage({ ...action, source: 'coderoad', // filter events by source on editor side }) -} // router finds first state match of const useStateMachine = (): Output => { const [state, send] = useMachine(createMachine({ editorSend })) - const sendWithLog = (action: T.Action): void => { - logger(`SEND: ${action.type}`, action) - send(action) - } - // event bus listener React.useEffect(() => { const listener = 'message' @@ -43,7 +37,7 @@ const useStateMachine = (): Output => { // filter out events from other extensions return } - sendWithLog(action) + send(action) } window.addEventListener(listener, handler) return () => { @@ -58,7 +52,7 @@ const useStateMachine = (): Output => { return { context: state.context, route, - send: sendWithLog, + send, } }