OLD | NEW |
| (Empty) |
1 # Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 import pickle | |
6 import socket | |
7 import struct | |
8 | |
9 from buildbot.status.status_push import StatusPush | |
10 from buildbot.status import results | |
11 | |
12 | |
13 _DEFAULT_PORT = 2004 # Default port of pickled messages to Graphite | |
14 _SERVER_ADDRESS = 'skia-monitoring-b:%s' % _DEFAULT_PORT | |
15 | |
16 | |
17 def _sanitizeGraphiteNames(string): | |
18 return string.replace('.', '_').replace(' ', '_') | |
19 | |
20 | |
21 class GraphiteStatusPush(StatusPush): | |
22 """Uploads data to Graphite. Documentation for Graphite at | |
23 http://graphite.readthedocs.org/en/latest/feeding-carbon.html """ | |
24 | |
25 def __init__(self, serverAddr=_SERVER_ADDRESS): | |
26 self.currentBuilds = {} | |
27 self.serverAddress = serverAddr | |
28 StatusPush.__init__(self, GraphiteStatusPush.pushGraphite) | |
29 | |
30 def pushGraphite(self): | |
31 """Callback that StatusPush calls when something happens on the slaves.""" | |
32 events = self.queue.popChunk() | |
33 valid_events = [] | |
34 | |
35 def findInList(property_name, property_list): | |
36 """Extracts a property from the status data. The data is arranged as | |
37 triplets of information: internal name, data, external name.""" | |
38 for lst in property_list: | |
39 if property_name == lst[0] or property_name == lst[2]: | |
40 return lst[1] | |
41 | |
42 # Record only stepFinished events | |
43 for event in events: | |
44 if event['event'] == 'stepFinished': | |
45 builder_name = findInList('buildername', event['payload']['properties']) | |
46 master_name = findInList('master', event['payload']['properties']) | |
47 key = '.'.join([ | |
48 'buildbot', | |
49 _sanitizeGraphiteNames(master_name), | |
50 _sanitizeGraphiteNames(builder_name), | |
51 _sanitizeGraphiteNames(event['payload']['step']['name']) | |
52 ]) | |
53 | |
54 # Step duration. | |
55 start = event['payload']['step']['times'][0] | |
56 end = event['payload']['step']['times'][1] | |
57 # The output is also a triplet, (name, (timestamp, value)) | |
58 valid_events.append( | |
59 ('.'.join([key, 'duration']), | |
60 (end, end - start))) | |
61 | |
62 # Step result. | |
63 result = event['payload']['step'].get('results', [0])[0] | |
64 failure = 0 | |
65 success = 0 | |
66 if result != results.SKIPPED: | |
67 if result in (results.SUCCESS, results.WARNINGS): | |
68 success = 1 | |
69 else: | |
70 failure = 1 | |
71 valid_events.append(('.'.join((key, 'result')), (end, result))) | |
72 valid_events.append(('.'.join((key, 'success')), (end, success))) | |
73 valid_events.append(('.'.join((key, 'failure')), (end, failure))) | |
74 | |
75 if len(valid_events) <= 0: | |
76 print 'GraphiteStatusPush: No valid events to send' | |
77 return self.queueNextServerPush() | |
78 else: | |
79 print 'GraphiteStatusPush: %d events to send' % len(valid_events) | |
80 | |
81 # Send the events across a socket to the Graphite server | |
82 try: | |
83 sock = socket.socket() | |
84 ip_address = self.serverAddress.split(':')[0] | |
85 port_num = _DEFAULT_PORT | |
86 if len(self.serverAddress.split(':')) > 1: | |
87 port_num = int(self.serverAddress.split(':')[1]) | |
88 sock.connect((ip_address, port_num)) | |
89 for start in range(0, len(valid_events), 100): | |
90 message = pickle.dumps(valid_events[start:start+100]) | |
91 header = struct.pack('!L', len(message)) | |
92 sock.sendall(header + message) | |
93 except Exception: | |
94 print 'GraphiteStatusPush: unable to connect to server' | |
95 self.queue.insertBackChunk(events) | |
96 | |
97 return self.queueNextServerPush() | |
98 | |
99 | |
OLD | NEW |