def doImageRender(graphClass, graphOptions): pngData = StringIO() t = time() img = graphClass(**graphOptions) img.output(pngData) log.rendering('Rendered PNG in %.6f seconds' % (time() - t)) imageData = pngData.getvalue() pngData.close() return imageData
def renderLocalView(request): try: start = time() reqParams = StringIO(request.raw_post_data) graphType = reqParams.readline().strip() optionsPickle = reqParams.read() reqParams.close() graphClass = GraphTypes[graphType] options = unpickle.loads(optionsPickle) image = doImageRender(graphClass, options) log.rendering("Delegated rendering request took %.6f seconds" % (time() - start)) return buildResponse(image) except: log.exception("Exception in graphite.render.views.rawrender") return HttpResponseServerError()
def delegateRendering(graphType, graphOptions): start = time() postData = graphType + '\n' + pickle.dumps(graphOptions) servers = settings.RENDERING_HOSTS[:] #make a copy so we can shuffle it safely shuffle(servers) for server in servers: start2 = time() try: # Get a connection try: pool = connectionPools[server] except KeyError: #happens the first time pool = connectionPools[server] = set() try: connection = pool.pop() except KeyError: #No available connections, have to make a new one connection = HTTPConnectionWithTimeout(server) connection.timeout = settings.REMOTE_RENDER_CONNECT_TIMEOUT # Send the request try: connection.request('POST','/graphite/render/local/', postData) except CannotSendRequest: connection = HTTPConnectionWithTimeout(server) #retry once connection.timeout = settings.REMOTE_RENDER_CONNECT_TIMEOUT connection.request('POST', '/graphite/render/local/', postData) # Read the response response = connection.getresponse() assert response.status == 200, "Bad response code %d from %s" % (response.status,server) contentType = response.getheader('Content-Type') imageData = response.read() assert contentType == 'image/png', "Bad content type: \"%s\" from %s" % (contentType,server) assert imageData, "Received empty response from %s" % server # Wrap things up log.rendering('Remotely rendered image on %s in %.6f seconds' % (server,time() - start2)) log.rendering('Spent a total of %.6f seconds doing remote rendering work' % (time() - start)) pool.add(connection) return imageData except: log.exception("Exception while attempting remote rendering request on %s" % server) log.rendering('Exception while remotely rendering on %s wasted %.6f' % (server,time() - start2)) continue
def renderView(request): start = time() (graphOptions, requestOptions) = parseOptions(request) useCache = 'noCache' not in requestOptions cacheTimeout = requestOptions['cacheTimeout'] requestContext = { 'startTime' : requestOptions['startTime'], 'endTime' : requestOptions['endTime'], 'localOnly' : requestOptions['localOnly'], 'data' : [] } data = requestContext['data'] # First we check the request cache if useCache: requestKey = hashRequest(request) cachedResponse = cache.get(requestKey) if cachedResponse: log.cache('Request-Cache hit [%s]' % requestKey) log.rendering('Returned cached response in %.6f' % (time() - start)) return cachedResponse else: log.cache('Request-Cache miss [%s]' % requestKey) # Now we prepare the requested data if requestOptions['graphType'] == 'pie': for target in requestOptions['targets']: if target.find(':') >= 0: try: name,value = target.split(':',1) value = float(value) except: raise ValueError, "Invalid target '%s'" % target data.append( (name,value) ) else: seriesList = evaluateTarget(requestContext, target) for series in seriesList: func = PieFunctions[requestOptions['pieMode']] data.append( (series.name, func(requestContext, series) or 0 )) elif requestOptions['graphType'] == 'line': # Let's see if at least our data is cached if useCache: targets = requestOptions['targets'] startTime = requestOptions['startTime'] endTime = requestOptions['endTime'] dataKey = hashData(targets, startTime, endTime) cachedData = cache.get(dataKey) if cachedData: log.cache("Data-Cache hit [%s]" % dataKey) else: log.cache("Data-Cache miss [%s]" % dataKey) else: cachedData = None if cachedData is not None: requestContext['data'] = data = cachedData else: # Have to actually retrieve the data now for target in requestOptions['targets']: t = time() seriesList = evaluateTarget(requestContext, target) log.rendering("Retrieval of %s took %.6f" % (target, time() - t)) data.extend(seriesList) if useCache: cache.set(dataKey, data, cacheTimeout) format = requestOptions.get('format') if format == 'csv': response = HttpResponse(mimetype='text/csv') writer = csv.writer(response, dialect='excel') for series in data: for i, value in enumerate(series): timestamp = datetime.fromtimestamp(series.start + (i * series.step), requestOptions['tzinfo']) writer.writerow((series.name, timestamp.strftime("%Y-%m-%d %H:%M:%S"), value)) return response if format == 'json': series_data = [] for series in data: timestamps = range(series.start, series.end, series.step) datapoints = zip(series, timestamps) series_data.append( dict(target=series.name, datapoints=datapoints) ) if 'jsonp' in requestOptions: response = HttpResponse( content="%s(%s)" % (requestOptions['jsonp'], json.dumps(series_data)), mimetype='text/javascript') else: response = HttpResponse(content=json.dumps(series_data), mimetype='application/json') response['Pragma'] = 'no-cache' response['Cache-Control'] = 'no-cache' return response if format == 'raw': response = HttpResponse(mimetype='text/plain') for series in data: response.write( "%s,%d,%d,%d|" % (series.name, series.start, series.end, series.step) ) response.write( ','.join(map(str,series)) ) response.write('\n') log.rendering('Total rawData rendering time %.6f' % (time() - start)) return response if format == 'svg': graphOptions['outputFormat'] = 'svg' if format == 'pickle': response = HttpResponse(mimetype='application/pickle') seriesInfo = [series.getInfo() for series in data] pickle.dump(seriesInfo, response, protocol=-1) log.rendering('Total pickle rendering time %.6f' % (time() - start)) return response # We've got the data, now to render it graphOptions['data'] = data if settings.REMOTE_RENDERING: # Rendering on other machines is faster in some situations image = delegateRendering(requestOptions['graphType'], graphOptions) else: image = doImageRender(requestOptions['graphClass'], graphOptions) useSVG = graphOptions.get('outputFormat') == 'svg' if useSVG and 'jsonp' in requestOptions: response = HttpResponse( content="%s(%s)" % (requestOptions['jsonp'], json.dumps(image)), mimetype='text/javascript') else: response = buildResponse(image, useSVG and 'image/svg+xml' or 'image/png') if useCache: cache.set(requestKey, response, cacheTimeout) log.rendering('Total rendering time %.6f seconds' % (time() - start)) return response