Commit 015f4717 authored by Tomáš Pecka's avatar Tomáš Pecka

Report more detailed ALT errors to WebUI

Reporting only the top level exception from ALT is simply not enough.
Compare the difference between these two errors logs propagated to the
webui and/or worker's logger.

Error: Evaluation of algorithm string::Parse failed.

vs.

Evaluation of algorithm string::Parse failed.
 -> Multiple initial states are not avaiable for DFA type

Closes #41.
parent 4c17bec2
import React from 'react'
import { List, ListItem, ListItemText, ListItemIcon } from '@material-ui/core'
import SubdirectoryArrowRightIcon from '@material-ui/icons/SubdirectoryArrowRight';
import { EvaluateResponseError } from '../interfaces/EvaluateResponseError'
export const createEvalErrorMessage = ( e: EvaluateResponseError) => {
return (
<List dense={true}>
{e.errorStack.map((errorMsg, idx) => (
<ListItem>
{(idx > 0) && (
<ListItemIcon>
<SubdirectoryArrowRightIcon />
</ListItemIcon>
)
}
<ListItemText primary={errorMsg} />
</ListItem>
))}
</List>
)
}
......@@ -5,6 +5,8 @@ import { algorithmUIActions } from '../reducers/algorithmUI'
import { algorithmDataActions } from '../reducers/algorithmData'
import { ReduxState } from '../reducers'
import { useSnackbar } from 'notistack'
import { EvaluateResponseError } from '../interfaces/EvaluateResponseError'
import { createEvalErrorMessage } from '../components/EvalErrorSnackbar'
const { setOutputValues } = algorithmDataActions
const { setEvaluatingDialogOpen } = algorithmUIActions
......@@ -32,10 +34,15 @@ export const useEvaluate = () => {
try {
result = await algorithmService.evaluate(algorithmData)
} catch (e) {
enqueueSnackbar(
e.message ?? (typeof e === 'string' ? e : 'Evaluation failed'),
{ variant: 'error' }
)
if (e instanceof EvaluateResponseError) {
enqueueSnackbar(createEvalErrorMessage(e), { variant: 'error' });
} else {
enqueueSnackbar(
e.message ?? (typeof e === 'string' ? e : 'Evaluation failed'),
{ variant: 'error' }
)
}
dispatch(setEvaluatingDialogOpen(false))
return
}
......
export interface EvaluateResponse {
error?: string
error?: string[],
outputs?: {
[outputId: string]: string
}
}
\ No newline at end of file
}
export class EvaluateResponseError extends Error {
errorStack: string[];
constructor(m: string[]) {
super(m[0]);
Object.setPrototypeOf(this, EvaluateResponseError.prototype);
this.errorStack = m;
}
}
import { Map } from 'immutable'
import { AlgorithmGraph, serialize } from '../interfaces/AlgorithmGraph'
import { EvaluateResponse } from '../interfaces/EvaluateResponse'
import { EvaluateResponseError } from '../interfaces/EvaluateResponseError'
export interface IAlgorithmService {
evaluate(data: AlgorithmGraph): Promise<Map<string, string>>
......@@ -21,10 +22,10 @@ class AlgorithmService implements IAlgorithmService {
}).then((res) => res.json())
} catch (e) {
console.error(e)
throw new Error('Error while communicating with the server')
throw new EvaluateResponseError(['Error while communicating with the server'])
}
if (response.error) throw new Error(response.error)
if (response.error) throw new EvaluateResponseError(response.error)
return Map<string, string>((response.outputs as any) ?? {})
}
......
#include "Worker.hpp"
#include <algorithm>
#include <alib/exception>
#include <future>
#include <memory>
#include <utility>
......@@ -109,7 +111,7 @@ void Worker::listenForMessages() {
try {
outputMap = future.get();
} catch (std::exception &e) {
replyError(*responseSession, taskId, e.what());
replyError(*responseSession, taskId, e);
message->acknowledge();
continue;
}
......@@ -135,7 +137,25 @@ void Worker::replyOutputs(cms::Session & session, int taskId, const std::map<std
void Worker::replyError(cms::Session & session, int taskId, const char * errorMessage) {
logger->logError(taskId, errorMessage);
Json::Value errorJson;
errorJson["error"] = errorMessage;
errorJson["error"][0] = errorMessage;
reply(session, taskId, errorJson);
}
void Worker::replyError(cms::Session & session, int taskId, const std::exception& exception) {
alib::ExceptionHandler::NestedExceptionContainer exceptions;
alib::ExceptionHandler::handle ( exceptions );
std::ostringstream oss;
alib::ExceptionHandler::handle ( oss );
std::string logMessage = oss.str ( );
std::transform ( logMessage.begin(), logMessage.end(), logMessage.begin(), [](char x) { return x == '\n' ? ' ' : x; });
logger->logError(taskId, logMessage.c_str());
Json::Value errorJson;
for ( size_t i = 0; i < exceptions.getExceptions ( ).size ( ); i++ ) {
errorJson["error"][static_cast<int>(i)] = exceptions.getExceptions()[i].desc.value();
}
reply(session, taskId, errorJson);
}
......
......@@ -50,6 +50,7 @@ private:
void listenForMessages();
void replyOutputs(cms::Session & session, int taskId, const std::map<std::string, std::string> & outputMap);
void replyError(cms::Session & session, int taskId, const char * errorMessage);
void replyError(cms::Session & session, int taskId, const std::exception& esception);
void reply(cms::Session & session, int taskId, Json::Value & json);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment