refactor: Update LogType to include ErrorLogType

The LogType in the schema module has been updated to include the ErrorLogType. This allows for more detailed logging of error messages, including the error message itself and the stack trace. This change improves the accuracy and usefulness of error logging in the application.
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-06-19 12:24:02 -03:00
commit 1367212412
10 changed files with 64 additions and 28 deletions

View file

@ -1,4 +1,5 @@
import time import time
import traceback
import uuid import uuid
from functools import partial from functools import partial
from typing import TYPE_CHECKING, Annotated, Optional from typing import TYPE_CHECKING, Annotated, Optional
@ -189,11 +190,13 @@ async def build_vertex(
result_data_response = ResultDataResponse.model_validate(result_dict, from_attributes=True) result_data_response = ResultDataResponse.model_validate(result_dict, from_attributes=True)
except Exception as exc: except Exception as exc:
tb = traceback.format_exc()
logger.exception(f"Error building Component: {exc}") logger.exception(f"Error building Component: {exc}")
params = format_exception_message(exc) params = format_exception_message(exc)
message = {"errorMessage": params, "stackTrace": tb}
valid = False valid = False
output_label = vertex.outputs[0]["name"] if vertex.outputs else "output" output_label = vertex.outputs[0]["name"] if vertex.outputs else "output"
logs = {output_label: Log(message=params, type="error")} logs = {output_label: Log(message=message, type="error")}
result_data_response = ResultDataResponse(results={}, logs=logs) result_data_response = ResultDataResponse(results={}, logs=logs)
artifacts = {} artifacts = {}
# If there's an error building the vertex # If there's an error building the vertex
@ -243,7 +246,7 @@ async def build_vertex(
) )
return build_response return build_response
except Exception as exc: except Exception as exc:
logger.error(f"Error building Component: {exc}") logger.error(f"Error building Component:\n\n{exc}")
logger.exception(exc) logger.exception(exc)
message = parse_exception(exc) message = parse_exception(exc)
raise HTTPException(status_code=500, detail=message) from exc raise HTTPException(status_code=500, detail=message) from exc

View file

@ -830,7 +830,7 @@ class Graph:
log_transaction(flow_id, vertex, status="success") log_transaction(flow_id, vertex, status="success")
return result_dict, params, valid, artifacts, vertex return result_dict, params, valid, artifacts, vertex
except Exception as exc: except Exception as exc:
logger.exception(f"Error building Component: {exc}") logger.exception(f"Error building Component:\n\n{exc}")
flow_id = self.flow_id flow_id = self.flow_id
log_transaction(flow_id, vertex, status="failure", error=str(exc)) log_transaction(flow_id, vertex, status="failure", error=str(exc))
raise exc raise exc

View file

@ -582,7 +582,7 @@ class Vertex:
logger.exception(e) logger.exception(e)
raise ValueError( raise ValueError(
f"Params {key} ({self.params[key]}) is not a list and cannot be extended with {result}" f"Params {key} ({self.params[key]}) is not a list and cannot be extended with {result}"
f"Error building Component {self.display_name}: {str(e)}" f"Error building Component {self.display_name}:\n\n{str(e)}"
) from e ) from e
def _handle_func(self, key, result): def _handle_func(self, key, result):
@ -622,11 +622,8 @@ class Vertex:
self.logs = build_logs(self, result) self.logs = build_logs(self, result)
self._update_built_object_and_artifacts(result) self._update_built_object_and_artifacts(result)
except Exception as exc: except Exception as exc:
tb = traceback.format_exc() logger.exception(exc)
error_detail = f"Error: {exc}\nTraceback: {tb}" raise ValueError(f"Error building Component {self.display_name}:\n\n{exc}") from exc
logger.exception(error_detail)
raise ValueError(f"Error building Component {self.display_name}: {error_detail}") from exc
def _update_built_object_and_artifacts(self, result): def _update_built_object_and_artifacts(self, result):
""" """

View file

@ -2,6 +2,7 @@ from enum import Enum
from typing import Generator, Literal, Union from typing import Generator, Literal, Union
from pydantic import BaseModel from pydantic import BaseModel
from typing_extensions import TypedDict
from langflow.schema import Data from langflow.schema import Data
from langflow.schema.message import Message from langflow.schema.message import Message
@ -22,12 +23,17 @@ class LogType(str, Enum):
UNKNOWN = "unknown" UNKNOWN = "unknown"
class StreamURL(BaseModel): class StreamURL(TypedDict):
location: str location: str
class ErrorLog(TypedDict):
errorMessage: str
stackTrace: str
class Log(BaseModel): class Log(BaseModel):
message: Union[StreamURL, dict, list, str] message: Union[ErrorLog, StreamURL, dict, list, str]
type: str type: str

View file

@ -41,7 +41,9 @@ const SwitchOutputView: React.FC<SwitchOutputViewProps> = ({
<div>NO OUTPUT</div> <div>NO OUTPUT</div>
</Case> </Case>
<Case condition={resultType === "error" || resultType === "ValueError"}> <Case condition={resultType === "error" || resultType === "ValueError"}>
<ErrorOutput value={resultMessage}></ErrorOutput> <ErrorOutput
value={`${resultMessage.errorMessage}\n\n${resultMessage.stackTrace}`}
></ErrorOutput>
</Case> </Case>
<Case condition={node && resultType === "text"}> <Case condition={node && resultType === "text"}>

View file

@ -26,6 +26,7 @@ import { useShortcutsStore } from "../../../../stores/shortcuts";
import { useTypesStore } from "../../../../stores/typesStore"; import { useTypesStore } from "../../../../stores/typesStore";
import { APIClassType } from "../../../../types/api"; import { APIClassType } from "../../../../types/api";
import { ParameterComponentType } from "../../../../types/components"; import { ParameterComponentType } from "../../../../types/components";
import { isErrorLog } from "../../../../types/utils/typeCheckingUtils";
import { import {
debouncedHandleUpdateValues, debouncedHandleUpdateValues,
handleUpdateValues, handleUpdateValues,
@ -114,11 +115,9 @@ export default function ParameterComponent({
if (!outputName) return; if (!outputName) return;
const logs = data?.logs[outputName]; const logs = data?.logs[outputName];
if (Array.isArray(logs) && logs.length > 1) { if (Array.isArray(logs) && logs.length > 1) {
return logs.some( return logs.some((log) => isErrorLog(log));
(log) => log.type === "error" || log.type === "ValueError",
);
} else { } else {
return logs?.type === "error" || logs?.type === "ValueError"; return isErrorLog(logs);
} }
}; };
@ -129,11 +128,6 @@ export default function ParameterComponent({
!!flowPool[data.id] && !!flowPool[data.id] &&
logHasMessage(flowPool[data.id][flowPool[data.id].length - 1]?.data); logHasMessage(flowPool[data.id][flowPool[data.id].length - 1]?.data);
let hasOutputs;
if (flowPoolNode?.data?.logs && outputName) {
hasOutputs = flowPoolNode?.data?.logs[outputName] ?? null;
}
const unknownOutput = logTypeIsUnknown(flowPoolNode?.data); const unknownOutput = logTypeIsUnknown(flowPoolNode?.data);
const errorOutput = logTypeIsError(flowPoolNode?.data); const errorOutput = logTypeIsError(flowPoolNode?.data);

View file

@ -1,5 +1,6 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { LogType, VertexBuildTypeAPI } from "../../types/api"; import { VertexBuildTypeAPI } from "../../types/api";
import { isErrorLog } from "../../types/utils/typeCheckingUtils";
const useValidationStatusString = ( const useValidationStatusString = (
validationStatus: VertexBuildTypeAPI, validationStatus: VertexBuildTypeAPI,
@ -8,11 +9,10 @@ const useValidationStatusString = (
useEffect(() => { useEffect(() => {
if (validationStatus?.data?.logs) { if (validationStatus?.data?.logs) {
// if it is not a string turn it into a string // if it is not a string turn it into a string
console.log("validationStatus", validationStatus);
let newValidationString = ""; let newValidationString = "";
Object.values(validationStatus?.data?.logs).forEach((log: any) => { Object.values(validationStatus?.data?.logs).forEach((log: any) => {
if (log.type === "error" || log.type === "ValueError") { if (isErrorLog(log)) {
newValidationString += `${log.message}\n`; newValidationString += `${log.message.errorMessage}\n`;
} }
}); });
setValidationString(newValidationString); setValidationString(newValidationString);

View file

@ -181,8 +181,13 @@ export type VertexBuildTypeAPI = {
artifacts: any | ChatOutputType | ChatInputType; artifacts: any | ChatOutputType | ChatInputType;
}; };
export type ErrorLogType = {
errorMessage: string;
stackTrace: string;
};
export type LogType = { export type LogType = {
message: any; message: any | ErrorLogType;
type: string; type: string;
}; };

View file

@ -0,0 +1,23 @@
import { ErrorLogType } from "../api";
export function isErrorLogType(value: any): value is ErrorLogType {
return (
typeof value === "object" &&
value !== null &&
"errorMessage" in value &&
typeof value.errorMessage === "string" &&
"stackTrace" in value &&
typeof value.stackTrace === "string"
);
}
export function isErrorLog(
log: any,
): log is { type: "error"; message: ErrorLogType } {
return (
typeof log === "object" &&
log !== null &&
(log.type === "error" || log.type === "ValueError") &&
isErrorLogType(log.message)
);
}

View file

@ -5,6 +5,7 @@ import { getVerticesOrder, postBuildVertex } from "../controllers/API";
import useAlertStore from "../stores/alertStore"; import useAlertStore from "../stores/alertStore";
import useFlowStore from "../stores/flowStore"; import useFlowStore from "../stores/flowStore";
import { VertexBuildTypeAPI } from "../types/api"; import { VertexBuildTypeAPI } from "../types/api";
import { isErrorLogType } from "../types/utils/typeCheckingUtils";
import { VertexLayerElementType } from "../types/zustand/flow"; import { VertexLayerElementType } from "../types/zustand/flow";
type BuildVerticesParams = { type BuildVerticesParams = {
@ -275,9 +276,14 @@ async function buildVertex({
const errorMessages = Object.keys(buildData.data.logs).map((key) => { const errorMessages = Object.keys(buildData.data.logs).map((key) => {
const logs = buildData.data.logs[key]; const logs = buildData.data.logs[key];
if (Array.isArray(logs)) { if (Array.isArray(logs)) {
return logs.map((log) => log.message); return logs
.filter((log) => isErrorLogType(log.message))
.map((log) => log.message.errorMessage);
} }
return [logs.message]; if (!isErrorLogType(logs.message)) {
return [];
}
return [logs.message.errorMessage];
}); });
onBuildError!( onBuildError!(
"Error Building Component", "Error Building Component",