Documentation
¶
Overview ¶
Package wsstat measures the latency of WebSocket connections. It wraps the coder/websocket package and includes latency measurements in the Result struct.
Index ¶
- Constants
- Variables
- type CertificateDetails
- type Option
- func WithBufferSize(n int) Option
- func WithCloseGrace(d time.Duration) Option
- func WithCompression(enabled bool) Option
- func WithHeaders(headers http.Header) Option
- func WithLogger(logger zerolog.Logger) Option
- func WithReadLimit(n int64) Option
- func WithResolves(resolves map[string]string) Option
- func WithSubprotocols(subprotocols []string) Option
- func WithTLSConfig(cfg *tls.Config) Option
- func WithTimeout(d time.Duration) Option
- func WithValidateUTF8(enabled bool) Option
- type Result
- func MeasureJSON(ctx context.Context, target *url.URL, msgs []any, opts ...Option) (*Result, []any, error)
- func MeasurePing(ctx context.Context, target *url.URL, count int, opts ...Option) (*Result, error)
- func MeasureText(ctx context.Context, target *url.URL, msgs []string, opts ...Option) (*Result, []string, error)
- type Subscription
- type SubscriptionMessage
- type SubscriptionOptions
- type SubscriptionStats
- type WSStat
- func (ws *WSStat) Close()
- func (ws *WSStat) CloseWith(code int, reason string) error
- func (ws *WSStat) DialContext(ctx context.Context, targetURL *url.URL, customHeaders http.Header) error
- func (ws *WSStat) ExtractResult() *Result
- func (ws *WSStat) PingPong() error
- func (ws *WSStat) ReadMessage() (int, []byte, error)
- func (ws *WSStat) ReadMessageJSON() (any, error)
- func (ws *WSStat) Subscribe(ctx context.Context, opts SubscriptionOptions) (*Subscription, error)
- func (ws *WSStat) SubscribeOnce(ctx context.Context, opts SubscriptionOptions) (SubscriptionMessage, error)
- func (ws *WSStat) WriteMessage(messageType int, data []byte)
- func (ws *WSStat) WriteMessageJSON(v any)
Constants ¶
const ( // TextMessage denotes a UTF-8 encoded text message (e.g. JSON). Numerically identical to // websocket.MessageText so the public int-based API stays stable across the transport swap. TextMessage = 1 // BinaryMessage denotes a binary data message. Numerically identical to // websocket.MessageBinary. BinaryMessage = 2 )
Variables ¶
var ( // ErrConnectionNotEstablished is returned when a read or ping is attempted before a // successful dial. ErrConnectionNotEstablished = errors.New("wsstat: connection not established") // ErrClosed is returned when an operation is attempted on a closed connection. ErrClosed = errors.New("wsstat: connection closed") )
Exported error sentinels for the failure classes library consumers branch on. Returned (via errors.Is) by the connection methods; the one-shot Measure* functions propagate them.
Functions ¶
This section is empty.
Types ¶
type CertificateDetails ¶
type CertificateDetails struct {
CommonName string
Issuer string
NotBefore time.Time
NotAfter time.Time
PublicKeyAlgorithm x509.PublicKeyAlgorithm
SignatureAlgorithm x509.SignatureAlgorithm
DNSNames []string
IPAddresses []net.IP
URIs []*url.URL
}
CertificateDetails holds details regarding a certificate.
type Option ¶
type Option func(*options)
Option configures a WSStat instance.
func WithBufferSize ¶
WithBufferSize sets the buffer size for read/write/pong channels.
func WithCloseGrace ¶
WithCloseGrace bounds how long Close waits for the peer's closing-handshake echo before forcing the connection shut. Zero or negative fires the teardown immediately rather than granting a grace window; a peer that echoes in that instant may still complete the handshake cleanly. Defaults to 3s.
Only values below 5s take effect: the underlying coder/websocket library caps its own close handshake at a hard-coded 5s, so Close returns by then regardless and a larger grace cannot extend the wait. The useful range is (0, 5s).
func WithCompression ¶
WithCompression enables negotiation of the permessage-deflate extension. Disabled by default. The negotiated extension is reported in Result.Compression.
func WithHeaders ¶
WithHeaders sets HTTP headers merged into every handshake request. Headers passed directly to Dial/DialContext take precedence over these on a per-key basis.
func WithLogger ¶
WithLogger sets the logger for the WSStat instance.
func WithReadLimit ¶
WithReadLimit bounds the size in bytes of a single inbound message. A value of 0 keeps the default (16 MiB); a negative value disables the limit (use with care: an unbounded message can exhaust memory). Defaults to 16 MiB.
func WithResolves ¶
WithResolves sets DNS resolution overrides for specific host:port combinations. Map key format: "host:port", value: "ip_address".
func WithSubprotocols ¶
WithSubprotocols sets the WebSocket subprotocols to offer during the handshake, in preference order. The negotiated value is reported in Result.Subprotocol.
func WithTLSConfig ¶
WithTLSConfig sets the TLS configuration for the connection.
func WithTimeout ¶
WithTimeout sets the timeout used for dialing and read deadlines.
func WithValidateUTF8 ¶
WithValidateUTF8 enables UTF-8 validation of inbound text frames. coder/websocket performs none (RFC 6455 §5.6 requires text payloads to be valid UTF-8); when enabled, an invalid text frame is logged at warn level and counted in Result.InvalidUTF8Frames rather than failing the connection. Disabled by default.
type Result ¶
type Result struct {
IPs []string // IP addresses of the WebSocket connection
URL *url.URL // URL of the WebSocket connection
Subprotocol string // Negotiated WebSocket subprotocol ("" if none)
Compression string // Negotiated Sec-WebSocket-Extensions value ("" if none)
RequestHeaders http.Header // Headers of the initial request
ResponseHeaders http.Header // Headers of the response
TLSState *tls.ConnectionState // State of the TLS connection
MessageCount int // Number of messages sent and received
// InvalidUTF8Frames counts inbound text frames that failed UTF-8 validation. Always 0
// unless WithValidateUTF8 is set (coder/websocket does not validate text frames itself).
InvalidUTF8Frames int
// Subscription statistics captured when long-lived streams are active.
Subscriptions map[string]SubscriptionStats // Metrics by subscription ID
SubscriptionFirstEvent time.Duration // Time until first subscription event
SubscriptionLastEvent time.Duration // Time until last subscription event
// Duration of each phase of the connection
DNSLookup time.Duration // Time to resolve DNS
TCPConnection time.Duration // TCP connection establishment time
TLSHandshake time.Duration // Time to perform TLS handshake
WSHandshake time.Duration // Time to perform WebSocket handshake
MessageRTT time.Duration // Time to send message and receive response
// Cumulative durations over the connection timeline
DNSLookupDone time.Duration // Time to resolve DNS (might be redundant with DNSLookup)
TCPConnected time.Duration // Time until the TCP connection is established
TLSHandshakeDone time.Duration // Time until the TLS handshake is completed
WSHandshakeDone time.Duration // Time until the WS handshake is completed
FirstMessageResponse time.Duration // Time until the first message is received
TotalTime time.Duration // Total time from opening to closing the connection
}
Result holds durations of each phase of a WebSocket connection, cumulative durations over the connection timeline, and other relevant connection details.
func MeasureJSON ¶
func MeasureJSON( ctx context.Context, target *url.URL, msgs []any, opts ...Option, ) (*Result, []any, error)
MeasureJSON behaves like MeasureText but encodes each element of msgs as JSON and decodes each response as JSON. Settings are supplied via opts.
func MeasurePing ¶
func MeasurePing( ctx context.Context, target *url.URL, count int, opts ...Option, ) (*Result, error)
MeasurePing establishes a connection to target, performs count ping/pong round-trips, closes the connection, and returns the measured Result. Settings are supplied via opts.
func MeasureText ¶
func MeasureText( ctx context.Context, target *url.URL, msgs []string, opts ...Option, ) (*Result, []string, error)
MeasureText establishes a WebSocket connection to target, sends each message in msgs as a text frame, reads one response per message, closes the connection, and returns the measured Result together with the responses in order. A single message is a one-element slice. Custom headers and other settings are supplied via opts (e.g. WithHeaders, WithTimeout). The whole operation honors ctx; a nil or already-canceled ctx aborts before dialing.
func (*Result) CertificateDetails ¶
func (r *Result) CertificateDetails() []CertificateDetails
CertificateDetails returns a slice of CertificateDetails for each certificate in the TLS connection.
type Subscription ¶
type Subscription struct {
ID string
// contains filtered or unexported fields
}
Subscription captures a long-lived stream registered through Subscribe. Counters are updated atomically by the WSStat instance.
func (*Subscription) ByteCount ¶
func (s *Subscription) ByteCount() uint64
ByteCount reports the aggregate payload size delivered to the subscription.
func (*Subscription) Cancel ¶
func (s *Subscription) Cancel()
Cancel stops the subscription and prevents further deliveries.
func (*Subscription) Done ¶
func (s *Subscription) Done() <-chan struct{}
Done returns a channel that closes once the subscription is fully torn down.
func (*Subscription) MessageCount ¶
func (s *Subscription) MessageCount() uint64
MessageCount reports the total number of messages delivered to the subscription.
func (*Subscription) Unsubscribe ¶
func (s *Subscription) Unsubscribe()
Unsubscribe is an alias for Cancel and preserves semantic clarity for callers.
func (*Subscription) Updates ¶
func (s *Subscription) Updates() <-chan SubscriptionMessage
Updates exposes the buffered stream of subscription messages.
type SubscriptionMessage ¶
type SubscriptionMessage struct {
MessageType int
Data []byte
Decoded any
Received time.Time
Err error
Size int
}
SubscriptionMessage represents a single frame delivered to a subscription consumer.
type SubscriptionOptions ¶
type SubscriptionOptions struct {
// ID can be provided to preassign a human-readable identifier. If empty, WSStat
// allocates an incremental identifier.
ID string
// MessageType and Payload describe the initial frame sent to initiate the subscription.
MessageType int
Payload []byte
// Buffer controls the per-subscription delivery queue length. Zero implies the default.
Buffer int
// contains filtered or unexported fields
}
SubscriptionOptions configures how WSStat establishes and demultiplexes a subscription.
type SubscriptionStats ¶
type SubscriptionStats struct {
FirstEvent time.Duration
LastEvent time.Duration
MessageCount uint64
ByteCount uint64
MeanInterArrival time.Duration
Error error
}
SubscriptionStats snapshots per-subscription metrics for reporting through Result.
type WSStat ¶
type WSStat struct {
// contains filtered or unexported fields
}
WSStat wraps the coder/websocket package with latency measuring capabilities.
Concurrency: DialContext must complete (single-threaded) before any other method is called. After a successful dial, ExtractResult and Close are safe to call concurrently with each other and with the read/write/subscription methods; ExtractResult takes a consistent snapshot even while Close is finalizing the Result. Close is idempotent and may be called from multiple goroutines. WriteMessage/WriteMessageJSON and ReadMessage/ReadMessageJSON/PingPong are not internally serialized against each other: concurrent writers (or concurrent readers) interleave on the shared channels, so callers that need ordering must coordinate it. Subscribe/SubscribeOnce are safe to call concurrently.
func New ¶
New creates and returns a new WSStat instance. To adjust channel buffer size or timeouts, use options. If not provided, package defaults are used for compatibility.
func (*WSStat) Close ¶
func (ws *WSStat) Close()
Close closes the WebSocket connection and cleans up the WSStat instance. Sets result times: CloseDone
func (*WSStat) CloseWith ¶
CloseWith closes the connection sending a chosen close code and reason in the RFC 6455 closing handshake, instead of Close's default StatusNormalClosure (1000) with an empty reason. code must be a sendable close status (1000-1003, 1007-1011, or 3000-4999) and reason at most 123 bytes (the control-frame payload limit minus the 2-byte code); an invalid code or over-long reason returns an error without closing. Returns ErrClosed if the connection is already closing. Otherwise teardown proceeds exactly as Close, which it calls; like Close it is idempotent, but the code/reason only take effect when CloseWith wins the race to initiate the close.
func (*WSStat) DialContext ¶
func (ws *WSStat) DialContext( ctx context.Context, targetURL *url.URL, customHeaders http.Header, ) error
DialContext establishes a new WebSocket connection bound to ctx. Canceling ctx (or calling Close) tears down the connection and unblocks in-flight reads and writes. If required, specify custom headers to merge with the default headers. Sets times: dialStart, wsHandshakeDone
func (*WSStat) ExtractResult ¶
ExtractResult calculate the current results and returns a copy of the Result object. Safe to call concurrently with the read/write/subscription methods and with Close.
func (*WSStat) PingPong ¶
PingPong sends a ping through the WebSocket connection and blocks until the matching pong is received. coder's Ping is a synchronous round-trip, so both the write and read timings are recorded around the single call. Sets result times: MessageReads, MessageWrites
func (*WSStat) ReadMessage ¶
ReadMessage reads a message from the WebSocket connection and measures the round-trip time. If an error occurs, it will be returned. Sets time: MessageReads
func (*WSStat) ReadMessageJSON ¶
ReadMessageJSON reads a message from the WebSocket connection and measures the round-trip time. Sets time: MessageReads
func (*WSStat) Subscribe ¶
func (ws *WSStat) Subscribe(ctx context.Context, opts SubscriptionOptions) (*Subscription, error)
Subscribe registers a long-lived listener using the supplied options and context. The returned Subscription can be used to consume streamed frames until cancellation.
func (*WSStat) SubscribeOnce ¶
func (ws *WSStat) SubscribeOnce( ctx context.Context, opts SubscriptionOptions, ) (SubscriptionMessage, error)
SubscribeOnce registers a subscription and waits for the first delivered message before canceling the subscription. The returned message is a snapshot of the first delivery.
func (*WSStat) WriteMessage ¶
WriteMessage sends a message through the WebSocket connection. Sets time: MessageWrites
func (*WSStat) WriteMessageJSON ¶
WriteMessageJSON sends a message through the WebSocket connection. Sets time: MessageWrites
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
wsstat
command
Package main implements the wsstat command-line tool for measuring WebSocket connection latency and streaming subscription events.
|
Package main implements the wsstat command-line tool for measuring WebSocket connection latency and streaming subscription events. |
|
Package main provides examples of how to use the wsstat package.
|
Package main provides examples of how to use the wsstat package. |
|
internal
|
|
|
app
Package app provides a high-level client for measuring WebSocket latency and streaming subscription events.
|
Package app provides a high-level client for measuring WebSocket latency and streaming subscription events. |
|
app/color
Package color provides ANSI color support for terminal output.
|
Package color provides ANSI color support for terminal output. |