@@ -35,6 +35,10 @@ def get_default_config_help(self):
35
35
" - memory (Global memory usage)\n " ,
36
36
'publish_view_bind' : "" ,
37
37
'publish_view_meta' : "" ,
38
+ 'data_format' : "Bind stats version:\n " +
39
+ " - xml_v2 (Original bind stats version from 9.5)\n " +
40
+ " - xml_v3 (New xml version)\n " +
41
+ " - json_v1 (JSON replacement for XML)\n " ,
38
42
})
39
43
return config_help
40
44
@@ -63,6 +67,7 @@ def get_default_config(self):
63
67
# By default we don't publish these special views
64
68
'publish_view_bind' : False ,
65
69
'publish_view_meta' : False ,
70
+ 'data_format' : 'xml_v2' ,
66
71
})
67
72
return config
68
73
@@ -73,7 +78,62 @@ def clean_counter(self, name, value):
73
78
self .publish (name , value )
74
79
75
80
def collect (self ):
81
+ if self .config ['data_format' ] == 'json_v1' :
82
+ return self .collect_json_v1 ()
83
+ if self .config ['data_format' ] == 'xml_v3' :
84
+ return self .collect_xml_v3 ()
85
+ if self .config ['data_format' ] == 'xml_v2' :
86
+ return self .collect_xml_v2 ()
87
+
88
+ def collect_json_v1 (self ):
89
+ try :
90
+ # Try newest interface first (JSON has least impact)
91
+ import json
92
+ req = urllib2 .urlopen ('http://%s:%d/json/v1/status' % (
93
+ self .config ['host' ], int (self .config ['port' ])))
94
+ except Exception , e :
95
+ self .log .error ('JSON v1 not supported: %s' , e )
96
+ return {}
97
+
98
+ if 'server' in self .config ['publish' ]:
99
+ try :
100
+ req = urllib2 .urlopen ('http://%s:%d/json/v1/server' % (
101
+ self .config ['host' ], int (self .config ['port' ])))
102
+ except Exception , e :
103
+ self .log .error ('Couldnt connect to bind: %s' , e )
104
+ return {}
105
+
106
+ response = json .load (req )
107
+ self .parse_json_v1_server (response )
108
+
109
+ def collect_xml_v3 (self ):
110
+ try :
111
+ # Try newer interface first
112
+ req = urllib2 .urlopen ('http://%s:%d/xml/v3/status' % (
113
+ self .config ['host' ], int (self .config ['port' ])))
114
+ except Exception , e :
115
+ self .log .error ('XML v3 not supported: %s' , e )
116
+ return {}
117
+
118
+ if 'server' in self .config ['publish' ]:
119
+ try :
120
+ req = urllib2 .urlopen ('http://%s:%d/xml/v3/server' % (
121
+ self .config ['host' ], int (self .config ['port' ])))
122
+ except Exception , e :
123
+ self .log .error ('Couldnt connect to bind: %s' , e )
124
+ return {}
125
+ # Proceed with v3 parsing
126
+ tree = ElementTree .parse (req )
127
+
128
+ if not tree :
129
+ raise ValueError ("Corrupt XML file, no statistics found" )
130
+
131
+ self .parse_xml_v3_server (tree )
132
+
133
+ def collect_xml_v2 (self ):
76
134
try :
135
+ # NOTE: Querying this node on a large server can impact bind
136
+ # answering queriesfor sometimes hundreds of milliseconds.
77
137
req = urllib2 .urlopen ('http://%s:%d/' % (
78
138
self .config ['host' ], int (self .config ['port' ])))
79
139
except Exception , e :
@@ -87,6 +147,10 @@ def collect(self):
87
147
88
148
root = tree .find ('bind/statistics' )
89
149
150
+ if not root :
151
+ raise ValueError (
152
+ "Missing bind/statistics tree - Wrong data_format?" )
153
+
90
154
if 'resolver' in self .config ['publish' ]:
91
155
for view in root .findall ('views/view' ):
92
156
name = view .find ('name' ).text
@@ -153,3 +217,45 @@ def collect(self):
153
217
'memory.%s' % counter .tag ,
154
218
int (counter .text )
155
219
)
220
+
221
+ def parse_xml_v3_server (self , root ):
222
+ for counters in root .findall ('server/counters' ):
223
+ for counter in counters :
224
+ self .clean_counter (
225
+ 'server.counters.%s.%s' % (counters .attrib ['type' ],
226
+ counter .attrib ['name' ]),
227
+ int (counter .text )
228
+ )
229
+
230
+ for view in root .findall ('views/view' ):
231
+ for counters in view .iter ('counters' ):
232
+ for counter in counters :
233
+ self .clean_counter (
234
+ 'views.%s.counters.%s.%s' % (view .attrib ['name' ],
235
+ counters .attrib ['type' ],
236
+ counter .attrib ['name' ]),
237
+ int (counter .text )
238
+ )
239
+
240
+ def parse_json_v1_server (self , response ):
241
+ for counter_metric_name in [
242
+ 'nsstat' , 'opcode' , 'qtype' , 'rcode' , 'zonestat'
243
+ ]:
244
+ for counter in response [counter_metric_name + 's' ]:
245
+ self .clean_counter (
246
+ 'server.counters.%s.%s' % (counter_metric_name , counter ),
247
+ int (response [counter_metric_name + 's' ][counter ])
248
+ )
249
+
250
+ for view in response ['views' ]:
251
+ for counters in response ['views' ][view ]:
252
+ # This mapping maps from XML v3 layout to JSON v1
253
+ for section_name in response ['views' ][view ]['resolver' ]:
254
+ for counter in \
255
+ response ['views' ][view ]['resolver' ][section_name ]:
256
+ self .clean_counter (
257
+ 'views.%s.counters.%s.%s' %
258
+ (view , section_name , counter ),
259
+ int (response ['views' ][view ]['resolver' ]
260
+ [section_name ][counter ])
261
+ )
0 commit comments