beezz / ddtrace-graphql

Python library for Datadog tracing of graphql calls.
MIT License
35 stars 19 forks source link

Use with Graphene #81

Closed matt-dalton closed 5 years ago

matt-dalton commented 5 years ago

Is it possible to use this library with Graphene?

I tried using the patch function at my Django entrypoint as suggested in the docs, but the service never appeared. Is this likely to be because I am using Graphene?

My code in my wsgi.py entrypoint file is as follows:

    from ddtrace import tracer, patch_all
    from ddtrace_graphql import patch as patch_graphql

    # Connect the APM to the agent
    try:
        tracer.configure(
            hostname=os.environ['DD_AGENT_HOST']
        )
    except Exception as e:
        print('Failed to register datadog tracing host', e)

    # Activate the APM
    patch_all()

    # Support frameworks
    patch_all(botocore=True, boto=True, kombu=True, celery=True)
    patch_graphql()
beezz commented 5 years ago

Hi @matt-dalton!

Yes, this works with graphene as the application for which this was created was using graphene (with pyramid and not django but that should not matter).

Can you past the whole wsgi.py? Other services are patched as expected?

matt-dalton commented 5 years ago

Interesting. Yeah I've had the other services running happily on their own for a week. Then tried to add GraphQL, but can't see anything in datadog.

My entire wsgi.py is as follow:

from ddtrace import tracer, patch_all
from django.core.wsgi import get_wsgi_application
from django.conf import settings
import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "finimize_django.settings.none")

if not settings.DEBUG:
    from ddtrace_graphql import patch as patch_graphql

    # Connect the APM to the agent
    try:
        tracer.configure(
            hostname=os.environ['DD_AGENT_HOST']
        )
    except Exception as e:
        print('Failed to register datadog tracing host', e)

    # Activate the APM
    patch_all()

    # Support frameworks
    patch_all(botocore=True, boto=True, kombu=True, celery=True)
    patch_graphql()

if settings.DEBUG or os.environ['AWS_ENV'] == 'www':
    application = get_wsgi_application()

Anything I can do to debug? Thanks for the help!

beezz commented 5 years ago

I just tried it myself with this minimal example and works just fine.

import logging

logging.basicConfig(level=logging.DEBUG)
from ddtrace_graphql import patch

patch()

import graphene

class Query(graphene.ObjectType):
    hello = graphene.String(description="A typical hello world")

    def resolve_hello(self, info):
        return "World"

schema = graphene.Schema(query=Query)

query = """
    query SayHello {
      hello
    }
"""
result = schema.execute(query)

print(result)

You can set the ddtrace_graphql.patch logger to debug and see in logs that the patching actually takes place.

DEBUG:ddtrace_graphql.patch:Patching `graphql.graphql` function.

Could it be that you have in settings something that imports from the graphene? Can you try to do the patching before any other imports (logging is fine)?

matt-dalton commented 5 years ago

Hmm strange. I tried patching in the file (schema.py) where I declare my Query/Schema as you did (in the right order), and it still doesn't work.

The only parts of my settings referring to Graphene are in INSTALLED_APPS and :

GRAPHENE = {
    'SCHEMA': 'finimize_django.graphql.schema.schema'
}

How do I set the ddtrace_graphql.patch logger?

beezz commented 5 years ago

For the logging please check Django docs here ~ https://docs.djangoproject.com/en/2.2/topics/logging/

Can you please try to run the minimal example few times to see if the service appear in datadog?

matt-dalton commented 5 years ago

I asked tech support about this, and their hunch (by reading the source code) was that this lib is not configured to post traces to whatever the DD_AGENT_HOST is, and defaults back to localhost. Does this sound correct? This would work in lots of cases, but I am running this in a containerised Kubernetes environment.

If there was a configure call so you could run something like the statement in my wsgi file above: tracer_graphql.configure(hostname=os.environ['DD_AGENT_HOST'])

Does this sound plausible? I'm passing on information here from someone more knowledgeable than me!

beezz commented 5 years ago

That's not right. By default it uses the global tracer (https://github.com/beezz/ddtrace-graphql/blob/master/ddtrace_graphql/base.py#L49) which you configured yourself in the wsgi file.

matt-dalton commented 5 years ago

OK - sorry for sidetracking.

Tried your minimal example, and it still doesn't show up in the Service List. I am getting the result logged out: <graphql.execution.base.ExecutionResult object at 0x7fc33c157bd0> so I know that code is run.

Are there any other dependencies that could affect it? I am running Django in a Kubernetes pod with these versions:

ddtrace==0.24.0
ddtrace_graphql==0.1.3
graphene==2.1.3
graphene-django==2.2.0
graphql-core==2.1.0
graphql-relay==0.4.5
beezz commented 5 years ago

In the dependency list I see nothing that should be a problem.

brianmcfeeley commented 5 years ago

Hi @beezz! Thank you so much for your work on this library.

I'm currently working to get this working with a flask/graphene stack myself right now, and I was hoping for some insight.

For starters, some context:

Relevant versions in requirements.txt

ddtrace==0.24.0
ddtrace_graphql==0.1.3

Here's a snippet from my docker-compose.yml for starting up:

  dispatch-flask:
    build:
      context: .
      dockerfile: ./containers/dev/flask/Dockerfile
    environment:
      FLASK_APP: ./dispatch/run.py
      POSTGRESQL_URL: postgres://${USER}@postgres/db
      CELERY_BROKER_URL: amqp://dispatch-mq:5672/
      DATADOG_TRACE_AGENT_HOSTNAME: <snip>
      DD_TRACE_AGENT_PORT: 8126
      DD_FLASK_ANALYTICS_ENABLED: "True"
      DATADOG_ENV: foo
      DATADOG_SERVICE_NAME: bar
      DATADOG_TRACE_DEBUG: "True"
      DDTRACE_GRAPHQL_SERVICE: baz
    entrypoint: ddtrace-run flask run --host=0.0.0.0 --port 5061
    depends_on:
      - dispatch-celery-worker
      - dispatch-celery-beat
    ports:
      - "5464:5464"
      - "5061:5061"
    expose:
      - "5061"
    volumes:
      - .:/app:cached
    links:
      - postgres
    env_file:
      - ./.secrets.env
      - ./dev.env

And in my run.py, the first two lines are:

from ddtrace_graphql import patch as patch_graphql
patch_graphql()

Now, the good: I do indeed see in the debug logs that we're patching the graphql function.

2019-05-31 20:53:08,504 DEBUG [ddtrace_graphql.patch] [patch.py:23] - Patching `graphql.graphql` function.

Another good: I'm seeing services populating in datadog for this environment.

The bad: I'm only seeing the main flask service and postgres.

I'm definitely triggering some graphQL queries, heres some stuff from the ddtrace debug logs on the flask side of things:

{"total_sql_query_duration": "0.04407s", "num_sql_queries": 30, "timestamp": "Fri May 31 20:57:00 2019", "method": "POST", "url": "http://localhost:5060/graphql/batch", "response": "200 OK", "request_duration": "0.48941s", "exception_info": null, "event": "Processed request"}
2019-05-31 20:57:00,672 DEBUG [ddtrace.tracer] [tracer.py:425] - writing 46 spans (enabled:True), 3 additional messages skipped
2019-05-31 20:57:00,672 DEBUG [ddtrace.tracer] [tracer.py:427] -
      name flask.request
        id 17634919309703984119
  trace_id 14887211035167629387
 parent_id None
   service dispatch.web
  resource POST /graphql/batch
      type http
     start 1559336220.1326494
       end 1559336220.6721995
  duration 0.539550s
     error 0
      tags
           env:spark-local
           flask.endpoint:graphql-batch
           flask.url_rule:/graphql/batch
           flask.version:0.12.4
           http.method:POST
           http.status_code:200
           http.url:/graphql/batch
           system.pid:12, 138 additional messages skipped

In spite of this, I'm not seeing a discrete graphql service in datadog. Do you have any ideas how I might troubleshoot further?

beezz commented 5 years ago

Hi @brianmcfeeley ,

Can you please try the minimal example here ~ https://github.com/beezz/ddtrace-graphql/issues/81#issuecomment-492815444

When you run the minimal example few times you should see in the logs of the trace agent something like:

2019-06-02 01:03:21 CEST | TRACE | INFO | (pkg/trace/agent/service.go:63 in Run) | total number of tracked services: 1
2019-06-02 01:04:01 CEST | TRACE | INFO | (pkg/trace/api/api.go:342 in logStats) | [lang:python lang_version:3.7.2 interpreter:CPython tracer_version:0.25.0] -> traces received: 1, traces dropped: 0, traces filtered: 0, traces amount: 297 bytes,services received: 0, services amount: 0 bytes, events extracted: 0, events sampled: 0

I just tried it now myself again to make sure it works. It took some time for the service to appear in the UI. For few minutes I saw the traces only in the traces list UI.

brianmcfeeley commented 5 years ago

Hi @beezz ,

Thanks for getting back to me -- I was indeed able to get the minimal example working, first in the trace list UI and then in the services view.

I'm thinking there may be some weirdness about how we're specifically using graphene, so I will try to incrementally build up from the minimal example into something more resembling a smaller-scale version of our flask app and see how far I get.

beezz commented 5 years ago

@brianmcfeeley I will close this issue now but feel free to open it again if you find out that it's library problem.

brianmcfeeley commented 5 years ago

Hey @beezz , I'm not convinced this needs to be reopened at the moment, but you may appreciate a little more context on my situation as I've dug a bit deeper.

Turns out we're actually using flask_graphql to generate our view functions for routing in flask. As best I can tell, under the hood this library is not using the graphql.graphql function from core, so the monkey patch is working 100% as intended but it's not the code path I need instrumented for my purposes.

I see a few different options for myself:

If I get a successful P.O.C for one of the first two options, I'll see if I can fork your project and contribute back a monkeypatch for flask_graphql users.

Please holler at me if you have any questions or ideas on the subject!

beezz commented 5 years ago

Hey @brianmcfeeley ,

thanks for additional context. Now that makes all sense :)

I checked out the flask_graphql package, it uses the graphql-server-core package and that one is using the execute_and_validate function from the graphql-core.

So I believe the easiest way to support all the integrations as listed on the grapqhl-server-core page is to instrument the execute_and_validate function.

beezz commented 5 years ago

Hi @brianmcfeeley,

to support also the graphql-server-core seems to be fairly simple. Please check out the #83 , with this simple changes to the library I was able to get the tracing for flask_graphql.

Please check it out if it's something that will work for you :)

brianmcfeeley commented 5 years ago

Hey @beezz ! Thanks for the update -- I was OOO for the weekend. What a nice way to start the week! I verified that it's working when building the library from the branch in #83 and i'm able to see both traces in the list as well as services popping up in the APM overviews.

I'm glad it was a simple extension, I hoped it would be after doing some digging!

matt-dalton commented 5 years ago

just a note on this....the new release (0.2.0) seems to have fixed my issue as well. Thanks so much guys!