github.com/netdata/go.d.plugin@v0.58.1/modules/bind/xml3_client.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package bind 4 5 import ( 6 "encoding/xml" 7 "fmt" 8 "net/http" 9 "net/url" 10 "path" 11 12 "github.com/netdata/go.d.plugin/pkg/web" 13 ) 14 15 type xml3Stats struct { 16 Server xml3Server `xml:"server"` 17 Views []xml3View `xml:"views>view"` 18 } 19 20 type xml3Server struct { 21 CounterGroups []xml3CounterGroup `xml:"counters"` 22 } 23 24 type xml3CounterGroup struct { 25 Type string `xml:"type,attr"` 26 Counters []struct { 27 Name string `xml:"name,attr"` 28 Value int64 `xml:",chardata"` 29 } `xml:"counter"` 30 } 31 32 type xml3View struct { 33 Name string `xml:"name,attr"` 34 CounterGroups []xml3CounterGroup `xml:"counters"` 35 } 36 37 func newXML3Client(client *http.Client, request web.Request) *xml3Client { 38 return &xml3Client{httpClient: client, request: request} 39 } 40 41 type xml3Client struct { 42 httpClient *http.Client 43 request web.Request 44 } 45 46 func (c xml3Client) serverStats() (*serverStats, error) { 47 req := c.request.Copy() 48 u, err := url.Parse(req.URL) 49 if err != nil { 50 return nil, fmt.Errorf("error on parsing URL: %v", err) 51 } 52 53 u.Path = path.Join(u.Path, "/server") 54 req.URL = u.String() 55 56 httpReq, err := web.NewHTTPRequest(req) 57 if err != nil { 58 return nil, fmt.Errorf("error on creating HTTP request: %v", err) 59 } 60 61 resp, err := c.httpClient.Do(httpReq) 62 if err != nil { 63 return nil, fmt.Errorf("error on request : %v", err) 64 } 65 defer closeBody(resp) 66 67 if resp.StatusCode != http.StatusOK { 68 return nil, fmt.Errorf("%s returned HTTP status %d", httpReq.URL, resp.StatusCode) 69 } 70 71 stats := xml3Stats{} 72 if err = xml.NewDecoder(resp.Body).Decode(&stats); err != nil { 73 return nil, fmt.Errorf("error on decoding response from %s : %v", httpReq.URL, err) 74 } 75 return convertXML(stats), nil 76 } 77 78 func convertXML(xmlStats xml3Stats) *serverStats { 79 stats := serverStats{ 80 OpCodes: make(map[string]int64), 81 NSStats: make(map[string]int64), 82 QTypes: make(map[string]int64), 83 SockStats: make(map[string]int64), 84 Views: make(map[string]jsonView), 85 } 86 87 var m map[string]int64 88 89 for _, group := range xmlStats.Server.CounterGroups { 90 switch group.Type { 91 default: 92 continue 93 case "opcode": 94 m = stats.OpCodes 95 case "qtype": 96 m = stats.QTypes 97 case "nsstat": 98 m = stats.NSStats 99 case "sockstat": 100 m = stats.SockStats 101 } 102 103 for _, v := range group.Counters { 104 m[v.Name] = v.Value 105 } 106 } 107 108 for _, view := range xmlStats.Views { 109 stats.Views[view.Name] = jsonView{ 110 Resolver: jsonViewResolver{ 111 Stats: make(map[string]int64), 112 QTypes: make(map[string]int64), 113 CacheStats: make(map[string]int64), 114 }, 115 } 116 for _, viewGroup := range view.CounterGroups { 117 switch viewGroup.Type { 118 default: 119 continue 120 case "resqtype": 121 m = stats.Views[view.Name].Resolver.QTypes 122 case "resstats": 123 m = stats.Views[view.Name].Resolver.Stats 124 case "cachestats": 125 m = stats.Views[view.Name].Resolver.CacheStats 126 } 127 for _, viewCounter := range viewGroup.Counters { 128 m[viewCounter.Name] = viewCounter.Value 129 } 130 } 131 } 132 return &stats 133 }