Channel
A generic, telemetry-aware channel wrapper. Provides observable Send and Receive operations with opt-in/out metrics and tracing.
Lives in the github.com/foomo/gofuncy/channel subpackage.
Signature
func New[T any](opts ...Option[T]) *Channel[T]Type Parameters
| Parameter | Description |
|---|---|
T | The type of values sent through the channel. |
Parameters
| Parameter | Type | Description |
|---|---|---|
opts | ...Option[T] | Functional options to configure the channel. |
Options
Defaults
| Feature | Default | Option |
|---|---|---|
| Name | "gofuncy.channel" | WithName[T](name) |
| Buffer size | 0 (unbuffered) | WithBuffer[T](size) |
| Logger | slog.Default() | WithLogger[T](l) |
Chans counter (gofuncy.chans.current) | on | WithoutChansCounter[T]() |
Messages sent counter (gofuncy.messages.sent) | on | WithoutMessagesSentCounter[T]() |
Duration histogram (gofuncy.messages.duration.seconds) | off | WithDurationHistogram[T]() |
| Tracing | off | WithTracing[T]() |
| Meter provider | OTel global | WithMeterProvider[T](mp) |
| Tracer provider | OTel global | WithTracerProvider[T](tp) |
TIP
Counters are cheap and enabled by default. Duration histogram and tracing are opt-in because they add overhead on every Send call. This matches the convention used by Go, Do, Wait, and Group.
Behavior
Newcreates the underlying Go channel and initializes telemetry instruments based on the enabled options.- If the chans counter is enabled, the channel increments
gofuncy.chans.currenton creation and decrements it onClose. Sendwrites values to the channel one at a time. For each value:- If the context is cancelled, returns the context error immediately.
- If the channel is closed, returns
channel.ErrClosed. - If the messages sent counter is enabled, increments
gofuncy.messages.sent. - If the duration histogram is enabled, records the time spent waiting for the channel to accept the value (backpressure detection).
- If tracing is enabled, adds a span event for each sent value.
Receivereturns the raw underlying<-chan T. This is zero-allocation and works withrange.Closeis idempotent — safe to call multiple times. It broadcasts to all blocked senders, then closes the underlying channel.
Methods
Send
func (c *Channel[T]) Send(ctx context.Context, values ...T) errorSends one or more values into the channel. Returns channel.ErrClosed if the channel has been closed, or the context error if the context is cancelled while waiting.
Receive
func (c *Channel[T]) Receive() <-chan TReturns a read-only view of the underlying channel. Use with range or select.
Close
func (c *Channel[T]) Close()Closes the channel. Idempotent — subsequent calls are no-ops. Unblocks any goroutines waiting in Send.
Len / Cap / Name
func (c *Channel[T]) Len() int
func (c *Channel[T]) Cap() int
func (c *Channel[T]) Name() stringReturn the current number of buffered values, the buffer capacity, and the channel name.
Example
package main
import (
"context"
"fmt"
"time"
"github.com/foomo/gofuncy"
"github.com/foomo/gofuncy/channel"
)
func main() {
ctx := context.Background()
// Create a buffered channel with default telemetry (counters on)
ch := channel.New[string](channel.WithBuffer[string](10))
// Producer
gofuncy.Go(ctx, func(ctx context.Context) error {
defer ch.Close()
for i := range 5 {
if err := ch.Send(ctx, fmt.Sprintf("event-%d", i)); err != nil {
return err
}
}
return nil
})
// Consumer
for msg := range ch.Receive() {
fmt.Println(msg)
}
time.Sleep(100 * time.Millisecond)
}Telemetry Metrics
| Metric | Type | Description |
|---|---|---|
gofuncy.chans.current | UpDownCounter | Number of open channels. Attributes: gofuncy.chan.name, gofuncy.chan.cap. |
gofuncy.messages.sent | Counter | Total messages sent. Attributes: gofuncy.chan.name. |
gofuncy.messages.duration.seconds | Histogram | Time spent waiting for the channel to accept a value. High values indicate backpressure. Attributes: gofuncy.chan.name. |
WARNING
Receive() returns the raw Go channel. The gofuncy.messages.sent counter tracks total sends only — it is not decremented on receive. To detect stuck or filling channels, compare the sent counter growth over time or use the duration histogram to measure backpressure.
