wsstat

package module
v2.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2026 License: MIT Imports: 18 Imported by: 0

README

wsstat

Go Documentation Go Report Card MIT License

This project provides a way to stat a WebSocket connection; measure the latency and learn the transport details. It implements the Go package wsstat and a CLI tool, also named wsstat.

wsstat CLI Client

The CLI client provides a simple and easy to use tool to check the status of a WebSocket endpoint:

~ wsstat example.org

Target: example.org
IP: 1.2.3.4
WS version: 13
TLS version: TLS 1.3

  DNS Lookup    TCP Connection    TLS Handshake    WS Handshake    Message RTT
|     61ms  |           22ms  |          44ms  |         29ms  |        27ms  |
|           |                 |                |               |              |
|  DNS lookup:61ms            |                |               |              |
|                 TCP connected:84ms           |               |              |
|                                       TLS done:128ms         |              |
|                                                        WS done:158ms        |
-                                                                         Total:186ms

The client replicates what reorx/httpstat and davecheney/httpstat does for HTTP, but for WebSocket. It is said that imitation is the sincerest form of flattery, and inspiration has for certain been sourced from these projects.

Install
Snap

If you are using a Linux distribution that supports Snap, you can install the tool from the Snap Store:

sudo snap install wsstat
Go

Requires that you have Go installed on your system and that you have $GOPATH/bin in your PATH. Recommended Go version is 1.21 or later.

Install via Go:

# To install the latest version, specify other releases with @<tag>
go install github.com/jkbrsn/wsstat/v2@latest

# To include the version in the binary, run the install from the root of the repo
git clone github.com/jkbrsn/wsstat
cd wsstat
git fetch --all
git checkout origin/main
go install -ldflags "-X main.version=$(cat VERSION)" github.com/jkbrsn/wsstat@latest

Note: installing the package with @latest will always install the latest version no matter the other parameters of the command.

The snap is listed here: snapcraft.io/wsstat

Maintainers: see docs/operations/snap-release-flow.md for how snap revisions are built, published to edge, and promoted.

Binary
Linux

Download the binary from the latest release (amd64) on the release page:

wget https://github.com/jkbrsn/wsstat/releases/download/<tag>/wsstat

Make the binary executable:

chmod +x wsstat

Move the binary to a directory in your PATH:

sudo mv wsstat /usr/local/bin/wsstat  # system-wide
mv wsstat ~/bin/wsstat  # user-specific, ensure ~/bin is in your PATH
macOS and Windows

Currently not actively supported, but you may build and try it yourself:

git clone https://github.com/jkbrsn/wsstat.git
cd wsstat
make build-all

# Binary ends up in ./bin/wsstat-<OS>-<ARCH>

Then for Windows:

  1. Place the binary in a directory of your choice and add the directory to your PATH environment variable.
  2. Rename the binary to wsstat.exe for convenience.
  3. You should now be able to run wsstat from the command prompt or PowerShell.

For macOS:

  1. Make the binary executable: chmod +x wsstat-darwin-<ARCH>
  2. Move the binary to a directory in your PATH: sudo mv wsstat-darwin-<ARCH> /usr/local/bin/wsstat
Usage

Some examples:

# Basic request
wsstat wss://echo.example.com

# Send an RPC method
wsstat --rpc-method eth_blockNumber wss://rpc.example.com/ws

# Start a subscription
wsstat --subscribe --summary-interval 5s wss://stream.example.com/feed

# Attach headers to dial request
wsstat -H "Authorization: Bearer TOKEN" -H "Origin: https://foo" wss://api.example.com/ws

# Resolve to a target IP and set a longer timeout
wsstat --resolve example.com:443:127.0.0.1 --timeout 30s wss://example.com/ws

# Allow insecure connection, make output extra verbose
wsstat --insecure -vv wss://self-signed.example.com

For a full list of the available options, check the wsstat --help option of your client.

Subscription Mode

Long-lived streaming endpoints can be exercised with the subscription mode:

wsstat -subscribe -text '{"method":"subscribe"}' wss://example.org/stream

When -subscribe is supplied the client keeps the socket open, forwards each incoming frame to stdout, and periodically snapshots timing metrics. Use -buffer to adjust the per-subscription queue length and -summary-interval (for example, 30s) to print recurring summaries that include per-subscription message counts, byte totals, and mean inter-arrival latency.

Control how many interactions occur by setting -count. Non-subscription commands default to -count 1. When streaming (-subscribe), -count 0 keeps the connection open until you cancel it, while any positive value limits delivery to that many events before wsstat disconnects:

wsstat -subscribe -count 5 -text '{"method":"subscribe"}' wss://example.org/stream

For a single-response probe, you can either run -subscribe -count 1 or use the dedicated helper -subscribe-once, both of which subscribe and exit after the first event:

wsstat -subscribe -count 1 -text '{"method":"subscribe_ticker"}' wss://example.org/ws
wsstat -subscribe-once -text '{"method":"subscribe_ticker"}' wss://example.org/ws

For machine-readable output of summaries, add -format json.

wsstat Library Package

Use the wsstat Golang package to trace WebSocket connection and latency in your Go applications. It wraps gorilla/websocket for the WebSocket protocol implementation, and measures the duration of the different phases of the connection cycle.

Install

Install to use in your Go project:

go get github.com/jkbrsn/wsstat/v2
Usage

The examples/main.go program demonstrates two ways to use the wsstat package to trace a WebSocket connection. The example only executes one-hit message reads and writes, but WSStat also support operating on a continuous connection.

Run the example like this, from project root:

go run examples/main.go <a WebSocket URL>

Build & Test

The project has a Makefile that provides a number of commands to build and test the project:

# build
make build
make build-all  # build for all supported platforms

# test
make test
make test V=1 RACE=1  # test with optional flags

# lint
make lint

Contributing

For contributions, please open a GitHub issue with questions or suggestions. Before submitting an issue, have a look at the existing TODO list to see if what you've got in mind is already in the works.

Documentation

Overview

Package wsstat measures the latency of WebSocket connections. It wraps the gorilla/websocket package and includes latency measurements in the Result struct.

Package wsstat measures the latency of WebSocket connections. It wraps the gorilla/websocket package and includes latency measurements in the Result struct.

Index

Constants

This section is empty.

Variables

This section is empty.

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

func WithBufferSize(n int) Option

WithBufferSize sets the buffer size for read/write/pong channels.

func WithLogger

func WithLogger(logger zerolog.Logger) Option

WithLogger sets the logger for the WSStat instance.

func WithResolves

func WithResolves(resolves map[string]string) Option

WithResolves sets DNS resolution overrides for specific host:port combinations. Map key format: "host:port", value: "ip_address".

func WithTLSConfig

func WithTLSConfig(cfg *tls.Config) Option

WithTLSConfig sets the TLS configuration for the connection.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the timeout used for dialing and read deadlines.

type Result

type Result struct {
	IPs             []string             // IP addresses of the WebSocket connection
	URL             *url.URL             // URL of the WebSocket connection
	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

	// 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 MeasureLatency

func MeasureLatency(
	targetURL *url.URL,
	msg string,
	customHeaders http.Header,
) (*Result, []byte, error)

MeasureLatency is a wrapper around a one-hit usage of the WSStat instance. It establishes a WebSocket connection, sends a message, reads the response, and closes the connection. Note: sets all times in the Result object.

func MeasureLatencyBurst

func MeasureLatencyBurst(
	targetURL *url.URL,
	msgs []string,
	customHeaders http.Header,
) (*Result, []string, error)

MeasureLatencyBurst is a convenience wrapper around the WSStat instance, used to measure the latency of a WebSocket connection with multiple messages sent in quick succession. It connects to the server, sends all messages, reads the responses, and closes the connection. Note: sets all times in the Result object, where the MessageRTT will be the mean round trip time of all messages sent.

func MeasureLatencyBurstWithContext

func MeasureLatencyBurstWithContext(
	ctx context.Context,
	targetURL *url.URL,
	msgs []string,
	customHeaders http.Header,
	opts ...Option,
) (*Result, []string, error)

MeasureLatencyBurstWithContext measures latency with cancellation support

func MeasureLatencyJSON

func MeasureLatencyJSON(
	targetURL *url.URL,
	v any,
	customHeaders http.Header,
) (*Result, any, error)

MeasureLatencyJSON is a wrapper around a one-hit usage of the WSStat instance. It establishes a WebSocket connection, sends a JSON message, reads the response, and closes the connection. Note: sets all times in the Result object.

func MeasureLatencyJSONBurst

func MeasureLatencyJSONBurst(
	targetURL *url.URL,
	v []any,
	customHeaders http.Header,
) (*Result, []any, error)

MeasureLatencyJSONBurst is a convenience wrapper around the WSStat instance, used to measure the latency of a WebSocket connection with multiple messages sent in quick succession. It connects to the server, sends all JSON messages, reads the responses, and closes the connection. Note: sets all times in the Result object, where the MessageRTT will be the mean round trip time of all messages sent.

func MeasureLatencyJSONBurstWithContext

func MeasureLatencyJSONBurstWithContext(
	ctx context.Context,
	targetURL *url.URL,
	v []any,
	customHeaders http.Header,
	opts ...Option,
) (*Result, []any, error)

MeasureLatencyJSONBurstWithContext measures latency with cancellation support

func MeasureLatencyPing

func MeasureLatencyPing(
	targetURL *url.URL,
	customHeaders http.Header,
) (*Result, error)

MeasureLatencyPing is a convenience wrapper around a one-hit usage of the WSStat instance. It establishes a WebSocket connection, sends a ping message, awaits the pong response, and closes the connection. Note: sets all times in the Result object.

func MeasureLatencyPingBurst

func MeasureLatencyPingBurst(
	targetURL *url.URL,
	pingCount int,
	customHeaders http.Header,
) (*Result, error)

MeasureLatencyPingBurst is a convenience wrapper around a one-hit usage of the WSStat instance. It establishes a WebSocket connection, sends ping messages according to pingCount, awaits the pong responses, and closes the connection. Note: sets all times in the Result object.

func MeasureLatencyPingBurstWithContext

func MeasureLatencyPingBurstWithContext(
	ctx context.Context,
	targetURL *url.URL,
	pingCount int,
	customHeaders http.Header,
	opts ...Option,
) (*Result, error)

MeasureLatencyPingBurstWithContext measures latency with cancellation support

func (*Result) CertificateDetails

func (r *Result) CertificateDetails() []CertificateDetails

CertificateDetails returns a slice of CertificateDetails for each certificate in the TLS connection.

func (*Result) Format

func (r *Result) Format(s fmt.State, verb rune)

Format formats the time.Duration members of Result.

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 gorilla/websocket package with latency measuring capabilities.

func New

func New(opts ...Option) *WSStat

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) Dial

func (ws *WSStat) Dial(targetURL *url.URL, customHeaders http.Header) error

Dial establishes a new WebSocket connection using the custom dialer defined in this package. If required, specify custom headers to merge with the default headers. Sets times: dialStart, wsHandshakeDone

func (*WSStat) ExtractResult

func (ws *WSStat) ExtractResult() *Result

ExtractResult calculate the current results and returns a copy of the Result object.

func (*WSStat) OneHitMessage

func (ws *WSStat) OneHitMessage(messageType int, data []byte) ([]byte, error)

OneHitMessage sends a single message through the WebSocket connection, and waits for the response. Note: this function assumes that the response received is the response to the sent message, make sure to only run this function sequentially to avoid unexpected behavior. Sets result times: MessageReads, MessageWrites

func (*WSStat) OneHitMessageJSON

func (ws *WSStat) OneHitMessageJSON(v any) (any, error)

OneHitMessageJSON sends a single JSON message through the WebSocket connection, and waits for the response. Note: this function assumes that the response received is the response to the sent message, make sure to only run this function sequentially to avoid unexpected behavior. Sets result times: MessageReads, MessageWrites

func (*WSStat) PingPong

func (ws *WSStat) PingPong() error

PingPong sends a ping message through the WebSocket connection and awaits the pong. Note: this function assumes that the pong received is the response to the sent message, make sure to only run this function sequentially to avoid unexpected behavior. Sets result times: MessageReads, MessageWrites

func (*WSStat) ReadMessage

func (ws *WSStat) ReadMessage() (int, []byte, error)

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

func (ws *WSStat) ReadMessageJSON() (any, error)

ReadMessageJSON reads a message from the WebSocket connection and measures the round-trip time. Sets time: MessageReads

func (*WSStat) ReadPong

func (ws *WSStat) ReadPong() error

ReadPong reads a pong 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

func (ws *WSStat) WriteMessage(messageType int, data []byte)

WriteMessage sends a message through the WebSocket connection. Sets time: MessageWrites

func (*WSStat) WriteMessageJSON

func (ws *WSStat) WriteMessageJSON(v any)

WriteMessageJSON sends a message through the WebSocket connection. Sets time: MessageWrites

Directories

Path Synopsis
Package main provides examples of how to use the wsstat package.
Package main provides examples of how to use the wsstat package.
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.
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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL