diff --git a/skyvern-frontend/src/App.tsx b/skyvern-frontend/src/App.tsx
index ea11570c..f193f16b 100644
--- a/skyvern-frontend/src/App.tsx
+++ b/skyvern-frontend/src/App.tsx
@@ -5,30 +5,37 @@ import { QueryClientProvider } from "@tanstack/react-query";
import { queryClient } from "./api/QueryClient";
import { PostHogProvider } from "posthog-js/react";
+import { LoggingContext, loggingStub } from "@/store/LoggingContext";
import { UserContext } from "@/store/UserContext";
const postHogOptions = {
api_host: "https://app.posthog.com",
};
+const getLogging = () => {
+ return loggingStub;
+};
+
const getUser = () => {
return null;
};
function App() {
return (
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/skyvern-frontend/src/hooks/useLogging.ts b/skyvern-frontend/src/hooks/useLogging.ts
new file mode 100644
index 00000000..7ddaaebd
--- /dev/null
+++ b/skyvern-frontend/src/hooks/useLogging.ts
@@ -0,0 +1,9 @@
+import { LoggingContext } from "@/store/LoggingContext";
+import { useContext } from "react";
+
+function useLogging() {
+ const getLogging = useContext(LoggingContext);
+ return getLogging();
+}
+
+export { useLogging };
diff --git a/skyvern-frontend/src/routes/workflows/debugger/DebuggerRun.tsx b/skyvern-frontend/src/routes/workflows/debugger/DebuggerRun.tsx
index 97821c45..bc090a0c 100644
--- a/skyvern-frontend/src/routes/workflows/debugger/DebuggerRun.tsx
+++ b/skyvern-frontend/src/routes/workflows/debugger/DebuggerRun.tsx
@@ -6,13 +6,13 @@ function DebuggerRun() {
const workflowFailureReason = workflowRun?.failure_reason ? (
-
Workflow Failure Reason
+
Run Failure Reason
{workflowRun.failure_reason}
) : null;
diff --git a/skyvern-frontend/src/routes/workflows/editor/nodes/components/NodeHeader.tsx b/skyvern-frontend/src/routes/workflows/editor/nodes/components/NodeHeader.tsx
index cdbb228f..3dd03ca5 100644
--- a/skyvern-frontend/src/routes/workflows/editor/nodes/components/NodeHeader.tsx
+++ b/skyvern-frontend/src/routes/workflows/editor/nodes/components/NodeHeader.tsx
@@ -8,6 +8,7 @@ import { getClient } from "@/api/AxiosClient";
import { ProxyLocation } from "@/api/types";
import { Timer } from "@/components/Timer";
import { toast } from "@/components/ui/use-toast";
+import { useLogging } from "@/hooks/useLogging";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
import { useNodeLabelChangeHandler } from "@/routes/workflows/hooks/useLabelChangeHandler";
@@ -131,6 +132,7 @@ function NodeHeader({
totpUrl,
type,
}: Props) {
+ const log = useLogging();
const {
blockLabel: urlBlockLabel,
workflowPermanentId,
@@ -214,7 +216,7 @@ function NodeHeader({
await saveWorkflow.mutateAsync();
if (!workflowPermanentId) {
- console.error("There is no workflowPermanentId");
+ log.error("Run block: there is no workflowPermanentId");
toast({
variant: "destructive",
title: "Failed to start workflow block run",
@@ -224,7 +226,7 @@ function NodeHeader({
}
if (!debugSession) {
- console.error("There is no debug session, yet");
+ log.error("Run block: there is no debug session, yet");
toast({
variant: "destructive",
title: "Failed to start workflow block run",
@@ -263,6 +265,12 @@ function NodeHeader({
});
if (!body) {
+ log.error("Run block: could not construct run payload", {
+ workflowPermanentId,
+ blockLabel,
+ debugSessionId: debugSession.debug_session_id,
+ browserSessionId: debugSession.browser_session_id,
+ });
toast({
variant: "destructive",
title: "Failed to start workflow block run",
@@ -271,6 +279,13 @@ function NodeHeader({
return;
}
+ log.info("Run block: sending run payload", {
+ workflowPermanentId,
+ blockLabel,
+ debugSessionId: debugSession.debug_session_id,
+ browserSessionId: debugSession.browser_session_id,
+ });
+
return await client.post(
"/run/workflows/blocks",
body,
@@ -278,7 +293,12 @@ function NodeHeader({
},
onSuccess: (response) => {
if (!response) {
- console.error("No response");
+ log.error("Run block: no response", {
+ workflowPermanentId,
+ blockLabel,
+ debugSessionId: debugSession?.debug_session_id,
+ browserSessionId: debugSession?.browser_session_id,
+ });
toast({
variant: "destructive",
title: "Failed to start workflow block run",
@@ -287,6 +307,14 @@ function NodeHeader({
return;
}
+ log.info("Run block: run started", {
+ workflowPermanentId,
+ blockLabel,
+ debugSessionId: debugSession?.debug_session_id,
+ browserSessionId: debugSession?.browser_session_id,
+ runId: response.data.run_id,
+ });
+
toast({
variant: "success",
title: "Workflow block run started",
@@ -299,6 +327,13 @@ function NodeHeader({
},
onError: (error: AxiosError) => {
const detail = (error.response?.data as { detail?: string })?.detail;
+ log.error("Run block: error", {
+ workflowPermanentId,
+ blockLabel,
+ debugSessionId: debugSession?.debug_session_id,
+ browserSessionId: debugSession?.browser_session_id,
+ error,
+ });
toast({
variant: "destructive",
title: "Failed to start workflow block run",
@@ -310,7 +345,10 @@ function NodeHeader({
const cancelBlock = useMutation({
mutationFn: async () => {
if (!debugSession) {
- console.error("Missing debug session");
+ log.error("Cancel block: missing debug session", {
+ workflowPermanentId,
+ blockLabel,
+ });
toast({
variant: "destructive",
title: "Failed to cancel workflow block run",
@@ -326,6 +364,12 @@ function NodeHeader({
.then((response) => response.data);
},
onSuccess: () => {
+ log.info("Cancel block: canceled", {
+ workflowPermanentId,
+ blockLabel,
+ debugSessionId: debugSession?.debug_session_id,
+ browserSessionId: debugSession?.browser_session_id,
+ });
toast({
variant: "success",
title: "Workflow Canceled",
@@ -333,6 +377,13 @@ function NodeHeader({
});
},
onError: (error) => {
+ log.error("Cancel block: error", {
+ workflowPermanentId,
+ blockLabel,
+ debugSessionId: debugSession?.debug_session_id,
+ browserSessionId: debugSession?.browser_session_id,
+ error,
+ });
toast({
variant: "destructive",
title: "Error",
diff --git a/skyvern-frontend/src/store/LoggingContext.ts b/skyvern-frontend/src/store/LoggingContext.ts
new file mode 100644
index 00000000..5ca26187
--- /dev/null
+++ b/skyvern-frontend/src/store/LoggingContext.ts
@@ -0,0 +1,26 @@
+import { createContext } from "react";
+
+type LogFn = (message: string, data?: Record) => void;
+
+interface Logging {
+ info: LogFn;
+ warn: LogFn;
+ error: LogFn;
+}
+
+// make this a stub of LogFn that does nothing
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const noop: LogFn = (..._: Parameters) => {};
+
+const stub: Logging = {
+ info: noop,
+ warn: noop,
+ error: noop,
+};
+
+type GetLogging = () => Logging;
+
+const LoggingContext = createContext(() => stub);
+
+export { LoggingContext, stub as loggingStub };