brutasse / graphite-cyanite

A plugin for using graphite-web with the cassandra-based Cyanite storage backend.
BSD 3-Clause "New" or "Revised" License
85 stars 21 forks source link

"TypeError: string indices must be integers" from graphite-web #10

Closed mwmanley closed 9 years ago

mwmanley commented 9 years ago

This code block seems problematic when using this plugin against graphite-web 0.10.0:

def find_nodes(self, query):
    paths = requests.get(urls.paths,
                         params={'query': query.pattern}).json()
    for path in paths:
        if path['leaf']:
            yield CyaniteLeafNode(path['path'],
                                  CyaniteReader(path['path']))
        else:
            yield BranchNode(path['path'])

When I try to use aggregation or summary functions against wildcard paths, such as "sumSeries", I am getting:

File "/usr/lib/python2.7/site-packages/cyanite.py", line 107, in find_nodes if path['leaf']: TypeError: string indices must be integers

But only if I use an aggregation/summary function. If I do not use a function, graphite will render the data from Cassandra correctly.

The JSON looks formed correctly, so I am not sure what is going on. I am using Python 2.7. Has anyone else encountered this issue? I will keep plugging away at all the Python, but this bug seems rather severe.

Thanks!

brutasse commented 9 years ago

Can you show the values of query.pattern and paths in the find_nodes function? It'd be easier to troubleshoot with the data returned by cyanite.

mwmanley commented 9 years ago

Sure. Here you go. Added:

    print query.pattern
    print paths

and here you go:

[Fri May 01 21:20:55 2015] [error] prd.ca1.bidder01.bidding.*.bids [Fri May 01 21:20:55 2015] [error] [{u'path': u'prd.ca1.bidder01.bidding.SOMO_AUDIENCE.bids', u'depth': 6, u'leaf': True, u'tenant': u''}, {u'path': u'prd.ca1.bidder01.bidding.PUBMATIC_RTB.bids', u'depth': 6, u'leaf': True, u'tenant': u''}, {u'path': u'prd.ca1.bidder01.bidding.SPOTX.bids', u'depth': 6, u'leaf': True, u'tenant': u''}, {u'path': u'prd.ca1.bidder01.bidding.PASS_BACK_PURGATORY.bids', u'depth': 6, u'leaf': True, u'tenant': u''}, {u'path': u'prd.ca1.bidder01.bidding.DFP_SB_TAPAD.bids', u'depth': 6, u'leaf': True, u'tenant': u''}, {u'path': u'prd.ca1.bidder01.bidding.SMAATO.bids', u'depth': 6, u'leaf': True, u'tenant': u''}, {u'path': u'prd.ca1.bidder01.bidding.RMX.bids', u'depth': 6, u'leaf': True, u'tenant': u''}, {u'path': u'prd.ca1.bidder01.bidding.APPNEXUS.bids', u'depth': 6, u'leaf': True, u'tenant': u''}, {u'path': u'prd.ca1.bidder01.bidding.RUBICON.bids', u'depth': 6, u'leaf': True, u'tenant': u''}]

brutasse commented 9 years ago

Hmm thanks… But is this when you get the error? I don't see how an if path['leaf'] check would fail with this data

mwmanley commented 9 years ago

Yeah. I am confused too:

Traceback (most recent call last): File "/usr/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response response = wrapped_callback(request, _callback_args, *_callback_kwargs) File "/opt/graphite/webapp/graphite/metrics/views.py", line 128, in find_view matches = list( STORE.find(query, fromTime, untilTime, local=local_only) ) File "/opt/graphite/webapp/graphite/storage.py", line 47, in find for node in finder.find_nodes(query): File "/usr/lib/python2.7/site-packages/cyanite.py", line 102, in find_nodes if path['leaf']: TypeError: string indices must be integers

mwmanley commented 9 years ago

I figured out the problem. It's not with this, which is a red herring. The problem is that the cyanite plugin doesn't handle when wildcard paths match strings that return no data. So, the string comes back with a timeseries, and obviously no path and no data.

I re-wrote "fetch" as below and it now does sums, averages, and so on correctly:

def fetch(self, start_time, end_time):
    data = requests.get(urls.metrics, params={'path': self.path,
                                              'from': start_time,
                                              'to': end_time}).json()
    if 'error' in data:
        return (start_time, end_time, end_time - start_time), []
    time_info = data['from'], data['to'], data['step']
    if len (data['series']) == 0:
        return
    return time_info, data['series'].get(self.path, [])

If you want, I can submit a patch. Without this return of nothing, it seems to be causing graphite-web to just return no results.

brutasse commented 9 years ago

Thank you, I just integrated your fix! A new version is available on PyPI so you can update your graphite-cyanite installation.

altvnk commented 9 years ago

I'm experiencing the same error with updated code:

Sat Aug 08 01:43:14 2015 :: Exception Caught
Traceback (most recent call last):
  File "/opt/graphite/webapp/graphite/metrics/views.py", line 128, in find_view
    matches = list( STORE.find(query, fromTime, untilTime, local=local_only) )
  File "/opt/graphite/webapp/graphite/storage.py", line 47, in find
    for node in finder.find_nodes(query):
  File "/usr/lib/python2.7/site-packages/cyanite.py", line 104, in find_nodes
    if path['leaf']:
TypeError: string indices must be integers
Sat Aug 08 01:43:14 2015 :: Exception encountered in <GET http://node-01:8080/metrics/find/?_dc=1438987394664&query=*&format=treejson&path=&node=GraphiteTree>
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/django/core/handlers/base.py", line 112, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/opt/graphite/webapp/graphite/metrics/views.py", line 128, in find_view
    matches = list( STORE.find(query, fromTime, untilTime, local=local_only) )
  File "/opt/graphite/webapp/graphite/storage.py", line 47, in find
    for node in finder.find_nodes(query):
  File "/usr/lib/python2.7/site-packages/cyanite.py", line 104, in find_nodes
    if path['leaf']:
TypeError: string indices must be integers
altvnk commented 9 years ago

Seems like this is referenced to https://github.com/pyr/cyanite/issues/119