| 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 |