@@ -18,55 +18,65 @@ import (
18
18
19
19
var statsLog = log .WithFields (log.Fields {"app" : "broker health monitor" })
20
20
21
- // BrokerMonitor is the
22
- type BrokerMonitor struct {
23
- RESTURL string
24
- token string
25
- ExpectedBrokerNumber int
26
- }
27
-
28
21
const (
29
22
topicStatsDBTable = "topic-stats"
30
23
)
31
24
32
- // BrokerStats is per broker statistics
33
- type BrokerStats struct {
34
- Broker string `json:"broker"`
35
- Data map [string ]map [string ]map [string ]map [string ]interface {} `json:"data"`
36
- }
25
+ // GetBrokers gets a list of brokers and ports
26
+ func GetBrokers (restBaseURL , clusterName , token string ) ([]string , error ) {
27
+ brokersURL := util .SingleSlashJoin (restBaseURL , "admin/v2/brokers/" + clusterName )
28
+ newRequest , err := http .NewRequest (http .MethodGet , brokersURL , nil )
29
+ if err != nil {
30
+ return nil , err
31
+ }
32
+ newRequest .Header .Add ("user-agent" , "pulsar-monitor" )
33
+ newRequest .Header .Add ("Authorization" , "Bearer " + token )
34
+ client := & http.Client {
35
+ CheckRedirect : util .PreserveHeaderForRedirect ,
36
+ }
37
+ resp , err := client .Do (newRequest )
38
+ if resp != nil {
39
+ defer resp .Body .Close ()
40
+ }
41
+ if err != nil {
42
+ return nil , err
43
+ }
37
44
38
- // Stats is the json response object for REST API
39
- type Stats struct {
40
- Total int `json:"total"`
41
- Offset int `json:"offset"`
42
- Data []BrokerStats `json:"data"`
43
- }
45
+ if resp .StatusCode > 300 {
46
+ return nil , fmt .Errorf ("failed to get a list of brokers, returns incorrect status code %d" , resp .StatusCode )
47
+ }
44
48
45
- // TopicStats is the usage for topic on each individual broker
46
- type TopicStats struct {
47
- ID string `json:"id"` // ID is the topic fullname
48
- Tenant string `json:"tenant"`
49
- Namespace string `json:"namespace"`
50
- Topic string `json:"topic"`
51
- Data interface {} `json:"data"`
52
- UpdatedAt time.Time `json:"updatedAt"`
49
+ bodyBytes , err := ioutil .ReadAll (resp .Body )
50
+ if err != nil {
51
+ return nil , err
52
+ }
53
+
54
+ brokers := []string {}
55
+ err = json .Unmarshal (bodyBytes , & brokers )
56
+ if err != nil {
57
+ return nil , err
58
+ }
59
+
60
+ return brokers , nil
53
61
}
54
62
55
- // brokersTopicsQuery returns a map of broker and topic full name, and error of this operation
56
- func brokersTopicsQuery ( urlString , token string ) ( map [ string ][] string , error ) {
57
- // key is tenant, value is partition topic name
58
- var brokerTopicMap = make ( map [ string ][] string )
63
+ // required configuration cluster name and broker url
64
+ // 1. get a list of broker ips
65
+ // 2. query each broker individually
66
+ //
59
67
60
- if ! strings .HasPrefix (urlString , "http" ) {
61
- urlString = "http://" + urlString
68
+ // BrokerTopicsQuery returns a map of broker and topic full name, or error of this operation
69
+ func BrokerTopicsQuery (brokerBaseURL , token string ) ([]string , error ) {
70
+ // key is tenant, value is partition topic name
71
+ if ! strings .HasPrefix (brokerBaseURL , "http" ) {
72
+ brokerBaseURL = "http://" + brokerBaseURL
62
73
}
63
- topicStatsURL := util .SingleSlashJoin (urlString , "admin/v2/broker-stats/topics" )
74
+ topicStatsURL := util .SingleSlashJoin (brokerBaseURL , "admin/v2/broker-stats/topics" )
64
75
statsLog .Debugf (" proxy request route is %s\n " , topicStatsURL )
65
76
66
77
newRequest , err := http .NewRequest (http .MethodGet , topicStatsURL , nil )
67
78
if err != nil {
68
- statsLog .Errorf ("make http request %s error %v" , topicStatsURL , err )
69
- return brokerTopicMap , err
79
+ return nil , err
70
80
}
71
81
newRequest .Header .Add ("user-agent" , "pulsar-monitor" )
72
82
newRequest .Header .Add ("Authorization" , "Bearer " + token )
@@ -78,52 +88,46 @@ func brokersTopicsQuery(urlString, token string) (map[string][]string, error) {
78
88
defer response .Body .Close ()
79
89
}
80
90
if err != nil {
81
- statsLog .Errorf ("make http request %s error %v" , topicStatsURL , err )
82
- return brokerTopicMap , err
91
+ return nil , err
83
92
}
84
93
85
94
if response .StatusCode != http .StatusOK {
86
- statsLog .Errorf ("GET broker topic stats %s response status code %d" , topicStatsURL , response .StatusCode )
87
- return brokerTopicMap , err
95
+ return nil , err
88
96
}
89
97
90
98
body , err := ioutil .ReadAll (response .Body )
91
99
if err != nil {
92
100
statsLog .Errorf ("GET broker topic stats request %s error %v" , topicStatsURL , err )
93
- return brokerTopicMap , err
101
+ return nil , err
94
102
}
95
103
96
- var brokers Stats
97
- if err = json .Unmarshal (body , & brokers ); err != nil {
98
- statsLog .Errorf ("GET broker topic stats request %s unmarshal error %v" , topicStatsURL , err )
99
- return brokerTopicMap , err
104
+ var namespaces map [string ]map [string ]map [string ]map [string ]interface {}
105
+ if err = json .Unmarshal (body , & namespaces ); err != nil {
106
+ return nil , err
100
107
}
101
108
102
- for _ , broker := range brokers .Data {
103
- var topics []string
104
- for k , v := range broker .Data {
105
- tenant := strings .Split (k , "/" )[0 ]
106
- statsLog .Debugf ("namespace %s tenant %s" , k , tenant )
109
+ topics := []string {}
110
+ for k , v := range namespaces {
111
+ tenant := strings .Split (k , "/" )[0 ]
112
+ statsLog .Debugf ("namespace %s tenant %s" , k , tenant )
107
113
108
- for bundleKey , v2 := range v {
109
- statsLog .Debugf (" bundle %s" , bundleKey )
110
- for persistentKey , v3 := range v2 {
111
- statsLog .Debugf (" %s key" , persistentKey )
114
+ for bundleKey , v2 := range v {
115
+ statsLog .Debugf (" bundle %s" , bundleKey )
116
+ for persistentKey , v3 := range v2 {
117
+ statsLog .Debugf (" %s key" , persistentKey )
112
118
113
- for topicFn := range v3 {
114
- // statsLog.Infof(" topic name %s", topicFn)
115
- topics = append (topics , topicFn )
116
- }
119
+ for topicFn := range v3 {
120
+ // statsLog.Infof(" topic name %s", topicFn)
121
+ topics = append (topics , topicFn )
117
122
}
118
123
}
119
124
}
120
- brokerTopicMap [broker .Broker ] = topics
121
125
}
122
-
123
- return brokerTopicMap , nil
126
+ return topics , nil
124
127
}
125
128
126
- func brokerHealthCheck (broker , token string ) error {
129
+ // BrokerHealthCheck calls broker's health endpoint
130
+ func BrokerHealthCheck (broker , token string ) error {
127
131
// key is tenant, value is partition topic name
128
132
if ! strings .HasPrefix (broker , "http" ) {
129
133
broker = "http://" + broker
@@ -192,17 +196,28 @@ func QueryTopicStats(url, token string) error {
192
196
}
193
197
194
198
// TestBrokers evaluates all brokers' health
195
- func TestBrokers (urlPrefix , token string ) (int , error ) {
196
- brokerTopics , err := brokersTopicsQuery (urlPrefix , token )
199
+ func TestBrokers (urlPrefix , clusterName , token string ) (int , error ) {
200
+ brokers , err := GetBrokers (urlPrefix , clusterName , token )
197
201
if err != nil {
198
202
return 0 , err
199
203
}
200
204
205
+ log .Debugf ("got a list of brokers %v" , brokers )
201
206
failedBrokers := 0
202
- errorStr := ""
203
- for brokerName , topics := range brokerTopics {
204
- if err := brokerHealthCheck (brokerName , token ); err != nil {
205
- errorStr = errorStr + ";;" + err .Error ()
207
+ errStr := ""
208
+ for _ , brokerURL := range brokers {
209
+ // check the broker health
210
+ if err := BrokerHealthCheck (brokerURL , token ); err != nil {
211
+ errStr = errStr + ";;" + err .Error ()
212
+ failedBrokers ++
213
+ continue
214
+ }
215
+ log .Debugf ("broker %s health ok" , brokerURL )
216
+
217
+ // Get broker topic stats
218
+ topics , err := BrokerTopicsQuery (brokerURL , token )
219
+ if err != nil {
220
+ errStr = errStr + ";;" + err .Error ()
206
221
failedBrokers ++
207
222
continue
208
223
}
@@ -221,7 +236,7 @@ func TestBrokers(urlPrefix, token string) (int, error) {
221
236
url = util .SingleSlashJoin (util .SingleSlashJoin (urlPrefix , "/admin/v2/" ), url + "/stats" )
222
237
err = QueryTopicStats (url , token )
223
238
if err != nil {
224
- errorStr = errorStr + ";;" + err .Error ()
239
+ errStr = errStr + ";;" + err .Error ()
225
240
failureCount ++
226
241
}
227
242
count ++
@@ -234,11 +249,12 @@ func TestBrokers(urlPrefix, token string) (int, error) {
234
249
break
235
250
}
236
251
}
237
- statsLog .Infof ("broker %s health monitor required %d topic stats test, failed %d test" , brokerName , count , failureCount )
252
+ statsLog .Infof ("broker %s health monitor required %d topic stats test, failed %d test" , brokerURL , count , failureCount )
238
253
}
239
- statsLog .Infof ("failed %d brokers out of total %d brokers" , failedBrokers , len (brokerTopics ))
240
- if errorStr != "" {
241
- return failedBrokers , errors .Errorf (errorStr )
254
+
255
+ statsLog .Infof ("cluster %s has %d failed brokers out of total %d brokers" , clusterName , failedBrokers , len (brokers ))
256
+ if errStr != "" {
257
+ return failedBrokers , errors .Errorf (errStr )
242
258
}
243
259
244
260
return failedBrokers , nil
0 commit comments