Skip to content

Commit 940afa1

Browse files
authored
fix: let workspace pages download partial logs for unhealthy workspaces (coder#13761)
* fix: get basic fix in for preventing download logs from blowing up UI * fix: make sure blob units can't go out of bounds * fix: make sure timeout is cleared on component unmount * fix: reduce risk of shared cache state breaking useAgentLogs * fix: allow partial downloading of logs * fix: make sure useMemo cache is used properly * wip: commit current progress on updated logs functionality * docs: rewrite comment for clarity * refactor: clean up current code * fix: update styles for unavailable logs * fix: resolve linter violations * fix: update type signature of getErrorDetail * fix: revert log/enabled logic for useAgentLogs * fix: remove memoization from DownloadLogsDialog * fix: update name of timeout state * refactor: make log web sockets logic more clear * docs: reword comment for clarity * fix: commit current style update progress * fix: finish style updates
1 parent 07d4171 commit 940afa1

File tree

3 files changed

+234
-69
lines changed

3 files changed

+234
-69
lines changed

site/src/api/errors.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,18 @@ export const getValidationErrorMessage = (error: unknown): string => {
110110
return validationErrors.map((error) => error.detail).join("\n");
111111
};
112112

113-
export const getErrorDetail = (error: unknown): string | undefined | null => {
113+
export const getErrorDetail = (error: unknown): string | undefined => {
114114
if (error instanceof Error) {
115115
return "Please check the developer console for more details.";
116116
}
117+
117118
if (isApiError(error)) {
118119
return error.response.data.detail;
119120
}
121+
120122
if (isApiErrorResponse(error)) {
121123
return error.detail;
122124
}
123-
return null;
125+
126+
return undefined;
124127
};

site/src/modules/resources/AgentLogs/useAgentLogs.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,35 @@ export type UseAgentLogsOptions = Readonly<{
1515
enabled?: boolean;
1616
}>;
1717

18+
/**
19+
* Defines a custom hook that gives you all workspace agent logs for a given
20+
* workspace.
21+
*
22+
* Depending on the status of the workspace, all logs may or may not be
23+
* available.
24+
*/
1825
export function useAgentLogs(
1926
options: UseAgentLogsOptions,
2027
): readonly WorkspaceAgentLog[] | undefined {
2128
const { workspaceId, agentId, agentLifeCycleState, enabled = true } = options;
29+
2230
const queryClient = useQueryClient();
2331
const queryOptions = agentLogs(workspaceId, agentId);
24-
const query = useQuery({
25-
...queryOptions,
26-
enabled,
27-
});
28-
const logs = query.data;
32+
const { data: logs, isFetched } = useQuery({ ...queryOptions, enabled });
2933

34+
// Track the ID of the last log received when the initial logs response comes
35+
// back. If the logs are not complete, the ID will mark the start point of the
36+
// Web sockets response so that the remaining logs can be received over time
3037
const lastQueriedLogId = useRef(0);
3138
useEffect(() => {
32-
if (logs && lastQueriedLogId.current === 0) {
33-
lastQueriedLogId.current = logs[logs.length - 1].id;
39+
const isAlreadyTracking = lastQueriedLogId.current !== 0;
40+
if (isAlreadyTracking) {
41+
return;
42+
}
43+
44+
const lastLog = logs?.at(-1);
45+
if (lastLog !== undefined) {
46+
lastQueriedLogId.current = lastLog.id;
3447
}
3548
}, [logs]);
3649

@@ -42,7 +55,7 @@ export function useAgentLogs(
4255
});
4356

4457
useEffect(() => {
45-
if (agentLifeCycleState !== "starting" || !query.isFetched) {
58+
if (agentLifeCycleState !== "starting" || !isFetched) {
4659
return;
4760
}
4861

@@ -69,7 +82,7 @@ export function useAgentLogs(
6982
return () => {
7083
socket.close();
7184
};
72-
}, [addLogs, agentId, agentLifeCycleState, query.isFetched]);
85+
}, [addLogs, agentId, agentLifeCycleState, isFetched]);
7386

7487
return logs;
7588
}

0 commit comments

Comments
 (0)