diff --git a/modules/nats/cmd/nats-tools/main.go b/modules/nats/cmd/nats-tools/main.go index 4dcac6d8..933abbea 100644 --- a/modules/nats/cmd/nats-tools/main.go +++ b/modules/nats/cmd/nats-tools/main.go @@ -87,7 +87,7 @@ func tools(monitor Monitor, users func(context.Context) ([]byte, error), written return Subscriptions(subsz, connz, arg(a, "subject"), limitOf(a, 100)) }}, {Name: "nats_streams", - Description: "JetStream: every stream with its subjects, retention, message count and size — or, given one stream, every consumer on it with what it has pending, unacknowledged and redelivered.", + Description: "JetStream: every stream with its subjects, retention, message count, size and size cap (max_bytes, when it has one) — or, given one stream, every consumer on it with what it has pending, unacknowledged and redelivered.", Input: map[string]any{"stream": str("one stream, e.g. EVENTS, CONTROL, ASSIGNMENTS, SEAT_NODE_BUILD_AGENT or KV_")}, Run: func(a map[string]any) (any, error) { doc, err := get(jsz) diff --git a/modules/nats/cmd/nats-tools/tools.go b/modules/nats/cmd/nats-tools/tools.go index e725a070..88d5b8b9 100644 --- a/modules/nats/cmd/nats-tools/tools.go +++ b/modules/nats/cmd/nats-tools/tools.go @@ -351,6 +351,10 @@ func Streams(jsz []byte, stream string) (map[string]any, error) { if s.Config.MaxMsgsPerSubject > 0 { row["max_per_subject"] = s.Config.MaxMsgsPerSubject } + // The cap on the stream's size, so how full it is reads against it (-1 and 0 are no cap). + if s.Config.MaxBytes > 0 { + row["max_bytes"] = s.Config.MaxBytes + } if stream != "" { row["description"] = s.Config.Description var consumers []map[string]any diff --git a/modules/nats/cmd/nats-tools/tools_test.go b/modules/nats/cmd/nats-tools/tools_test.go index 3e989242..2a2eca4a 100644 --- a/modules/nats/cmd/nats-tools/tools_test.go +++ b/modules/nats/cmd/nats-tools/tools_test.go @@ -22,7 +22,7 @@ const subsz = `{"num_subscriptions":3,"subscriptions_list":[ {"subject":"mesh.node.anchor.declare","msgs":1,"cid":1}]}` const jsz = `{"streams":2,"consumers":2,"messages":12,"bytes":300,"account_details":[{"stream_detail":[ - {"name":"EVENTS","config":{"subjects":["mesh.mod.*.event.>"],"retention":"limits","max_age":604800000000000,"max_msgs_per_subject":10000}, + {"name":"EVENTS","config":{"subjects":["mesh.mod.*.event.>"],"retention":"limits","max_age":604800000000000,"max_msgs_per_subject":10000,"max_bytes":1048576}, "state":{"messages":10,"bytes":200,"num_subjects":3,"consumer_count":2,"last_ts":"2026-10-04T10:00:00Z"}, "consumer_detail":[ {"name":"anchor_audit","config":{"filter_subject":"mesh.mod.*.event.>"},"num_pending":5,"num_ack_pending":1,"num_redelivered":2,"delivered":{"last_active":"2026-10-04T10:00:00Z"}}, @@ -80,7 +80,7 @@ func TestStreamsBacklogAndBuckets(t *testing.T) { } one, _ := Streams([]byte(jsz), "EVENTS") row := one["detail"].([]map[string]any)[0] - if row["max_age_hours"].(int64) != 168 || len(row["consumer_detail"].([]map[string]any)) != 2 { + if row["max_age_hours"].(int64) != 168 || row["max_bytes"].(int64) != 1048576 || len(row["consumer_detail"].([]map[string]any)) != 2 { t.Fatalf("%v", row) } if _, err := Streams([]byte(jsz), "NOPE"); err == nil {