The Go runtime exposes credential- and payload-free diagnostics, a bounded lifecycle observer, and an optional OpenTelemetry module. Observer and telemetry failures are isolated from send results.
Diagnostics#
Diagnostics returns one coherent snapshot of current resource use and saturating counters:
snapshot := client.Diagnostics()
log.Printf(
"in_flight=%d buffered_bytes=%d overloads=%d dropped_events=%d",
snapshot.InFlightOperations,
snapshot.BufferedBytes,
snapshot.ConcurrencyOverloadRejections,
snapshot.DroppedObserverEvents,
)| Field | Meaning |
|---|---|
InFlightOperations | Operations currently holding admission. |
BufferedBytes | Request, response, and parser bytes currently reserved. |
ConcurrencyOverloadRejections | Operations rejected by the in-flight limit. |
ByteOverloadRejections | Operations rejected by the aggregate byte limit. |
ResponseHeaderLimitFailures | Responses rejected by header bounds. |
ResponseCloseFailures | Response cleanup failures. |
DroppedObserverEvents | Lifecycle events dropped because the observer queue was full. |
ObserverFailures | Observer callback panics recovered by the runtime. |
TelemetryFailures | Telemetry panics recovered by the runtime. |
Closed | Whether the client has begun shutdown. |
The snapshot contains no event payload, customer ID, idempotency key, URL, header value, or credential.
Lifecycle observers#
Pass an Observer when constructing the generated client:
client, err := repostclient.NewClient(repost.ClientOptions{
Observer: func(event repost.ObserverEvent) {
if event.Kind == repost.ObserverEventKindOperationEnd {
recordOutcome(event.Outcome, event.ErrorCode, event.DeliveryState)
}
},
})| Event kind | Emitted when |
|---|---|
operation.start | An operation passes admission. |
attempt.start | One transport attempt starts. |
attempt.end | One attempt settles. |
retry.delay | The runtime schedules a retry wait. |
operation.cancel | Caller cancellation is observed. |
operation.end | The final delivery state is known. |
Events contain stable outcomes, error codes, delivery states, HTTP status classes, durations, attempt numbers, and bounded attempt summaries. They contain no request or response bodies, headers, credentials, customer IDs, idempotency keys, or URLs.
The queue holds at most 1,024 events. Callbacks run serially on a dedicated goroutine outside send and transport paths. When the queue is full, new events are dropped and counted instead of blocking a send. A callback panic increments ObserverFailures without changing the operation result.
Keep callbacks fast. Send events to your own bounded metrics or logging layer if processing needs more time.
OpenTelemetry#
The OpenTelemetry bridge is a separate Go module so applications that do not use OpenTelemetry do not inherit its dependencies. Install it with:
go get github.com/repost-sh/repost-go/[email protected]Use global providers:
client, err := repostclient.NewClient(repost.ClientOptions{
Telemetry: otelrepost.Telemetry(),
Observer: otelrepost.MetricsObserver(),
})Or pass providers owned by your application:
client, err := repostclient.NewClient(repost.ClientOptions{
Telemetry: otelrepost.Telemetry(
otelrepost.WithTracerProvider(tracerProvider),
),
Observer: otelrepost.MetricsObserver(
otelrepost.WithMeterProvider(meterProvider),
),
})The bridge borrows providers. Closing the Repost client does not shut them down.
Traces#
The bridge creates one repost.send span and one repost.send.attempt child for each attempt. Passing an inbound request context to a generated send keeps the inbound span as the parent of repost.send.
Attempt spans use http.request.method, repost.retry.attempt, network.protocol.name, http.response.status_code, and error.type. The bridge propagates only W3C traceparent and tracestate headers supplied by the tracing context.
Metrics#
| Metric | Unit |
|---|---|
repost.client.operations | operations |
repost.client.operation.duration | ms |
repost.client.attempts | attempts |
repost.client.attempt.duration | ms |
repost.client.retry.delay | ms |
Metrics use only outcome, error.code, delivery.state, and http.status.class. The bridge does not accept arbitrary customer labels.