store stacktrace as a json array so we can reverse it when displaying and fixed up display of errors
This commit is contained in:
parent
6fa18c53df
commit
08271da363
|
@ -1,8 +1,8 @@
|
||||||
"""empty message
|
"""empty message
|
||||||
|
|
||||||
Revision ID: e0510795b643
|
Revision ID: 5dae229f0a9b
|
||||||
Revises:
|
Revises:
|
||||||
Create Date: 2023-04-19 14:36:11.004444
|
Create Date: 2023-04-20 08:19:03.409112
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -10,7 +10,7 @@ import sqlalchemy as sa
|
||||||
from sqlalchemy.dialects import mysql
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = 'e0510795b643'
|
revision = '5dae229f0a9b'
|
||||||
down_revision = None
|
down_revision = None
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
|
@ -467,7 +467,7 @@ def upgrade():
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
sa.Column('process_instance_event_id', sa.Integer(), nullable=False),
|
sa.Column('process_instance_event_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('message', sa.String(length=1024), nullable=False),
|
sa.Column('message', sa.String(length=1024), nullable=False),
|
||||||
sa.Column('stacktrace', sa.Text(), nullable=False),
|
sa.Column('stacktrace', sa.JSON(), nullable=False),
|
||||||
sa.Column('task_line_number', sa.Integer(), nullable=True),
|
sa.Column('task_line_number', sa.Integer(), nullable=True),
|
||||||
sa.Column('task_offset', sa.Integer(), nullable=True),
|
sa.Column('task_offset', sa.Integer(), nullable=True),
|
||||||
sa.Column('task_line_contents', sa.String(length=255), nullable=True),
|
sa.Column('task_line_contents', sa.String(length=255), nullable=True),
|
|
@ -17,7 +17,7 @@ class ProcessInstanceErrorDetailModel(SpiffworkflowBaseDBModel):
|
||||||
message: str = db.Column(db.String(1024), nullable=False)
|
message: str = db.Column(db.String(1024), nullable=False)
|
||||||
|
|
||||||
# this should be 65k in mysql
|
# this should be 65k in mysql
|
||||||
stacktrace: str = db.Column(db.Text(), nullable=False)
|
stacktrace: Optional[list] = db.Column(db.JSON, nullable=False)
|
||||||
|
|
||||||
task_line_number: Optional[int] = db.Column(db.Integer)
|
task_line_number: Optional[int] = db.Column(db.Integer)
|
||||||
task_offset: Optional[int] = db.Column(db.Integer)
|
task_offset: Optional[int] = db.Column(db.Integer)
|
||||||
|
|
|
@ -619,7 +619,7 @@ class TaskService:
|
||||||
|
|
||||||
if exception is not None:
|
if exception is not None:
|
||||||
# truncate to avoid database errors on large values. We observed that text in mysql is 65K.
|
# truncate to avoid database errors on large values. We observed that text in mysql is 65K.
|
||||||
stacktrace = traceback.format_exc()[0:63999]
|
stacktrace = traceback.format_exc().split("\n")
|
||||||
message = str(exception)[0:1023]
|
message = str(exception)[0:1023]
|
||||||
|
|
||||||
task_line_number = None
|
task_line_number = None
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import copy
|
import copy
|
||||||
import time
|
import time
|
||||||
|
from spiffworkflow_backend.models.process_instance_event import ProcessInstanceEventType
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Set
|
from typing import Set
|
||||||
|
@ -329,6 +330,7 @@ class WorkflowExecutionService:
|
||||||
self.process_bpmn_messages()
|
self.process_bpmn_messages()
|
||||||
self.queue_waiting_receive_messages()
|
self.queue_waiting_receive_messages()
|
||||||
except SpiffWorkflowException as swe:
|
except SpiffWorkflowException as swe:
|
||||||
|
TaskService.add_event_to_process_instance(self.process_instance_model, ProcessInstanceEventType.task_failed.value, exception=swe, task_guid=str(swe.task.id))
|
||||||
raise ApiError.from_workflow_exception("task_error", str(swe), swe) from swe
|
raise ApiError.from_workflow_exception("task_error", str(swe), swe) from swe
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -34,7 +34,9 @@ export const childrenForErrorObject = (errorObject: ErrorForDisplay) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = <div>{errorObject.message}</div>;
|
const message = (
|
||||||
|
<div className={errorObject.messageClassName}>{errorObject.message}</div>
|
||||||
|
);
|
||||||
const taskName = errorDetailDisplay(errorObject, 'task_name', 'Task Name');
|
const taskName = errorDetailDisplay(errorObject, 'task_name', 'Task Name');
|
||||||
const taskId = errorDetailDisplay(errorObject, 'task_id', 'Task ID');
|
const taskId = errorDetailDisplay(errorObject, 'task_id', 'Task ID');
|
||||||
const fileName = errorDetailDisplay(errorObject, 'file_name', 'File Name');
|
const fileName = errorDetailDisplay(errorObject, 'file_name', 'File Name');
|
||||||
|
@ -44,14 +46,26 @@ export const childrenForErrorObject = (errorObject: ErrorForDisplay) => {
|
||||||
'Line Number'
|
'Line Number'
|
||||||
);
|
);
|
||||||
const errorLine = errorDetailDisplay(errorObject, 'error_line', 'Context');
|
const errorLine = errorDetailDisplay(errorObject, 'error_line', 'Context');
|
||||||
let taskTrace = null;
|
let codeTrace = null;
|
||||||
if (errorObject.task_trace && errorObject.task_trace.length > 0) {
|
if (errorObject.task_trace && errorObject.task_trace.length > 0) {
|
||||||
taskTrace = (
|
codeTrace = (
|
||||||
<div className="error_info">
|
<div className="error_info">
|
||||||
<span className="error_title">Call Activity Trace:</span>
|
<span className="error_title">Call Activity Trace:</span>
|
||||||
{errorObject.task_trace.reverse().join(' -> ')}
|
{errorObject.task_trace.reverse().join(' -> ')}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else if (errorObject.stacktrace) {
|
||||||
|
codeTrace = (
|
||||||
|
<pre className="error_info">
|
||||||
|
<span className="error_title">Stacktrace:</span>
|
||||||
|
{errorObject.stacktrace.reverse().map((a) => (
|
||||||
|
<>
|
||||||
|
{a}
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</pre>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -63,7 +77,7 @@ export const childrenForErrorObject = (errorObject: ErrorForDisplay) => {
|
||||||
fileName,
|
fileName,
|
||||||
lineNumber,
|
lineNumber,
|
||||||
errorLine,
|
errorLine,
|
||||||
taskTrace,
|
codeTrace,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -234,6 +234,8 @@ export type HotCrumbItem = HotCrumbItemArray | HotCrumbItemObject;
|
||||||
|
|
||||||
export interface ErrorForDisplay {
|
export interface ErrorForDisplay {
|
||||||
message: string;
|
message: string;
|
||||||
|
|
||||||
|
messageClassName?: string;
|
||||||
sentry_link?: string;
|
sentry_link?: string;
|
||||||
task_name?: string;
|
task_name?: string;
|
||||||
task_id?: string;
|
task_id?: string;
|
||||||
|
@ -241,6 +243,7 @@ export interface ErrorForDisplay {
|
||||||
error_line?: string;
|
error_line?: string;
|
||||||
file_name?: string;
|
file_name?: string;
|
||||||
task_trace?: string[];
|
task_trace?: string[];
|
||||||
|
stacktrace?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthenticationParam {
|
export interface AuthenticationParam {
|
||||||
|
@ -301,7 +304,7 @@ export interface JsonSchemaForm {
|
||||||
export interface ProcessInstanceEventErrorDetail {
|
export interface ProcessInstanceEventErrorDetail {
|
||||||
id: number;
|
id: number;
|
||||||
message: string;
|
message: string;
|
||||||
stacktrace: string;
|
stacktrace: string[];
|
||||||
task_line_contents?: string;
|
task_line_contents?: string;
|
||||||
task_line_number?: number;
|
task_line_number?: number;
|
||||||
task_offset?: number;
|
task_offset?: number;
|
||||||
|
|
|
@ -160,21 +160,16 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
if (eventErrorDetails) {
|
if (eventErrorDetails) {
|
||||||
const errorForDisplay: ErrorForDisplay = {
|
const errorForDisplay: ErrorForDisplay = {
|
||||||
message: eventErrorDetails.message,
|
message: eventErrorDetails.message,
|
||||||
|
messageClassName: 'failure-string',
|
||||||
task_name: eventForModal.task_definition_name,
|
task_name: eventForModal.task_definition_name,
|
||||||
task_id: eventForModal.task_definition_identifier,
|
task_id: eventForModal.task_definition_identifier,
|
||||||
line_number: eventErrorDetails.task_line_number,
|
line_number: eventErrorDetails.task_line_number,
|
||||||
error_line: eventErrorDetails.task_line_contents,
|
error_line: eventErrorDetails.task_line_contents,
|
||||||
task_trace: eventErrorDetails.task_trace,
|
task_trace: eventErrorDetails.task_trace,
|
||||||
|
stacktrace: eventErrorDetails.stacktrace,
|
||||||
};
|
};
|
||||||
const errorChildren = childrenForErrorObject(errorForDisplay);
|
const errorChildren = childrenForErrorObject(errorForDisplay);
|
||||||
// <pre>{eventErrorDetails.stacktrace}</pre>
|
errorMessageTag = <>{errorChildren}</>;
|
||||||
errorMessageTag = (
|
|
||||||
<>
|
|
||||||
<p className="failure-string">{eventErrorDetails.message}</p>
|
|
||||||
<br />
|
|
||||||
{errorChildren}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -207,8 +202,8 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
failureCallback: (error: any) => {
|
failureCallback: (error: any) => {
|
||||||
const errorObject: ProcessInstanceEventErrorDetail = {
|
const errorObject: ProcessInstanceEventErrorDetail = {
|
||||||
id: 0,
|
id: 0,
|
||||||
message: `ERROR: ${error.message}`,
|
message: `ERROR retrieving error details: ${error.message}`,
|
||||||
stacktrace: '',
|
stacktrace: [],
|
||||||
};
|
};
|
||||||
setEventErrorDetails(errorObject);
|
setEventErrorDetails(errorObject);
|
||||||
},
|
},
|
||||||
|
@ -218,7 +213,7 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
|
|
||||||
const eventTypeCell = (logEntry: ProcessInstanceLogEntry) => {
|
const eventTypeCell = (logEntry: ProcessInstanceLogEntry) => {
|
||||||
if (
|
if (
|
||||||
['process_instance_error', 'task_error'].includes(logEntry.event_type)
|
['process_instance_error', 'task_failed'].includes(logEntry.event_type)
|
||||||
) {
|
) {
|
||||||
const errorTitle = 'Event has an error';
|
const errorTitle = 'Event has an error';
|
||||||
const errorIcon = (
|
const errorIcon = (
|
||||||
|
|
Loading…
Reference in New Issue