Giter Site home page Giter Site logo

graphite-influxdb's Introduction

Graphite-InfluxDB

An influxdb (0.8-rc5 or higher) backend for Graphite-web (source or 0.10.x) or graphite-api.

STATUS

THIS PROJECT IS NO LONGER MAINTAINED. CHECK OUT [InfluxGraph](https://github.com/InfluxGraph/influxgraph) instead.

Install and configure using docker

Using docker is an easy way to get graphite-api + graphite-influx up and running. See https://github.com/Dieterbe/graphite-api-influxdb-docker which provides a container that has all packages installed to make maximum use of these tools.

Otherwise, follow instructions below. Graphite-api is the simplest to setup, though graphite-web might perform better. You can use the experimental statsd support in graphite-api to have this backend submit performance metrics (not supported with graphite-web)

Manual installation

pip install graphite_influxdb

About the retention schemas

In the configs below, you'll see that you need to configure the schemas (datapoint resolutions) explicitly. It basically contains the same information as /etc/carbon/storage-schemas.conf would for whisper. But Influxdb currently has no way to supply us this information (yet), so we must configure it explicitly here. Also, it seems like internally, the graphite-web/graphite-api is to configure the step (resolution in seconds) per metric (i.e. per Node/Reader), without looking at the timeframe. I don't know how to deal with this yet (TODO), so for now it's one step per pattern, so we don't need to specify retention timeframes. (In fact, in the code we can assume the data exists from now to -infinity, missing data you query for will just show up as nulls anyway) The schema declares at which interval you should have points in InfluxDB. Schema rules use regex and are processed in order, first match wins. If no rule matches, 60 seconds is used.

Using with graphite-api

You need the patched version from https://github.com/Dieterbe/graphite-api/tarball/support-templates2 This adds support for caching, statsd instrumentation, and graphite-style templates

Note that the elasticsearch stuff is optional, see below

In your graphite-api config file:

finders:
  - graphite_influxdb.InfluxdbFinder
influxdb:
   host: localhost
   port: 8086
   user: graphite
   pass: graphite
   db:   graphite
   ssl: false
   schema:
     - ['high-res-metrics', 1]
     - ['^collectd', 10]
es:
   enabled: false
   hosts:
     - elastichost1:9200
   index: graphite_metrics2
   field: _id

Also enable the cache. memcache doesn't seem to work well because the list of series is too big. filesystem seems to work well:

cache:
    type: 'filesystem'
    dir: '/tmp/graphite-api-cache'

Using with graphite-web

Note that the elasticsearch stuff is optional, see below In graphite's local_settings.py:

STORAGE_FINDERS = (
    'graphite_influxdb.InfluxdbFinder',
)
INFLUXDB_HOST = "localhost"
INFLUXDB_PORT = 8086
INFLUXDB_USER = "graphite"
INFLUXDB_PASS = "graphite"
INFLUXDB_DB =  "graphite"
INFLUXDB_SSL = "false"
INFLUXDB_SCHEMA = [
    ('', 60),
    ('high-res-metrics', 10)
]
ES_ENABLED = "false"
ES_HOSTS = ['elastichost1:9200']
ES_INDEX = "graphite_metrics2"
ES_FIELD = "_id"

Using Elasticsearch as an index

If you have an index in elasticsearch that contains all your metric id's, then you can use that as a metadata source. Your mileage may vary, but for me ES is noticeably faster. (see also influxdata/influxdb#884) You just need to install the elasticsearch pip module (comes in the docker image mentioned above) and enable it in the config. If you're wondering how to populate an ES index, you can use graph-explorer structured metrics plugins or carbon-tagger (beware the latter currently only does metrics 2.0 metrics)

graphite-influxdb's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphite-influxdb's Issues

TypeError('reduce() of empty sequence with no initial value',): seriesLists was: ([],)

this error shows up from time to time, not sure yet why.
somehow graphite-api/functions.py normalize() receives an empty list as input.
i've been trying to trace it down but couldn't get log messages from my fetch and fetch_multi functions.
I'm hoping that once logging is a bit more robust in graphite-api I'll be able to fix it properly.
either fetch or fetch_multi is not returning a proper list, or maybe those functions just aren't called properly.

cc @brutasse

cache object is not available

When starting graphite-api with gunicorn, I got this exception:
Traceback (most recent call last):
File "/usr/local/bin/gunicorn", line 9, in
load_entry_point('gunicorn==19.0.0', 'console_scripts', 'gunicorn')()
File "/usr/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 74, in run
WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
File "/usr/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 166, in run
super(Application, self).run()
File "/usr/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 71, in run
Arbiter(self).run()
File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 196, in run
self.halt(reason=inst.reason, exit_status=inst.exit_status)
File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 292, in halt
self.stop()
File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 343, in stop
time.sleep(0.1)
File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 209, in handle_chld
self.reap_workers()
File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 459, in reap_workers
raise HaltServer(reason, self.WORKER_BOOT_ERROR)
gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3>

In class InfluxdbFinder you init cache using graphite_api cache (but I can't find graphite_api cache object in graphite_api code (graphite_api.app, there's no such cache object).
class InfluxdbFinder(object):
fetch_multi = 'influxdb'
slots = ('client', 'schemas', 'cache', 'cheat_times')

def __init__(self, config=None):
    try:
        from graphite_api.app import app
        self.cache = app.cache
    except:
        from django.core.cache import cache
        self.cache = cache

Since we fall back to Django cache, I don't know why using Django cache because we do not use Django here. Caching using Django cache need to be set somewhere else (?). How to get this work with that exception?

class InfluxdbFinder(object):
fetch_multi = 'influxdb'
slots = ('client', 'schemas', 'cache', 'cheat_times')

def __init__(self, config=None):
    try:
        from graphite_api.app import app
        self.cache = app.cache
    except:
        from django.core.cache import cache
        self.cache = cache

Documentation should include an example query

I'm trying to use this backend to render graphs from an InfluxDB but I'm unable to formulate a render query that returns a graph. It would be great if there was one ore more example render URLs in the documentation.

list series not in current influxdb, 400 error

Traceback (most recent call last):
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_api-1.1.2-py2.7.egg/graphite_api/app.py", line 207, in metrics_index
    recurse('*', index)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_api-1.1.2-py2.7.egg/graphite_api/app.py", line 243, in recurse
    for node in app.store.find(query):
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_api-1.1.2-py2.7.egg/graphite_api/storage.py", line 22, in find
    for node in finder.find_nodes(query):
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_influxdb.py", line 323, in find_nodes
    for (name, res) in self.get_leaves(query):
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_influxdb.py", line 278, in get_leaves
    series = self.assure_series(query)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_influxdb.py", line 247, in assure_series
    ret = self.client.query("list series /%s/" % regex.pattern)
  File "/var/www/webapp/graphite-api/venv/libTraceback (most recent call last):
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_api-1.1.2-py2.7.egg/graphite_api/app.py", line 207, in metrics_index
    recurse('*', index)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_api-1.1.2-py2.7.egg/graphite_api/app.py", line 243, in recurse
    for node in app.store.find(query):
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_api-1.1.2-py2.7.egg/graphite_api/storage.py", line 22, in find
    for node in finder.find_nodes(query):
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_influxdb.py", line 323, in find_nodes
    for (name, res) in self.get_leaves(query):
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_influxdb.py", line 278, in get_leaves
    series = self.assure_series(query)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/graphite_influxdb.py", line 247, in assure_series
    ret = self.client.query("list series /%s/" % regex.pattern)
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/influxdb/client.py", line 325, in query
    expected_response_code=expected_response_code
  File "/var/www/webapp/graphite-api/venv/lib/python2.7/site-packages/influxdb/client.py", line 248, in request
    raise InfluxDBClientError(response.content, response.status_code)
InfluxDBClientError: 400: {"error":"error parsing query: found list, expected SELECT, DELETE, SHOW, CREATE, DROP, GRANT, REVOKE, ALTER, SET at line 1, char 1"}

relevant section, graphite_influxdb.py

with statsd.timer('service=graphite-api.ext_service=influxdb.target_type=gauge.unit=ms.action=get_series'):
            ret = self.client.query("list series /%s/" % regex.pattern)

Cache generation breaks API

Hi there

I'm using latest commit (5d33c4c) and having issues with maintain_cache.py

as i deduced, it queries influx for all metric names and presents them to graphite-api in form of a cache (files on fs), the /index endpoint run then generates the graphite-like metric tree (right? ;])

maintain_cache.py runs in an endless loop and updates the cache. problem is, the cache is unreadable during the some runtime of the loop and the API gives me HTTP 500. however, for few secs of the loop period, the cache is readable (or empty, though i've got a lot of 14B files constantly popping in and out) and the API serves something:

$ curl -X POST -H "Content-Type: application/json" http://localhost:8888/index -o-
{
  "entries": 0,
  "success": true
}

and

$ curl -X GET -H "Content-Type: application/json" http://localhost:8888/metrics/find?query=* -o-
[]

and

https://gist.github.com/blufor/b1a8c8ece8535041f6c2

maintain_cache.py output:

BEGIN LOOP
influxdb:: list series
influxdb:: list series took 0.047581911087 seconds
building datastructures
size of series data 104
size of series list 87632
building datastructures took 0.00231409072876 seconds
cache:: store series_list
cache:: store series_list took 0.00760102272034 seconds
influxdb:: select * from // order asc limit 1
influxdb:: select * from // order asc limit 1 took 5.18891000748 seconds
cache:: store first-point for all series
cache:: store first-point for all series took 7.52191519737 seconds
ENTIRE LOOP took 12.769493103 seconds

Some versions:

  • influx: 0.8-rc4
  • graphite-api: the version from the PR mentioned in README
  • python: 2.7

Cyclical dependency between graphite_api and graphite_influxdb

At https://github.com/vimeo/graphite-influxdb/blob/master/graphite_influxdb.py#L225 there is an attempt to import graphite_api.app.

However, graphite_api tries to import graphite_influxdb.InfluxdbFinder if /etc/graphite-api.yaml is configured with an InfluxDBFinder.

This causes a cyclical dependency graphite_api -> graphite_influxdb -> graphite_api and an import error, causing graphite_api to not startup.

>>> from graphite_api.app import app
{"path": "/etc/graphite-api.yaml", "event": "loading configuration"}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/site-packages/graphite_api/app.py", line 48, in <module>
    configure(app)
  File "/usr/lib/python2.6/site-packages/graphite_api/config.py", line 96, in configure
    finders.append(load_by_path(finder)(config))
  File "/usr/lib/python2.6/site-packages/graphite_influxdb.py", line 228, in __init__
    from django.core.cache import cache
ImportError: No module named django.core.cache

/etc/graphite-api.yaml has:

search_index: /tmp/index
finders:
  - graphite_influxdb.InfluxdbFinder
  <..>
  cache:
    CACHE_TYPE: 'filesystem'
    CACHE_DIR: '/tmp/graphite-api-cache'

'show series' response breaking api change causing empty series list

Hello,

Influxdb on 0.12 includes breaking api change in 'show swries' response.
https://docs.influxdata.com/influxdb/v0.11/concepts/010_vs_011
That causes problem in the assure_series function.
I had temporary fixed the problem by modifying response parsing at the end of the function

-                 series = [key_name for (key_name,_) in ret.keys()]
+                 series = [key_name for [key_name] in  ret.raw['series'][0]['values']]

That should be probably configurable and/or detectable by the client (maybe client library?) and appropriate parsing function should be used.

Error on list-series: InfluxDBClientError: 400: syntax error, unexpected '/', expecting $end

Hi Guys.

After we are reinstalled last graphite-influxdb f and influxdb-python packages. from github, we got the following error:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 111, in get_response
    response = 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/local/lib/python2.7/dist-packages/graphite_influxdb-0.3-py2.7.egg/graphite_influxdb.py", line 302, in find_nodes
    for (name, res) in self.get_leaves(query):
  File "/usr/local/lib/python2.7/dist-packages/graphite_influxdb-0.3-py2.7.egg/graphite_influxdb.py", line 257, in get_leaves
    series = self.assure_series(query)
  File "/usr/local/lib/python2.7/dist-packages/graphite_influxdb-0.3-py2.7.egg/graphite_influxdb.py", line 226, in assure_series
    ret = self.client.query("list series /%s/" % regex.pattern)
  File "/usr/local/lib/python2.7/dist-packages/influxdb-0.1.11-py2.7.egg/influxdb/client.py", line 282, in query
    status_code=200
  File "/usr/local/lib/python2.7/dist-packages/influxdb-0.1.11-py2.7.egg/influxdb/client.py", line 124, in request
    raise InfluxDBClientError(response.content, response.status_code)
InfluxDBClientError: 400: syntax error, unexpected '/', expecting $end
list series /^[^\.]*/
            ^

After reviewing the influxdb docs http://influxdb.com/docs/v0.7/api/query_language.html it seems like query should be either:

list series

or

select * from /.*/ 

We are working on

InfluxDB v0.7.3 (git: 216a3eb) (leveldb: 1.15)

Can you help me to fix it?

When trying to use the latest code, I only receive 500 errors

I'm testing with the latest code but only receive 500 errors. I tested with the 0.2 version earlier today and that one works fine. So is there anything broken with tip at the moment? Or should it work? As I saw a couple of improvements in the caching mechanism, I would like to give it a go with the latest code available :)

So any pointer would be great!

Note: I did of course use a patched graphite-api to test with! And I'm using InfluxDB 0.7.3 so I didn't take the latest 'maintain_cache.py' from 16 hours ago, but the previous one.

optimize get_intervals

as per http://graphite-api.readthedocs.org/en/latest/finders.html

get_intervals() is a method that hints graphite-web about the time range available for
this given metric in the database. It must return an IntervalSet of one or more Interval objects.

this function gets invoked when constructing a LeafNode https://github.com/brutasse/graphite-api/blob/master/graphite_api/node.py#L24

I'm not clear on the specifics, but it looks like whenever you do a request for something like /render/?target=foo.bar.* get_intervals() will get executed for all matching targets, which causes a slowdown.

I hope @brutasse can weigh in on this, but i'm looking to make this more efficient, maybe get this info for all series at once. perhaps collecting this information is better done in find_nodes(), where we would collect all matching series, their columns an their interval all at once. (this would require some influxdb enhancements)

Not sending data to InfluxDB

Made changes in Graphite-web local_settings.py. Restarted all services. Now inserted values in InfluxDB using in-built Graphite listener. But data is not refelecting in Graphite web ui.

latest influxdb.InfluxDBClient and influxDB 0.8.8

Hi all, nice work, for while I fight with influxdb installed via PIP. I was not able to make it work until I found problem with influxdb lib, what have compatibility update
so I changed line 6

from influxdb import InfluxDBClient

to

from influxdb.influxdb08  import InfluxDBClient

woala all is working now :)

# pip list | grep influx
graphite-influxdb (0.4)
influxdb (1.0.0)

the Installation needs graphite-api even when install on graphite-web

We would like to install graphite-web on front of a influxdb database but graphite-influxdb needs graphite-api !!

can I configure on with graphite-web without graphite-api ?

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 101, in get_response
    request.path_info)
  File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py", line 300, in resolve
    sub_match = pattern.resolve(new_path)
  File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py", line 300, in resolve
    sub_match = pattern.resolve(new_path)
  File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py", line 209, in resolve
    return ResolverMatch(self.callback, args, kwargs, self.name)
  File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py", line 216, in callback
    self._callback = get_callable(self._callback_str)
  File "/usr/local/lib/python2.7/dist-packages/django/utils/functional.py", line 27, in wrapper
    result = func(*args)
  File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py", line 92, in get_callable
    lookup_view = getattr(import_module(mod_name), func_name)
  File "/usr/local/lib/python2.7/dist-packages/django/utils/importlib.py", line 35, in import_module
    __import__(name)
  File "/opt/graphite/webapp/graphite/metrics/views.py", line 21, in <module>
    from graphite.storage import STORE
  File "/opt/graphite/webapp/graphite/storage.py", line 165, in <module>
    STORE = Store()
  File "/opt/graphite/webapp/graphite/storage.py", line 27, in __init__
    for finder_path in settings.STORAGE_FINDERS]
  File "/opt/graphite/webapp/graphite/storage.py", line 20, in get_finder
    return getattr(module, class_name)()
  File "/usr/local/lib/python2.7/dist-packages/graphite_influxdb-0.2-py2.7.egg/graphite_influxdb.py", line 223, in __init__
    from graphite_api.app import app
ImportError: No module named graphite_api.app

find queries for metrics that don't match + errors out due to "="

http://localhost:8000/metrics/find?query=idle

T 172.17.0.2:43465 -> 10.90.128.100:8086 [AP]
GET /db/graphite/series?q=select+%2A+from+service%3Dstatsdaemon.instance%3Dgce-central.statsd_type%3Dgauge.target_type%3Dgauge.type%3Dcalculation.unit%3Dms+limit+1&p=graphite&time_precision=s&chunked=false&u=graphite HTTP/1.1.
Host: graphite.df.vimeows.com:8086.
Accept-Encoding: gzip, deflate, compress.
Accept: */*.
User-Agent: python-requests/2.2.1 CPython/2.7.3 Linux/3.13.8-1-ARCH.
.

#
T 10.90.128.100:8086 -> 172.17.0.2:43465 [AP]
HTTP/1.1 400 Bad Request.
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept.
Access-Control-Allow-Methods: GET, POST, PUT, DELETE.
Access-Control-Allow-Origin: *.
Access-Control-Max-Age: 2592000.
Content-Type: text/plain.
Date: Tue, 08 Apr 2014 22:43:13 GMT.
Content-Length: 71.
.
Error at 0:21. syntax error, unexpected OPERATION_EQUAL, expecting $end

the influxdb error results in graphite-api http 500

make it faster

  1. gunicorn processes every request in sequence, even when they're stuck getting the data from influxdb. so if you load a dashboard with a bunch of graphs, it takes a while before they all load.
    even with -k gevent -w 8 --threads 16 it only processes as many requests at a time as you have cores. I would love for graphite-api / gunicorn to be able to process all requests in parrallel.

  2. as seen with the statsd instrumentation, here are some slow things and what we can do about them:

cache_get_nodes 150 ms

right now, on every render request we load the entire list of series, which is slow.
once influxdb gets support for list series like /<regex>/ this should be faster, and we can do away with the seperate maintain_cache.py script

find_branches 1000ms
find_leaves 100ms
( --> yield_nodes 1100ms)

the caching works relatively well to alleviate these (the cache gets are < 1ms), but on cache miss it's expensive, the solution is the same as above. if influx can return a list filtered on regex, this can be a lot shorter and quicker. now we iterate over all series and do the logic in python.

cc @pauldix TLDR: list series like /regex/ would shave a few hundred ms off every graphite-influxdb graph render request.

get_intervals (get oldest and latest timestamp for series)

slow too, but we can use the cheat_times option for now.

circular import when import graphite_api

import graphite_influxdb

Traceback (most recent call last):
File "graphite_api/app.py", line 63, in
configure(app)
File "graphite_api/config.py", line 127, in configure
finders.append(load_by_path(finder)(config))
File "graphite_api/config.py", line 74, in load_by_path
return getattr(finder, klass)
AttributeError: 'module' object has no attribute 'InfluxdbFinder'

Error 500/404.

Hi. Trying to implement graphite-api + graphite-influxdb and having complex problems with what I interpret should be a simple process.

From what I understand, I should be able to get a test call working at http://theserver:8013/render?target=test, but this throws an error 500 in Apache which, when I enabled some more verbose Python logging in the WSGI script, actually showed a 404 on the back-end. This same behavior is what happens when issuing any URL call to the Render API, actually. Any assistance provided would be greatly appreciated as I'm pretty much at the end of my rope, lack the Python chops to do any deeper debugging with gdb and such, and am fairly desperate for a solution. :)

Host system is CentOS 7 with Python 2.7.5, all modules installed via latest Pip.

/etc/graphite-api.yaml:

search_index: /var/www/wsgi-scripts/index
finders:
  - graphite_influxdb.InfluxdbFinder
influxdb:
   host: localhost
   port: 8086
   user: grafana
   pass: grafanaisawesome
   db:   graphite
   ssl: false
   schema:
     - ['^monitoring', 1]
cache:
    type: 'filesystem'
    dir: '/var/www/wsgi-scripts/graphite-api-cache'
/etc/httpd/conf.d/graphite-api.conf:

LoadModule wsgi_module modules/mod_wsgi.so

WSGISocketPrefix /var/run/wsgi

Listen 8013
<VirtualHost *:8013>

    WSGIDaemonProcess graphite-api processes=5 threads=5 display-name='%{GROUP}' inactivity-timeout=120
    WSGIProcessGroup graphite-api
    WSGIApplicationGroup %{GLOBAL}
    WSGIImportScript /var/www/wsgi-scripts/graphite-api.wsgi process-group=graphite-api application-group=%{GLOBAL}

    WSGIScriptAlias / /var/www/wsgi-scripts/graphite-api.wsgi

    <Directory /var/www/wsgi-scripts/>
        Order deny,allow
        Allow from all
    </Directory>

</VirtualHost>
/var/www/wsgi-scripts/graphite-api.wsgi:

from graphite_api.app import app as application

Stack trace from Apache error logs with Python debug logging configured:

[Mon May 04 15:56:44.913840 2015] [:error] [pid 21770] F1 2015-05-04 15:56:44,913 ERROR {"event": "Exception on /render [GET]", "exception": "Traceback (most recent call last):\\n  File \\"/usr/lib/python2.7/site-packages/flask/app.py\\", line 1817, in wsgi_app\\n    response = self.full_dispatch_request()\\n  File \\"/usr/lib/python2.7/site-packages/flask/app.py\\", line 1477, in full_dispatch_request\\n    rv = self.handle_user_exception(e)\\n  File \\"/usr/lib/python2.7/site-packages/flask/app.py\\", line 1381, in handle_user_exception\\n    reraise(exc_type, exc_value, tb)\\n  File \\"/usr/lib/python2.7/site-packages/flask/app.py\\", line 1475, in full_dispatch_request\\n    rv = self.dispatch_request()\\n  File \\"/usr/lib/python2.7/site-packages/flask/app.py\\", line 1461, in dispatch_request\\n    return self.view_functions[rule.endpoint](**req.view_args)\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/app.py\\", line 394, in render\\n    series_list = evaluateTarget(context, target)\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/app.py\\", line 470, in evaluateTarget\\n    result = evaluateTokens(requestContext, tokens)\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/app.py\\", line 480, in evaluateTokens\\n    return evaluateTokens(requestContext, tokens.expression)\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/app.py\\", line 488, in evaluateTokens\\n    arg) for arg in tokens.call.args]\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/app.py\\", line 480, in evaluateTokens\\n    return evaluateTokens(requestContext, tokens.expression)\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/app.py\\", line 483, in evaluateTokens\\n    return fetchData(requestContext, tokens.pathExpression)\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/render/datalib.py\\", line 158, in fetchData\\n    return _fetchData(pathExpr, startTime, endTime, requestContext, seriesList)\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/render/datalib.py\\", line 95, in _fetchData\\n    for node in matching_nodes:\\n  File \\"/usr/lib/python2.7/site-packages/graphite_api/storage.py\\", line 22, in find\\n    for node in finder.find_nodes(query):\\n  File \\"/usr/lib/python2.7/site-packages/graphite_influxdb.py\\", line 323, in find_nodes\\n    for (name, res) in self.get_leaves(query):\\n  File \\"/usr/lib/python2.7/site-packages/graphite_influxdb.py\\", line 278, in get_leaves\\n    series = self.assure_series(query)\\n  File \\"/usr/lib/python2.7/site-packages/graphite_influxdb.py\\", line 247, in assure_series\\n    ret = self.client.query(\\"list series /%s/\\" % regex.pattern)\\n  File \\"/usr/lib/python2.7/site-packages/influxdb/client.py\\", line 309, in query\\n    expected_response_code=expected_response_code\\n  File \\"/usr/lib/python2.7/site-packages/influxdb/client.py\\", line 272, in request\\n    raise InfluxDBClientError(response.content, response.status_code)\\nInfluxDBClientError: 404: 404 page not found\\n"}

Simple error thrown without Python logging configured:

[Mon May 04 15:41:00.483854 2015] [:error] [pid 21379] No handlers could be found for logger "flask.app"

Thanks in advance for any direction provided.

get_leaves() broken

since pr #39 get_leaves() now returns each leaf multiple times, once for each defined step rule.
this function was modified because it was supposedly faster. i've written a test script and could not verify the claims. we benchmark a few different approaches here. in fact, results were too noisy to draw a clear result.
one time one approach is faster, then it's the other. probably the manner of measuring is also no good. it's also independent of how many series matched.
suggestions on how to improve the script are welcome (perhaps with real series and a real query) but i deliberately used a simple query as to minimize the effect of the regex matching.

below a few test runs, first with explicit printing of results of each method, later i just print the number of results. and finally the script.

~ ❯❯❯ ./python-test.py                                                                                                                                                      ⏎
bench of original in 0.33136s
[['foklnbyiba49tg4yps7nl39li1xa6n6964fg2n1ljigbo', 60],
 ['fod2dptwjl65utbaz5y9hhla5gef5t32rspl1lxl5yis6', 60],
 ['fo3kv8izt2barx37drhilyq79ug8v2zu8z2m822sxjusx', 60]]
--------------------
--------------------
bench of pr39 in 0.32841s
[('foklnbyiba49tg4yps7nl39li1xa6n6964fg2n1ljigbo', 60),
 ('foklnbyiba49tg4yps7nl39li1xa6n6964fg2n1ljigbo', 60),
 ('fod2dptwjl65utbaz5y9hhla5gef5t32rspl1lxl5yis6', 60),
 ('fod2dptwjl65utbaz5y9hhla5gef5t32rspl1lxl5yis6', 60),
 ('fo3kv8izt2barx37drhilyq79ug8v2zu8z2m822sxjusx', 60),
 ('fo3kv8izt2barx37drhilyq79ug8v2zu8z2m822sxjusx', 60)]
--------------------
--------------------
bench of mixedFn in 0.33337s
[('foklnbyiba49tg4yps7nl39li1xa6n6964fg2n1ljigbo', 60),
 ('fod2dptwjl65utbaz5y9hhla5gef5t32rspl1lxl5yis6', 60),
 ('fo3kv8izt2barx37drhilyq79ug8v2zu8z2m822sxjusx', 60)]
--------------------
--------------------
bench of mixed in 0.32136s
[('foklnbyiba49tg4yps7nl39li1xa6n6964fg2n1ljigbo', 60),
 ('fod2dptwjl65utbaz5y9hhla5gef5t32rspl1lxl5yis6', 60),
 ('fo3kv8izt2barx37drhilyq79ug8v2zu8z2m822sxjusx', 60)]
--------------------
--------------------
~ ❯❯❯ ./python-test.py
bench of original in 0.31945s
[['fo0b0jm8xwpb7wte6axp8sctbasceuudfoulbmbcfba9x', 60]]
--------------------
--------------------
bench of pr39 in 0.31719s
[('fo0b0jm8xwpb7wte6axp8sctbasceuudfoulbmbcfba9x', 60),
 ('fo0b0jm8xwpb7wte6axp8sctbasceuudfoulbmbcfba9x', 60)]
--------------------
--------------------
bench of mixedFn in 0.32163s
[('fo0b0jm8xwpb7wte6axp8sctbasceuudfoulbmbcfba9x', 60)]
--------------------
--------------------
bench of mixed in 0.32973s
[('fo0b0jm8xwpb7wte6axp8sctbasceuudfoulbmbcfba9x', 60)]
--------------------
--------------------
~ ❯❯❯ ./python-test.py
bench of original in 0.32971s
num results: 88
--------------------
--------------------
bench of pr39 in 0.32140s
num results: 176
--------------------
--------------------
bench of mixedFn in 0.31840s
num results: 88
--------------------
--------------------
bench of mixed in 0.33463s
num results: 88
--------------------
--------------------
~ ❯❯❯ ./python-test.py
bench of original in 0.34168s
num results: 83
--------------------
--------------------
bench of pr39 in 0.33666s
num results: 166
--------------------
--------------------
bench of mixedFn in 0.33500s
num results: 83
--------------------
--------------------
bench of mixed in 0.33549s
num results: 83
--------------------
--------------------
~ ❯❯❯ ./python-test.py
bench of original in 0.34352s (results: 91)
bench of pr39 in 0.33575s (results: 182)
bench of mixedFn in 0.34085s (results: 91)
bench of mixed in 0.33506s (results: 91)
bench of original in 0.34312s (results: 91)
bench of pr39 in 0.34076s (results: 182)
bench of mixedFn in 0.33724s (results: 91)
bench of mixed in 0.33398s (results: 91)
bench of original in 0.34319s (results: 91)
bench of pr39 in 0.35466s (results: 182)
bench of mixedFn in 0.33678s (results: 91)
bench of mixed in 0.34007s (results: 91)
bench of original in 0.36299s (results: 91)
bench of pr39 in 0.34341s (results: 182)
bench of mixedFn in 0.33877s (results: 91)
bench of mixed in 0.33573s (results: 91)
bench of original in 0.34222s (results: 91)
bench of pr39 in 0.34859s (results: 182)
bench of mixedFn in 0.34439s (results: 91)
bench of mixed in 0.33657s (results: 91)
#!/usr/bin/env python2
import string
import random
import datetime
# from pprint import pprint
import re


def id_generator(size=45, chars=string.ascii_lowercase + string.digits):
    return ''.join(random.choice(chars) for x in range(size))


schema = [
    ['^high-res-metrics', 10],
    ['', 60],
]

series = [id_generator() for i in range(100000)]
regex = re.compile("^f.*ba")
schemas = [(re.compile(patt), step) for (patt, step) in schema]


def bench(fn, desc):
    now = datetime.datetime.now()
    res = fn()
    end = datetime.datetime.now()

    dt = end - now
    print "bench of %s in %s.%ss (results: %d)" % (desc, dt.seconds, dt.microseconds, len(res))


def orig():
    leaves = []
    for name in series:
        if regex.match(name) is not None:
            res = 60  # fallback default
            for (rule_patt, rule_res) in schemas:
                if rule_patt.match(name):
                    res = rule_res
                    break
            leaves.append([name, res])
    return leaves


def pr39():
    leaves = [(name, (res if pattern.match(name) else 60))
              for name in series
              if regex.match(name)
              for (pattern, res) in schemas
              ]
    return leaves


def mixedFn():
    names = [name for name in series if regex.match(name)]

    def setSchema(name):
        res = 60  # fallback default
        for (rule_patt, rule_res) in schemas:
            if rule_patt.match(name):
                res = rule_res
                break
        return (name, res)
    leaves = map(setSchema, names)
    return leaves


def mixed():
    leaves = [(name, next((res for (patt, res) in schemas if patt.match(name)), 60))
              for name in series if regex.match(name)
              ]
    return leaves


for i in range(5):
    bench(orig, "original")
    bench(pr39, "pr39")
    bench(mixedFn, "mixedFn")
    bench(mixed, "mixed")

InfluxDB 0.13 will be supported?

Hi there,

Is there is any chance that InfluxDB 0.13 will be supported?

I've tested graphite-influxdb with latest brutasse/graphite-api as well as with Dieterbe/graphite-api.
I've got a wrong response (for /metrics/find?query=*) from graphite-api: [{"text": "results", "id": "results", "allowChildren": 0, "expandable": 0, "leaf": 1}

But I have a bunch of properly tagged metrics in InfluxDB...

graphite-api.yaml fragment:

search_index: /srv/graphite/index
finders:
  - graphite_influxdb.InfluxdbFinder
functions:
  - graphite_api.functions.SeriesFunctions
  - graphite_api.functions.PieFunctions
influxdb:
   host: influxdb.dev.mydomain.com
   port: 8086
   user: graphite
   pass: graphite
   db:   metrics
   schema:
     - ['', 60]
     - ['high-res-metrics', 10]
...

Any ideas hot to make it work?

Flask-Cache: CACHE_TYPE is set to null

Using the docker image, it's like it's not respecting the cache config in /etc/graphite-api.yaml.

I've tried a bunch of things, currently looks like:

cache:
# memcache seems to have issues with storing the series. the data is too big and doesn't store it, and doesn't allow bumping size in config that much
#CACHE_TYPE: 'memcached'
#CACHE_KEY_PREFIX: 'graphite_api'
type: 'filesystem'
dir: '/tmp/graphite-api-cache'
#CACHE_TYPE: 'filesystem'
#CACHE_DIR: '/tmp/graphite-api-cache'

root@764a462ddbf4:/etc# cat /var/log/graphite-api.log
{"path": "/etc/graphite-api.yaml", "event": "loading configuration"}
/usr/local/lib/python2.7/dist-packages/flask_cache/init.py:152: UserWarning: Flask-Cache: CACHE_TYPE is set to null, caching is effectively disabled.
warnings.warn("Flask-Cache: CACHE_TYPE is set to null, "
{"index_path": "/srv/graphite/index", "event": "reading index data"}
{"index_path": "/srv/graphite/index", "duration": 5.2928924560546875e-05, "total_entries": 0, "event": "search index reloaded"}
{"path": "/etc/graphite-api.yaml", "event": "loading configuration"}
/usr/local/lib/python2.7/dist-packages/flask_cache/init.py:152: UserWarning: Flask-Cache: CACHE_TYPE is set to null, caching is effectively disabled.
warnings.warn("Flask-Cache: CACHE_TYPE is set to null, "
{"index_path": "/srv/graphite/index", "event": "reading index data"}
{"index_path": "/srv/graphite/index", "duration": 5.412101745605469e-05, "total_entries": 0, "event": "search index reloaded"}

dot in front of metric? + 2 metrics stuck to each other as one

not sure how i did this, i think i requested http://localhost:8000/render/?target=dfvimeodfs1-cpu.cpu10.user

and this happened:

GET /db/graphite/series?q=select+%2A+from+.dfvimeohbasea1.disk.sdc1.disk_octets.readservers.dfvimeotran11.network.em1.tx_bit+limit+1&p=graphite&time_precision=s&chunked=false&u=graphite HTTP/1.1.

HTTP 400 Error at 0:14. syntax error, unexpected $undefined, expecting TABLE_NAME or SIMPLE_NAME or REGEX_STRING or INSENSITIVE_REGEX_STRING

Whisper to influxdb migration and configuration tools?

Hi.

We are working now on a big graphite platform but we have plans to grow a lot the number of systems /products sending metrics in next months / years and we need something more scalable and also as flexible as whisper is.

We are now testing graphite-influxdb and it seems to be working with a single graphite-web frontend and a influxdb node as data backend.

We are interesting now in investigate :

a) how to migrate our current whisper data to influxdb. Are there any whisper2influx.sh tool ?

b) how to configure influxdb to get the N different fixed-size database (retentions) each one with different resolutions as whisper does, and how to configure xFilesFactor and aggregationMethod.?

This last point is important because we need higher resolutions (1 metric/minute) last weeks but also we need at least 3 years of data history. We expect about 10/20 million metrics in next months/years, I will be very grateful if we can configure a limited fixed-size data per metric. It will let us to save storage size.

AttributeError: 'NoneType' object has no attribute 'get'

I'm getting 500 error with this message:

AttributeError: 'NoneType' object has no attribute 'get'

And this stacktrace:

Stacktrace (most recent call last):

  File "flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "graphite_api/app.py", line 143, in metrics_find
    key=lambda node: node.name
  File "graphite_api/storage.py", line 22, in find
    for node in finder.find_nodes(query):
  File "site-packages/graphite_influxdb.py", line 323, in find_nodes
    for (name, res) in self.get_leaves(query):
  File "site-packages/graphite_influxdb.py", line 275, in get_leaves
    data = self.cache.get(key_leaves)

Any idea what could be wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.