SendLoop sends any pending logs until it hits an error or the context is canceled. It does not retry as it is expected that a higher layer retries establishing connection to the agent API and calls SendLoop again.
(ctx context.Context, dest LogDest)
| 360 | // retry as it is expected that a higher layer retries establishing connection to the agent API and |
| 361 | // calls SendLoop again. |
| 362 | func (l *LogSender) SendLoop(ctx context.Context, dest LogDest) error { |
| 363 | l.L.Lock() |
| 364 | defer l.L.Unlock() |
| 365 | if l.exceededLogLimit { |
| 366 | l.logger.Debug(ctx, "aborting SendLoop because log limit is already exceeded") |
| 367 | return ErrLogLimitExceeded |
| 368 | } |
| 369 | |
| 370 | ctxDone := false |
| 371 | defer l.logger.Debug(ctx, "log sender send loop exiting") |
| 372 | |
| 373 | // wake 4 times per Flush interval to check if anything needs to be flushed |
| 374 | ctx, cancel := context.WithCancel(ctx) |
| 375 | defer cancel() |
| 376 | go func() { |
| 377 | tkr := time.NewTicker(flushInterval / 4) |
| 378 | defer tkr.Stop() |
| 379 | for { |
| 380 | select { |
| 381 | // also monitor the context here, so we notice immediately, rather |
| 382 | // than waiting for the next tick or logs |
| 383 | case <-ctx.Done(): |
| 384 | l.L.Lock() |
| 385 | ctxDone = true |
| 386 | l.L.Unlock() |
| 387 | l.Broadcast() |
| 388 | return |
| 389 | case <-tkr.C: |
| 390 | l.Broadcast() |
| 391 | } |
| 392 | } |
| 393 | }() |
| 394 | |
| 395 | for { |
| 396 | for !ctxDone && !l.hasPendingWorkLocked() { |
| 397 | l.Wait() |
| 398 | } |
| 399 | if ctxDone { |
| 400 | return ctx.Err() |
| 401 | } |
| 402 | |
| 403 | src, q := l.getPendingWorkLocked() |
| 404 | logger := l.logger.With(slog.F("log_source_id", src)) |
| 405 | q.flushRequested = false // clear flag since we're now flushing |
| 406 | req := &proto.BatchCreateLogsRequest{ |
| 407 | LogSourceId: src[:], |
| 408 | } |
| 409 | |
| 410 | // outputToSend keeps track of the size of the protobuf message we send, while |
| 411 | // outputToRemove keeps track of the size of the output we'll remove from the queues on |
| 412 | // success. They are different because outputToSend also counts protocol message overheads. |
| 413 | outputToSend := 0 |
| 414 | outputToRemove := 0 |
| 415 | n := 0 |
| 416 | for n < len(q.logs) { |
| 417 | log := q.logs[n] |
| 418 | outputToSend += len(log.Output) + overheadPerLog |
| 419 | if outputToSend > maxBytesPerBatch { |