Returns provisioner logs based on query parameters. The intended usage for a client to stream all logs (with JS API): GET /logs GET /logs?after= &follow The combination of these responses should provide all current logs to the consumer, and future logs are streamed in the follow request.
(rw http.ResponseWriter, r *http.Request, job database.ProvisionerJob)
| 152 | // The combination of these responses should provide all current logs |
| 153 | // to the consumer, and future logs are streamed in the follow request. |
| 154 | func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job database.ProvisionerJob) { |
| 155 | var ( |
| 156 | ctx = r.Context() |
| 157 | logger = api.Logger.With(slog.F("job_id", job.ID)) |
| 158 | follow = r.URL.Query().Has("follow") |
| 159 | afterRaw = r.URL.Query().Get("after") |
| 160 | format = r.URL.Query().Get("format") |
| 161 | ) |
| 162 | |
| 163 | // Validate format parameter. |
| 164 | if format == "" { |
| 165 | format = "json" |
| 166 | } |
| 167 | if format != "json" && format != "text" { |
| 168 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 169 | Message: "Invalid format parameter.", |
| 170 | Detail: "Allowed values are \"json\" and \"text\".", |
| 171 | }) |
| 172 | return |
| 173 | } |
| 174 | |
| 175 | // Text format is not supported with streaming. |
| 176 | if format == "text" && follow { |
| 177 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 178 | Message: "Text format is not supported with follow mode.", |
| 179 | Detail: "Use format=json or omit the follow parameter.", |
| 180 | }) |
| 181 | return |
| 182 | } |
| 183 | |
| 184 | var after int64 |
| 185 | // Only fetch logs created after the time provided. |
| 186 | if afterRaw != "" { |
| 187 | var err error |
| 188 | after, err = strconv.ParseInt(afterRaw, 10, 64) |
| 189 | if err != nil { |
| 190 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 191 | Message: "Query param \"after\" must be an integer.", |
| 192 | Validations: []codersdk.ValidationError{ |
| 193 | {Field: "after", Detail: "Must be an integer"}, |
| 194 | }, |
| 195 | }) |
| 196 | return |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | if !follow { |
| 201 | fetchAndWriteLogs(ctx, api.Database, job.ID, after, rw, format) |
| 202 | return |
| 203 | } |
| 204 | |
| 205 | follower := newLogFollower(ctx, logger, api.Database, api.Pubsub, rw, r, job, after) |
| 206 | api.WebsocketWaitMutex.Lock() |
| 207 | api.WebsocketWaitGroup.Add(1) |
| 208 | api.WebsocketWaitMutex.Unlock() |
| 209 | defer api.WebsocketWaitGroup.Done() |
| 210 | follower.follow() |
| 211 | } |
no test coverage detected