| 296 | } |
| 297 | |
| 298 | func (l *LogSender) Enqueue(src uuid.UUID, logs ...Log) { |
| 299 | logger := l.logger.With(slog.F("log_source_id", src)) |
| 300 | if len(logs) == 0 { |
| 301 | logger.Debug(context.Background(), "enqueue called with no logs") |
| 302 | return |
| 303 | } |
| 304 | l.L.Lock() |
| 305 | defer l.L.Unlock() |
| 306 | if l.exceededLogLimit { |
| 307 | logger.Warn(context.Background(), "dropping enqueued logs because we have reached the server limit") |
| 308 | // don't error, as we also write to file and don't want the overall write to fail |
| 309 | return |
| 310 | } |
| 311 | defer l.Broadcast() |
| 312 | q, ok := l.queues[src] |
| 313 | if !ok { |
| 314 | q = &logQueue{} |
| 315 | l.queues[src] = q |
| 316 | } |
| 317 | for k, log := range logs { |
| 318 | // Here we check the queue size before adding a log because we want to queue up slightly |
| 319 | // more logs than the database would store to ensure we trigger "logs truncated" at the |
| 320 | // database layer. Otherwise, the end user wouldn't know logs are truncated unless they |
| 321 | // examined the Coder agent logs. |
| 322 | if l.outputLen > maxBytesQueued { |
| 323 | logger.Warn(context.Background(), "log queue full; truncating new logs", slog.F("new_logs", k), slog.F("queued_logs", len(q.logs))) |
| 324 | return |
| 325 | } |
| 326 | pl, err := ProtoFromLog(log) |
| 327 | if err != nil { |
| 328 | logger.Critical(context.Background(), "failed to convert log", slog.Error(err)) |
| 329 | pl = &proto.Log{ |
| 330 | CreatedAt: timestamppb.Now(), |
| 331 | Level: proto.Log_ERROR, |
| 332 | Output: "**Coder Internal Error**: Failed to convert log", |
| 333 | } |
| 334 | } |
| 335 | if len(pl.Output)+overheadPerLog > maxBytesPerBatch { |
| 336 | logger.Warn(context.Background(), "dropping log line that exceeds our limit", slog.F("len", len(pl.Output))) |
| 337 | continue |
| 338 | } |
| 339 | q.logs = append(q.logs, pl) |
| 340 | l.outputLen += len(pl.Output) |
| 341 | } |
| 342 | logger.Debug(context.Background(), "enqueued agent logs", slog.F("new_logs", len(logs)), slog.F("queued_logs", len(q.logs))) |
| 343 | } |
| 344 | |
| 345 | func (l *LogSender) Flush(src uuid.UUID) { |
| 346 | l.L.Lock() |