Go SDK · BufferedRecorder
The default recorder buffers events in memory and flushes in batches. Constructor:
rec := recorder.New(projectID, apiKey, opts...)
// or
rec := es.NewRecorder(opts...)
Options
| Option | Default | Purpose |
|---|---|---|
WithBufferSize(n) |
1000 |
Capacity of the in-memory event buffer. |
WithFlushSize(n) |
100 |
Pending-event count that triggers an immediate flush. |
WithFlushInterval(d) |
5s |
Max time between flushes when the size threshold isn't reached. |
WithFlushTimeout(d) |
30s |
Context timeout per flush call against the inner recorder. |
WithOverflowPolicy(p) |
PolicyDropNewest |
Behavior when Record finds the buffer full. |
WithDrainTimeout(d) |
30s |
Max time Close waits for in-flight events. |
WithSlogLogger(l) |
slog.Default() |
Logger for diagnostics (overflow warnings, flush errors). |
WithBaseURL(url) |
production | Override the ingestion endpoint (tests, staging). |
WithHTTPClient(c) |
Timeout: 10s |
Custom *http.Client. |
WithAutoIdempotencyKey() |
off | Copy Event.ID into IdempotencyKey when the latter is empty. |
Overflow policies
recorder.PolicyDropNewest // drop the incoming event, log a warning (default)
recorder.PolicyBlock // block until space frees or ctx cancels
recorder.PolicyError // return ErrBufferFull
Close & flush
Close()synchronously drains pending events (respectsWithDrainTimeout). Call it exactly once, on the path that actually runs at shutdown. It returnscontext.DeadlineExceededwhen the drain timed out with events still pending, so log what it returns.Flush(ctx)drains buffered events at call time. Useful in tests and for graceful shutdown sequences that need to observe drain success.Stats()returns aBufferedStatswithDropped,Flushed,FlushErrs,Pending,BufferSizefor observability.
Where Close goes
In a short-lived program (a CLI, a cron job, a one-shot script) whose main returns, defer rec.Close() at construction is correct.
In a server it is not. main blocks in ListenAndServe until a signal kills the process, so the deferred call never executes, and a log.Fatal on the error path is os.Exit, which also skips defers. Either way the buffer is discarded, and the events you lose are the ones recorded just before a deploy or a crash. Wire the close to a real shutdown instead:
// imports: context, errors, log, net/http, os, os/signal, syscall
ctx, stop := signal.NotifyContext(context.Background(),
os.Interrupt, syscall.SIGTERM)
defer stop()
srv := &http.Server{Addr: ":" + port, Handler: root}
go func() {
if err := srv.ListenAndServe(); err != nil &&
!errors.Is(err, http.ErrServerClosed) {
log.Print(err)
stop()
}
}()
<-ctx.Done()
if err := srv.Shutdown(context.Background()); err != nil {
log.Print(err)
}
if err := rec.Close(); err != nil { // runs, and drains
log.Printf("everscribe: drain incomplete: %v", err)
}
Close the recorder after srv.Shutdown returns, never before: in-flight requests keep recording events until it does.