Merge lp:~bloodearnest/charms/precise/squid-reverseproxy/fix-stats-cron into lp:charms/squid-reverseproxy

Proposed by Simon Davy
Status: Merged
Merged at revision: 47
Proposed branch: lp:~bloodearnest/charms/precise/squid-reverseproxy/fix-stats-cron
Merge into: lp:charms/squid-reverseproxy
Diff against target: 340 lines (+170/-33)
4 files modified
files/squid_metrics.py (+137/-10)
hooks/tests/test_metrics.py (+30/-21)
templates/metrics_cronjob.template (+1/-1)
templates/squid_metrics_ini.template (+2/-1)
To merge this branch: bzr merge lp:~bloodearnest/charms/precise/squid-reverseproxy/fix-stats-cron
Reviewer Review Type Date Requested Status
Tom Haddon Approve
Review via email: mp+218103@code.launchpad.net

Commit message

fix statsd wire format and send directly in metrics script

Description of the change

fix statsd wire format and send directly in metrics script

To post a comment you must log in.
Revision history for this message
Tom Haddon (mthaddon) wrote :

Looks good to me, and tested to work on a staging environment

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'files/squid_metrics.py'
2--- files/squid_metrics.py 2014-03-28 17:05:31 +0000
3+++ files/squid_metrics.py 2014-05-02 14:57:34 +0000
4@@ -1,10 +1,122 @@
5 #!/bin/env python
6 import shlex
7 import sys
8+import socket
9 import subprocess
10-import time
11 import ConfigParser
12
13+
14+METRIC_TYPES = {
15+ 'cacheSysVMsize': 'g', # Storage Mem size in KB
16+ 'cacheSysStorage': 'g', # Storage Swap size in KB
17+ 'cacheUptime': 'c', # The Uptime of the cache in timeticks
18+ 'cacheMemMaxSize': 'g', # The value of the cache_mem parameter in MB
19+ 'cacheSwapMaxSize': 'g', # The total of the cache_dir space allocated in MB
20+ 'cacheSwapHighWM': 'g', # Cache Swap High Water Mark
21+ 'cacheSwapLowWM': 'g', # Cache Swap Low Water Mark
22+ 'cacheUniqName': 'g', # Cache unique host name
23+ 'cacheSysPageFaults': 'c', # Page faults with physical i/o
24+ 'cacheSysNumReads': 'c', # HTTP I/O number of reads
25+ 'cacheMemUsage': 'g', # Total memory accounted for KB
26+ 'cacheCpuTime': 'c', # Amount of cpu seconds consumed
27+ 'cacheCpuUsage': 'g', # The percentage use of the CPU
28+ 'cacheMaxResSize': 'g', # Maximum Resident Size in KB
29+ 'cacheNumObjCount': 'g', # Number of objects stored by the cache
30+ 'cacheCurrentLRUExpiration': 'g', # Storage LRU Expiration Age
31+ 'cacheCurrentUnlinkRequests': 'g', # Requests given to unlinkd
32+ 'cacheCurrentUnusedFDescrCnt': 'g', # Available number of file descriptors
33+ 'cacheCurrentResFileDescrCnt': 'g', # Reserved number of file descriptors
34+ 'cacheCurrentFileDescrCnt': 'g', # Number of file descriptors in use
35+ 'cacheCurrentFileDescrMax': 'g', # Highest file descriptors in use
36+ 'cacheProtoClientHttpRequests': 'c', # Number of HTTP requests received
37+ 'cacheHttpHits': 'c', # Number of HTTP Hits sent to clients from cache
38+ 'cacheHttpErrors': 'c', # Number of HTTP Errors sent to clients
39+ 'cacheHttpInKb': 'c', # Number of HTTP KB's received from clients
40+ 'cacheHttpOutKb': 'c', # Number of HTTP KB's sent to clients
41+ 'cacheIcpPktsSent': 'c', # Number of ICP messages sent
42+ 'cacheIcpPktsRecv': 'c', # Number of ICP messages received
43+ 'cacheIcpKbSent': 'c', # Number of ICP KB's transmitted
44+ 'cacheIcpKbRecv': 'c', # Number of ICP KB's received
45+ 'cacheServerRequests': 'c', # All requests from the client for the cache server
46+ 'cacheServerErrors': 'c', # All errors for the cache server from client requests
47+ 'cacheServerInKb': 'c', # KB's of traffic received from servers
48+ 'cacheServerOutKb': 'c', # KB's of traffic sent to servers
49+ 'cacheCurrentSwapSize': 'g', # Storage Swap size
50+ 'cacheClients': 'g', # Number of clients accessing cache
51+ 'cacheMedianTime.1': 'g', # The value used to index the table 1/5/60
52+ 'cacheMedianTime.5': 'g', #
53+ 'cacheMedianTime.60': 'g', #
54+ 'cacheHttpAllSvcTime.1': 'g', # HTTP all service time
55+ 'cacheHttpAllSvcTime.5': 'g', #
56+ 'cacheHttpAllSvcTime.60': 'g', #
57+ 'cacheHttpMissSvcTime.1': 'g', # HTTP miss service time
58+ 'cacheHttpMissSvcTime.5': 'g', #
59+ 'cacheHttpMissSvcTime.60': 'g', #
60+ 'cacheHttpNmSvcTime.1': 'g', # HTTP hit not-modified service time
61+ 'cacheHttpNmSvcTime.5': 'g', #
62+ 'cacheHttpNmSvcTime.60': 'g', #
63+ 'cacheHttpHitSvcTime.1': 'g', # HTTP hit service time
64+ 'cacheHttpHitSvcTime.5': 'g', #
65+ 'cacheHttpHitSvcTime.60': 'g', #
66+ 'cacheIcpQuerySvcTime.1': 'g', # ICP query service time
67+ 'cacheIcpQuerySvcTime.5': 'g', #
68+ 'cacheIcpQuerySvcTime.60': 'g', #
69+ 'cacheIcpReplySvcTime.1': 'g', # ICP reply service time
70+ 'cacheIcpReplySvcTime.5': 'g', #
71+ 'cacheIcpReplySvcTime.60': 'g', #
72+ 'cacheDnsSvcTime.1': 'g', # DNS service time
73+ 'cacheDnsSvcTime.5': 'g', #
74+ 'cacheDnsSvcTime.60': 'g', #
75+ 'cacheRequestHitRati.1': 'g', # Request Hit Ratios
76+ 'cacheRequestHitRati.5': 'g', #
77+ 'cacheRequestHitRati.60': 'g', #
78+ 'cacheRequestByteRati.1': 'g', # Byte Hit Ratios
79+ 'cacheRequestByteRati.5': 'g', #
80+ 'cacheRequestByteRati.60': 'g', #
81+ 'cacheHttpNhSvcTime.1': 'g', # HTTP refresh hit service time
82+ 'cacheHttpNhSvcTime.5': 'g', #
83+ 'cacheHttpNhSvcTime.60': 'g', #
84+ 'cacheIpEntries': 'g', # IP Cache Entries
85+ 'cacheIpRequests': 'c', # Number of IP Cache requests
86+ 'cacheIpHits': 'c', # Number of IP Cache hits
87+ 'cacheIpPendingHits': 'g', # Number of IP Cache pending hits
88+ 'cacheIpNegativeHits': 'c', # Number of IP Cache pending hits
89+ 'cacheIpMisses': 'c', # Number of IP Cache misses
90+ 'cacheBlockingGetHostByName': 'c', # Number of blocking gethostbyname requests
91+ 'cacheAttemptReleaseLckEntries': 'c', # Number of attempts to release locked IP
92+ 'cacheFqdnEntries': 'g', # FQDN Cache entries
93+ 'cacheFqdnRequests': 'c', # Number of FQDN Cache requests
94+ 'cacheFqdnHits': 'c', # Number of FQDN Cache hits
95+ 'cacheFqdnPendingHits': 'g', # Number of FQDN Cache pending hits
96+ 'cacheFqdnNegativeHits': 'c', # Number of FQDN Cache negative hits
97+ 'cacheFqdnMisses': 'c', # Number of FQDN Cache misses
98+ 'cacheBlockingGetHostByAddr': 'c', # Number of blocking gethostbyaddr requests
99+ 'cacheDnsRequests': 'c', # Number of external dnsserver requests
100+ 'cacheDnsReplies': 'c', # Number of external dnsserver replies
101+ 'cacheDnsNumberServers': 'c', # Number of external dnsserver processes
102+ 'cachePeerIndex': 'g', # A unique value, greater than zero for each cache_peer instance in the managed system.
103+ 'cachePeerPortHttp': 'g', # The port the peer listens for HTTP requests
104+ 'cachePeerPortIcp': 'g', # The port the peer listens for ICP requests should be 0 if not configured to send ICP requests
105+ 'cachePeerType': 'g', # Peer Type
106+ 'cachePeerState': 'g', # The operational state of this peer
107+ 'cachePeerPingsSent': 'c', # Number of pings sent to peer
108+ 'cachePeerPingsAcked': 'c', # Number of pings received from peer
109+ 'cachePeerFetches': 'c', # Number of times this peer was selected
110+ 'cachePeerRtt': 'g', # Last known round-trip time to the peer (in ms)
111+ 'cachePeerIgnored': 'c', # How many times this peer was ignored
112+ 'cachePeerKeepAlSent': 'c', # Number of keepalives sent
113+ 'cachePeerKeepAlRecv': 'c', # Number of keepalives received
114+ 'cacheClientHttpRequests': 'c', # Number of HTTP requests received from client
115+ 'cacheClientHttpKb': 'c', # Amount of total HTTP traffic to this client
116+ 'cacheClientHttpHits': 'c', # Number of hits in response to this client's HTTP requests
117+ 'cacheClientHTTPHitKb': 'c', # Amount of HTTP hit traffic in KB
118+ 'cacheClientIcpRequests': 'c', # Number of ICP requests received from client
119+ 'cacheClientIcpKb': 'c', # Amount of total ICP traffic to this client (child)
120+ 'cacheClientIcpHits': 'c', # Number of hits in response to this client's ICP requests
121+ 'cacheClientIcpHitKb': 'c', # Amount of ICP hit traffic in KB
122+}
123+
124+
125 config_path = "/usr/local/etc/squid_metrics.ini"
126 cmd = "snmpwalk -v1 -Cc -Oq -c %s -m /usr/share/squid3/mib.txt localhost:%s"
127
128@@ -20,7 +132,8 @@
129 return {
130 'unit': config.get('metrics', 'unit'),
131 'scheme': config.get('metrics', 'scheme'),
132- 'port': config.get('metrics', 'port'),
133+ 'snmp_port': config.get('metrics', 'snmp_port'),
134+ 'statsd_hostport': config.get('metrics', 'statsd_hostport'),
135 'community': config.get('metrics', 'community'),
136 'metrics': config.get('metrics', 'metrics').strip().split(','),
137 }
138@@ -45,9 +158,9 @@
139
140 def get_metrics(config):
141
142- tstamp = int(time.time())
143 scheme = config['scheme'].replace('$UNIT', clean(config['unit']))
144- snmp_cmd = tuple(shlex.split(cmd % (config['community'], config['port'])))
145+ snmp_cmd = tuple(
146+ shlex.split(cmd % (config['community'], config['snmp_port'])))
147
148 try:
149 raw_peer_names = get_snmp_value(snmp_cmd, 'cachePeerName')
150@@ -59,6 +172,11 @@
151 peer_names = dict(line[25:].split(' ') for line in lines)
152
153 for metric in config['metrics']:
154+
155+ if metric not in METRIC_TYPES:
156+ # TODO log failure?
157+ continue
158+
159 # sadly, have to do one call per metric
160 try:
161 output = get_snmp_value(snmp_cmd, metric)
162@@ -67,6 +185,8 @@
163 # TODO log failure to read metric?
164 continue
165
166+ metric_type = METRIC_TYPES[metric]
167+
168 # output is like "SQUID-MIB::<key> <value>"
169 for line in output.split('\n'):
170 # ensure only what we asked, as snmpwalk can be overly generous
171@@ -85,15 +205,22 @@
172 name = scheme.replace('$METRIC', key)
173 else:
174 name = scheme + ".%s" % key
175- yield (name, value, tstamp)
176+ yield (name, value, metric_type)
177
178
179 if __name__ == '__main__':
180
181- if len(sys.argv) > 1:
182- config = load_config(sys.argv[1])
183- else:
184- config = load_config(config_path)
185+ config = load_config(config_path)
186+
187+ def send(x):
188+ print x
189+
190+ if len(sys.argv) > 1 and sys.argv[1] == "send":
191+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
192+ host, port = config['statsd_hostport'].split(':')
193+ sock.connect((host, int(port)))
194+ def send(x):
195+ sock.send(x)
196
197 for metric in get_metrics(config):
198- print "%s %s %s" % metric
199+ send(("%s:%s|%s" % metric).encode('utf8'))
200
201=== modified file 'hooks/tests/test_metrics.py'
202--- hooks/tests/test_metrics.py 2014-03-28 17:05:31 +0000
203+++ hooks/tests/test_metrics.py 2014-05-02 14:57:34 +0000
204@@ -31,6 +31,7 @@
205 self.config_get = self.add_patch("hooks.config_get")
206 self.local_unit = self.add_patch("hooks.local_unit")
207 self.log = self.add_patch("hooks.log")
208+ self.apt_install = self.add_patch("hooks.apt_install")
209
210 self.config_get.return_value = {
211 'metrics_sample_interval': 5,
212@@ -78,11 +79,12 @@
213 [metrics]
214 unit: unit/0
215 scheme: scheme
216- port: 1234
217+ snmp_port: 1234
218+ statsd_hostport: localhost:4321
219 community: community
220 metrics: a,b,c
221 """).strip()
222- self.assertEqual(config_write, expected_config)
223+ self.assertEqual(expected_config, config_write)
224
225 # 2nd open
226 cron_open_args = self.open.mock_calls[4][1]
227@@ -91,9 +93,9 @@
228 cron_write = self.open.mock_calls[6][1][0]
229 expected_cron = textwrap.dedent("""
230 # crontab for pushing squid metrics to statsd
231- */5 * * * * root python /script /config | nc localhost 4321
232- """).strip()
233- self.assertEqual(cron_write, expected_cron)
234+ */5 * * * * root python /script send
235+ """).lstrip()
236+ self.assertEqual(expected_cron, cron_write)
237
238
239 class MetricsJobTestCase(TestCase):
240@@ -109,20 +111,27 @@
241 self.config = {
242 'unit': 'unit/0',
243 'scheme': 'dev.$UNIT.$METRIC.5min',
244- 'port': '1234',
245+ 'snmp_port': '1234',
246+ 'statsd_hostport': '127.0.0.1:8000',
247 'community': 'public',
248 'metrics': [],
249 }
250
251 self.snmp = self.add_patch('squid_metrics.get_snmp_value')
252-
253- self.time = self.add_patch('squid_metrics.time.time')
254- self.time.return_value = 1
255+ patcher = patch.dict(squid_metrics.METRIC_TYPES, {
256+ 'first': 'c',
257+ 'second': 'c',
258+ 'third.5': 'g',
259+ 'fourth.60': 'g',
260+ 'cachePeerRtt': 'g',
261+ })
262+ patcher.start()
263+ self.addCleanup(patcher.stop)
264
265 def test_periods(self):
266
267 self.config['metrics'] = [
268- 'first', 'second', 'third.5', 'forth.60'
269+ 'first', 'second', 'third.5', 'fourth.60'
270 ]
271
272 self.snmp.side_effect = [
273@@ -130,16 +139,16 @@
274 'SQUID-MIB::first 1',
275 'SQUID-MIB::second.0 2',
276 'SQUID-MIB::third.5 3',
277- 'SQUID-MIB::forth.60 4',
278+ 'SQUID-MIB::fourth.60 4',
279 ]
280
281 metrics = list(squid_metrics.get_metrics(self.config))
282
283 self.assertEqual(metrics, [
284- ('dev.unit-0.first.5min', '1', 1),
285- ('dev.unit-0.second.5min', '2', 1),
286- ('dev.unit-0.third-5.5min', '3', 1),
287- ('dev.unit-0.forth-60.5min', '4', 1),
288+ ('dev.unit-0.first.5min', '1', 'c'),
289+ ('dev.unit-0.second.5min', '2', 'c'),
290+ ('dev.unit-0.third-5.5min', '3', 'g'),
291+ ('dev.unit-0.fourth-60.5min', '4', 'g'),
292 ])
293
294 def test_peers_with_names(self):
295@@ -163,9 +172,9 @@
296 metrics = list(squid_metrics.get_metrics(self.config))
297
298 self.assertEqual(metrics, [
299- ('dev.unit-0.cachePeerRtt.one-com.5min', '1', 1),
300- ('dev.unit-0.cachePeerRtt.two-org.5min', '2', 1),
301- ('dev.unit-0.cachePeerRtt.three-net.5min', '3', 1),
302+ ('dev.unit-0.cachePeerRtt.one-com.5min', '1', 'g'),
303+ ('dev.unit-0.cachePeerRtt.two-org.5min', '2', 'g'),
304+ ('dev.unit-0.cachePeerRtt.three-net.5min', '3', 'g'),
305 ])
306
307 def test_peers_without_names(self):
308@@ -185,7 +194,7 @@
309 metrics = list(squid_metrics.get_metrics(self.config))
310
311 self.assertEqual(metrics, [
312- ('dev.unit-0.cachePeerRtt.1.5min', '1', 1),
313- ('dev.unit-0.cachePeerRtt.2.5min', '2', 1),
314- ('dev.unit-0.cachePeerRtt.3.5min', '3', 1),
315+ ('dev.unit-0.cachePeerRtt.1.5min', '1', 'g'),
316+ ('dev.unit-0.cachePeerRtt.2.5min', '2', 'g'),
317+ ('dev.unit-0.cachePeerRtt.3.5min', '3', 'g'),
318 ])
319
320=== modified file 'templates/metrics_cronjob.template'
321--- templates/metrics_cronjob.template 2014-03-28 17:41:48 +0000
322+++ templates/metrics_cronjob.template 2014-05-02 14:57:34 +0000
323@@ -1,3 +1,3 @@
324 # crontab for pushing squid metrics to statsd
325-*/{{ interval }} * * * * root python {{ script }} {{ config }} | nc {{ statsd_host }} {{statsd_port }}
326+*/{{ interval }} * * * * root python {{ script }} send
327
328
329=== modified file 'templates/squid_metrics_ini.template'
330--- templates/squid_metrics_ini.template 2014-02-25 17:21:46 +0000
331+++ templates/squid_metrics_ini.template 2014-05-02 14:57:34 +0000
332@@ -1,6 +1,7 @@
333 [metrics]
334 unit: {{ unit_name }}
335 scheme: {{ metrics_scheme }}
336-port: {{ snmp_port }}
337+snmp_port: {{ snmp_port }}
338+statsd_hostport: {{ metrics_target }}
339 community: {{ snmp_community }}
340 metrics: {{ metrics_list|join(',') }}

Subscribers

People subscribed via source and target branches

to all changes: