Skip to content

Instantly share code, notes, and snippets.

@kfdm
Created August 18, 2017 03:08
Show Gist options
  • Save kfdm/a82c7c8fd4c70c471bc63219d5cc1f11 to your computer and use it in GitHub Desktop.
Save kfdm/a82c7c8fd4c70c471bc63219d5cc1f11 to your computer and use it in GitHub Desktop.
Prometheus Proxy Example

Promgen Code

Here's the above code with some additional comments for explanation

class ProxyQueryRange(PrometheusProxy):
    def get(self, request):
        data = []
        futures = []
        resultType = None
        with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
            # In Promgen, we put multiple prometheus servers behind nginx so
            # our Shard object contains our url like shard-name.example.com
            # and we filter by the shards enabled to proxy
            # Elsewhere in Promgen, we have a list of prometheus servers per
            # shard that could be accessed like shard.prometheus_set but that
            # isn't used here
            for host in models.Shard.objects.filter(proxy=True):
                # util.get is just a light wrapper around Python request's
                # request.get to add a User-Agent and Referer header to help
                # with debugging where requests come from. In general, we take
                # the query, as-is, from Grafana, and send that to each of our
                # upstream Prometheus shards
                futures.append(executor.submit(util.get, '{}/api/v1/query_range?{}'.format(host.url, request.META['QUERY_STRING']), headers=self.headers))
            for future in concurrent.futures.as_completed(futures):
                try:
                    result = future.result()
                    logger.debug('Appending data from %s', result.request.url)
                    _json = result.json()
                    # While it is a bit naieve to just append data in this way,
                    # it seems to handle ~90% of our use cases so it seemed a
                    # reasonable way to do this in a simple to understand way.
                    # We can always query a specific shard directly if the data
                    # looks strange
                    data += _json['data']['result']
                    resultType = _json['data']['resultType']
                except:
                    logger.exception('Error with response')

        return JsonResponse({
            'status': 'success',
            'data': {
                'resultType': resultType,
                'result': data,
            }
        })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment