diff --git a/server/monitor.go b/server/monitor.go index 116e7f6e..a44c131d 100644 --- a/server/monitor.go +++ b/server/monitor.go @@ -139,7 +139,7 @@ const defaultStackBufSize = 10000 func newSubsDetailList(client *client) []SubDetail { subsDetail := make([]SubDetail, 0, len(client.subs)) for _, sub := range client.subs { - subsDetail = append(subsDetail, newSubDetail(sub)) + subsDetail = append(subsDetail, newClientSubDetail(sub)) } return subsDetail } @@ -771,9 +771,12 @@ type SubszOptions struct { // Limit is the maximum number of subscriptions that should be returned by Subsz(). Limit int `json:"limit"` - // Subscriptions indicates if subscriptions should be included in the results. + // Subscriptions indicates if subscription details should be included in the results. Subscriptions bool `json:"subscriptions"` + // Filter based on this account name. + Account string `json:"account,omitempty"` + // Test the list against this subject. Needs to be literal since it signifies a publish subject. // We will only return subscriptions that would match if a message was sent to this subject. Test string `json:"test,omitempty"` @@ -781,6 +784,7 @@ type SubszOptions struct { // SubDetail is for verbose information for subscriptions. type SubDetail struct { + Account string `json:"account,omitempty"` Subject string `json:"subject"` Queue string `json:"qgroup,omitempty"` Sid string `json:"sid"` @@ -789,8 +793,10 @@ type SubDetail struct { Cid uint64 `json:"cid"` } +// Subscription client should be locked and guaranteed to be present. func newSubDetail(sub *subscription) SubDetail { return SubDetail{ + Account: sub.client.acc.GetName(), Subject: string(sub.subject), Queue: string(sub.queue), Sid: string(sub.sid), @@ -800,6 +806,17 @@ func newSubDetail(sub *subscription) SubDetail { } } +// For subs details under clients. +func newClientSubDetail(sub *subscription) SubDetail { + return SubDetail{ + Subject: string(sub.subject), + Queue: string(sub.queue), + Sid: string(sub.sid), + Msgs: sub.nm, + Max: sub.max, + } +} + // Subsz returns a Subsz struct containing subjects statistics func (s *Server) Subsz(opts *SubszOptions) (*Subsz, error) { var ( @@ -808,6 +825,7 @@ func (s *Server) Subsz(opts *SubszOptions) (*Subsz, error) { offset int limit = DefaultSubListSize testSub = "" + filterAcc = "" ) if opts != nil { @@ -827,6 +845,9 @@ func (s *Server) Subsz(opts *SubszOptions) (*Subsz, error) { return nil, fmt.Errorf("invalid test subject, must be valid publish subject: %s", testSub) } } + if opts.Account != "" { + filterAcc = opts.Account + } } slStats := &SublistStats{} @@ -839,6 +860,9 @@ func (s *Server) Subsz(opts *SubszOptions) (*Subsz, error) { subs := raw[:0] s.accounts.Range(func(k, v interface{}) bool { acc := v.(*Account) + if filterAcc != "" && acc.GetName() != filterAcc { + return true + } slStats.add(acc.sl.Stats()) acc.sl.localSubs(&subs) return true @@ -877,6 +901,9 @@ func (s *Server) Subsz(opts *SubszOptions) (*Subsz, error) { } else { s.accounts.Range(func(k, v interface{}) bool { acc := v.(*Account) + if filterAcc != "" && acc.GetName() != filterAcc { + return true + } slStats.add(acc.sl.Stats()) return true }) @@ -904,11 +931,14 @@ func (s *Server) HandleSubsz(w http.ResponseWriter, r *http.Request) { return } testSub := r.URL.Query().Get("test") + // Filtered account. + filterAcc := r.URL.Query().Get("acc") subszOpts := &SubszOptions{ Subscriptions: subs, Offset: offset, Limit: limit, + Account: filterAcc, Test: testSub, } diff --git a/server/monitor_test.go b/server/monitor_test.go index 7f94cfb2..0393c084 100644 --- a/server/monitor_test.go +++ b/server/monitor_test.go @@ -1547,6 +1547,28 @@ func TestSubszMultiAccount(t *testing.T) { if len(sl.Subs) != 6 { t.Fatalf("Expected subscription details for 6 subs, got %d\n", len(sl.Subs)) } + for _, sd := range sl.Subs { + if sd.Account != "A" && sd.Account != "B" { + t.Fatalf("Expected account information to be present and be 'A' or 'B', got %q", sd.Account) + } + } + + // Now make sure we can filter on account. + sl = pollSubsz(t, s, mode, url+"subsz?subs=1&acc=A", &SubszOptions{Account: "A", Subscriptions: true}) + if sl.NumSubs != 3 { + t.Fatalf("Expected NumSubs of 3, got %d\n", sl.NumSubs) + } + if sl.Total != 3 { + t.Fatalf("Expected Total of 6, got %d\n", sl.Total) + } + if len(sl.Subs) != 3 { + t.Fatalf("Expected subscription details for 6 subs, got %d\n", len(sl.Subs)) + } + for _, sd := range sl.Subs { + if sd.Account != "A" { + t.Fatalf("Expected account information to be present and be 'A', got %q", sd.Account) + } + } } }