streamLogs handles streaming or fetching startup logs. nolint:revive // Control flag is acceptable for internal method.
(ctx context.Context, agent codersdk.WorkspaceAgent, follow bool, fetchedAgent chan fetchAgentResult)
| 269 | // |
| 270 | //nolint:revive // Control flag is acceptable for internal method. |
| 271 | func (aw *agentWaiter) streamLogs(ctx context.Context, agent codersdk.WorkspaceAgent, follow bool, fetchedAgent chan fetchAgentResult) (codersdk.WorkspaceAgent, error) { |
| 272 | logStream, logsCloser, err := aw.opts.FetchLogs(ctx, agent.ID, 0, follow) |
| 273 | if err != nil { |
| 274 | return agent, xerrors.Errorf("fetch workspace agent startup logs: %w", err) |
| 275 | } |
| 276 | defer logsCloser.Close() |
| 277 | |
| 278 | var lastLog codersdk.WorkspaceAgentLog |
| 279 | |
| 280 | // If not following, we don't need to watch for agent state changes. |
| 281 | var fetchedAgentWhileFollowing chan fetchAgentResult |
| 282 | if follow { |
| 283 | fetchedAgentWhileFollowing = fetchedAgent |
| 284 | } |
| 285 | |
| 286 | for { |
| 287 | select { |
| 288 | case <-ctx.Done(): |
| 289 | return agent, ctx.Err() |
| 290 | case f := <-fetchedAgentWhileFollowing: |
| 291 | if f.err != nil { |
| 292 | return agent, xerrors.Errorf("fetch: %w", f.err) |
| 293 | } |
| 294 | agent = f.agent |
| 295 | |
| 296 | // If the agent is no longer starting, stop following |
| 297 | // logs because FetchLogs will keep streaming forever. |
| 298 | // We do one last non-follow request to ensure we have |
| 299 | // fetched all logs. |
| 300 | if !agent.LifecycleState.Starting() { |
| 301 | _ = logsCloser.Close() |
| 302 | fetchedAgentWhileFollowing = nil |
| 303 | |
| 304 | logStream, logsCloser, err = aw.opts.FetchLogs(ctx, agent.ID, lastLog.ID, false) |
| 305 | if err != nil { |
| 306 | return agent, xerrors.Errorf("fetch workspace agent startup logs: %w", err) |
| 307 | } |
| 308 | // Logs are already primed, so we can call close. |
| 309 | _ = logsCloser.Close() |
| 310 | } |
| 311 | case logs, ok := <-logStream: |
| 312 | if !ok { |
| 313 | return agent, nil |
| 314 | } |
| 315 | for _, log := range logs { |
| 316 | source, hasSource := aw.logSources[log.SourceID] |
| 317 | output := log.Output |
| 318 | if hasSource && source.DisplayName != "" { |
| 319 | output = source.DisplayName + ": " + output |
| 320 | } |
| 321 | aw.sw.Log(log.CreatedAt, log.Level, output) |
| 322 | lastLog = log |
| 323 | } |
| 324 | } |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | // waitForReconnection handles the Disconnected state. |