Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support GraphQL #850

Merged
merged 31 commits into from
Jun 17, 2020
Merged

Support GraphQL #850

merged 31 commits into from
Jun 17, 2020

Conversation

RyanKung
Copy link
Contributor

@RyanKung RyanKung commented Jun 3, 2020

What does this pull request do?

Support GraphQL

And I'm not sure what span_type it should be.

Related issues

closes #ISSUE

@cla-checker-service
Copy link

cla-checker-service bot commented Jun 3, 2020

💚 CLA has been signed

if "ResolveInfo" == type(query).__name__:
op = query.operation.operation
field = query.field_name
path = ">>".join(query.path)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local variable 'path' is assigned to but never used

@apmmachine
Copy link
Contributor

apmmachine commented Jun 3, 2020

❕ Build Aborted

The PR is not allowed to run in the CI yet

Pipeline View Test View Changes Artifacts

Expand to view the summary

Build stats

  • Build Cause: [Pull request #850 updated]

  • Reason: The PR is not allowed to run in the CI yet

  • Start Time: 2020-06-08T18:34:36.875+0000

  • Duration: 3 min 3 sec

  • Commit: 125a3f0

Steps errors

Expand to view the steps failures

  • Name: Error signal
    • Description: githubPrCheckApproved: The PR is not allowed to run in the CI yet. (Only users with write permission

    • Duration: 0 min 0 sec

    • Start Time: 2020-06-08T18:37:37.260+0000

    • log

Log output

Expand to view the last 100 lines of log output

[2020-06-08T18:37:13.152Z] No valid HEAD. Skipping the resetting
[2020-06-08T18:37:13.152Z]  > git clean -fdx # timeout=10
[2020-06-08T18:37:13.171Z] Fetching upstream changes from git@github.com:elastic/apm-agent-python.git
[2020-06-08T18:37:13.172Z] using GIT_SSH to set credentials GitHub user @elasticmachine SSH key
[2020-06-08T18:37:13.177Z]  > git fetch --no-tags --progress --prune -- git@github.com:elastic/apm-agent-python.git +refs/pull/850/head:refs/remotes/origin/PR-850 +refs/heads/master:refs/remotes/origin/master # timeout=15
[2020-06-08T18:37:13.911Z]  > git config core.sparsecheckout # timeout=10
[2020-06-08T18:37:13.916Z]  > git checkout -f 125a3f0001011f07e74f879967880ef5dbf06130 # timeout=15
[2020-06-08T18:37:13.997Z]  > git remote # timeout=10
[2020-06-08T18:37:14.012Z]  > git config --get remote.origin.url # timeout=10
[2020-06-08T18:37:14.022Z] using GIT_SSH to set credentials GitHub user @elasticmachine SSH key
[2020-06-08T18:37:14.027Z]  > git merge 321a3445ee59e1660050b8fdd1b612ee45eb636b # timeout=10
[2020-06-08T18:37:14.044Z]  > git rev-parse HEAD^{commit} # timeout=10
[2020-06-08T18:37:14.055Z]  > git config core.sparsecheckout # timeout=10
[2020-06-08T18:37:14.068Z]  > git checkout -f 125a3f0001011f07e74f879967880ef5dbf06130 # timeout=15
[2020-06-08T18:37:17.773Z] Commit message: "Merge branch 'master' into master"
[2020-06-08T18:37:17.785Z] First time build. Skipping changelog.
[2020-06-08T18:37:17.785Z] Cleaning workspace
[2020-06-08T18:37:17.777Z]  > git rev-list --no-walk f85fcc38737b1cba0a00541fdc99324744dd152a # timeout=10
[2020-06-08T18:37:17.787Z]  > git rev-parse --verify HEAD # timeout=10
[2020-06-08T18:37:17.793Z] Resetting working tree
[2020-06-08T18:37:17.793Z]  > git reset --hard # timeout=10
[2020-06-08T18:37:17.804Z]  > git clean -fdx # timeout=10
[2020-06-08T18:37:18.469Z] Masking supported pattern matches of $JOB_GCS_BUCKET or $NOTIFY_TO
[2020-06-08T18:37:18.511Z] Timeout set to expire in 1 hr 0 min
[2020-06-08T18:37:18.523Z] The timestamps step is unnecessary when timestamps are enabled for all Pipeline builds.
[2020-06-08T18:37:18.719Z] [INFO] Number of builds to be searched 10
[2020-06-08T18:37:18.932Z] [INFO] 'shallow' is forced to be disabled when running on PullRequests
[2020-06-08T18:37:18.961Z] Running in /var/lib/jenkins/workspace/thon_apm-agent-python-mbp_PR-850/src/github.com/elastic/apm-agent-python
[2020-06-08T18:37:18.974Z] [INFO] gitCheckout: Checkout SCM PR-850 with default customisation from the Item.
[2020-06-08T18:37:18.991Z] [INFO] Override default checkout
[2020-06-08T18:37:19.015Z] Sleeping for 10 sec
[2020-06-08T18:37:29.351Z] using credential f6c7695a-671e-4f4f-a331-acdce44ff9ba
[2020-06-08T18:37:29.381Z] Wiping out workspace first.
[2020-06-08T18:37:29.393Z] Cloning the remote Git repository
[2020-06-08T18:37:29.394Z] Using shallow clone with depth 3
[2020-06-08T18:37:29.394Z] Avoid fetching tags
[2020-06-08T18:37:29.411Z] Cloning repository git@github.com:elastic/apm-agent-python.git
[2020-06-08T18:37:29.444Z]  > git init /var/lib/jenkins/workspace/thon_apm-agent-python-mbp_PR-850/src/github.com/elastic/apm-agent-python # timeout=10
[2020-06-08T18:37:29.459Z] Fetching upstream changes from git@github.com:elastic/apm-agent-python.git
[2020-06-08T18:37:29.459Z]  > git --version # timeout=10
[2020-06-08T18:37:29.472Z] using GIT_SSH to set credentials GitHub user @elasticmachine SSH key
[2020-06-08T18:37:29.479Z]  > git fetch --no-tags --progress -- git@github.com:elastic/apm-agent-python.git +refs/heads/*:refs/remotes/origin/* # timeout=15
[2020-06-08T18:37:30.703Z] Cleaning workspace
[2020-06-08T18:37:30.719Z] Using shallow fetch with depth 3
[2020-06-08T18:37:30.719Z] Pruning obsolete local branches
[2020-06-08T18:37:30.680Z]  > git config remote.origin.url git@github.com:elastic/apm-agent-python.git # timeout=10
[2020-06-08T18:37:30.688Z]  > git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
[2020-06-08T18:37:30.698Z]  > git config remote.origin.url git@github.com:elastic/apm-agent-python.git # timeout=10
[2020-06-08T18:37:30.707Z]  > git rev-parse --verify HEAD # timeout=10
[2020-06-08T18:37:30.711Z] No valid HEAD. Skipping the resetting
[2020-06-08T18:37:30.712Z]  > git clean -fdx # timeout=10
[2020-06-08T18:37:30.723Z] Fetching upstream changes from git@github.com:elastic/apm-agent-python.git
[2020-06-08T18:37:30.723Z] using GIT_SSH to set credentials GitHub user @elasticmachine SSH key
[2020-06-08T18:37:30.731Z]  > git fetch --no-tags --progress --prune -- git@github.com:elastic/apm-agent-python.git +refs/pull/850/head:refs/remotes/origin/PR-850 +refs/heads/master:refs/remotes/origin/master # timeout=15
[2020-06-08T18:37:31.410Z] Merging remotes/origin/master commit 321a3445ee59e1660050b8fdd1b612ee45eb636b into PR head commit 125a3f0001011f07e74f879967880ef5dbf06130
[2020-06-08T18:37:31.522Z] Merge succeeded, producing 125a3f0001011f07e74f879967880ef5dbf06130
[2020-06-08T18:37:31.522Z] Checking out Revision 125a3f0001011f07e74f879967880ef5dbf06130 (PR-850)
[2020-06-08T18:37:31.581Z] Commit message: "Merge branch 'master' into master"
[2020-06-08T18:37:31.581Z] Cleaning workspace
[2020-06-08T18:37:32.259Z] Masking supported pattern matches of $GIT_USERNAME or $GIT_PASSWORD
[2020-06-08T18:37:31.414Z]  > git config core.sparsecheckout # timeout=10
[2020-06-08T18:37:31.418Z]  > git checkout -f 125a3f0001011f07e74f879967880ef5dbf06130 # timeout=15
[2020-06-08T18:37:31.478Z]  > git remote # timeout=10
[2020-06-08T18:37:31.487Z]  > git config --get remote.origin.url # timeout=10
[2020-06-08T18:37:31.494Z] using GIT_SSH to set credentials GitHub user @elasticmachine SSH key
[2020-06-08T18:37:31.498Z]  > git merge 321a3445ee59e1660050b8fdd1b612ee45eb636b # timeout=10
[2020-06-08T18:37:31.512Z]  > git rev-parse HEAD^{commit} # timeout=10
[2020-06-08T18:37:31.527Z]  > git config core.sparsecheckout # timeout=10
[2020-06-08T18:37:31.536Z]  > git checkout -f 125a3f0001011f07e74f879967880ef5dbf06130 # timeout=15
[2020-06-08T18:37:31.584Z]  > git rev-parse --verify HEAD # timeout=10
[2020-06-08T18:37:31.588Z] Resetting working tree
[2020-06-08T18:37:31.589Z]  > git reset --hard # timeout=10
[2020-06-08T18:37:31.621Z]  > git clean -fdx # timeout=10
[2020-06-08T18:37:32.934Z] + git fetch https://****:****@github.com/elastic/apm-agent-python.git +refs/pull/*/head:refs/remotes/origin/pr/*
[2020-06-08T18:37:34.387Z] Archiving artifacts
[2020-06-08T18:37:35.161Z] + git rev-parse HEAD
[2020-06-08T18:37:35.521Z] + git rev-parse HEAD
[2020-06-08T18:37:35.834Z] + git rev-parse origin/pr/850
[2020-06-08T18:37:35.879Z] [INFO] githubEnv: Found Git Build Cause: pr
[2020-06-08T18:37:36.150Z] Masking supported pattern matches of $GITHUB_TOKEN
[2020-06-08T18:37:37.060Z] [INFO] githubPrCheckApproved: Title: Support GraphQL - User: RyanKung - Author Association: FIRST_TIME_CONTRIBUTOR
[2020-06-08T18:37:37.262Z] ERROR: githubPrCheckApproved: The PR is not allowed to run in the CI yet
[2020-06-08T18:37:37.262Z] ERROR: githubPrCheckApproved: The PR is not allowed to run in the CI yet. (Only users with write permissions can do so.)
[2020-06-08T18:37:37.288Z] [INFO] Let's stop build #24. The PR is not allowed to run in the CI yet
[2020-06-08T18:37:37.300Z] Sleeping for 5 sec
[2020-06-08T18:37:38.360Z] Stage "Sanity checks" skipped due to earlier failure(s)
[2020-06-08T18:37:38.424Z] Stage "Test" skipped due to earlier failure(s)
[2020-06-08T18:37:38.456Z] Stage "Building packages" skipped due to earlier failure(s)
[2020-06-08T18:37:38.486Z] Stage "Integration Tests" skipped due to earlier failure(s)
[2020-06-08T18:37:38.516Z] Stage "Benchmarks" skipped due to earlier failure(s)
[2020-06-08T18:37:38.545Z] Stage "Prepare Release" skipped due to earlier failure(s)
[2020-06-08T18:37:38.559Z] Stage "Prepare Release" skipped due to earlier failure(s)
[2020-06-08T18:37:38.590Z] Stage "Prepare Release" skipped due to earlier failure(s)
[2020-06-08T18:37:38.623Z] Stage "Prepare Release" skipped due to earlier failure(s)
[2020-06-08T18:37:39.023Z] Running on Jenkins in /var/lib/jenkins/workspace/thon_apm-agent-python-mbp_PR-850
[2020-06-08T18:37:39.113Z] [INFO] getVaultSecret: Getting secrets
[2020-06-08T18:37:39.170Z] Masking supported pattern matches of $VAULT_ADDR or $VAULT_ROLE_ID or $VAULT_SECRET_ID
[2020-06-08T18:37:39.746Z] + chmod 755 generate-build-data.sh
[2020-06-08T18:37:39.747Z] + ./generate-build-data.sh https://apm-ci.elastic.co/blue/rest/organizations/jenkins/pipelines/apm-agent-python/apm-agent-python-mbp/PR-850/ https://apm-ci.elastic.co/blue/rest/organizations/jenkins/pipelines/apm-agent-python/apm-agent-python-mbp/PR-850/runs/24 ABORTED 182612
[2020-06-08T18:37:39.997Z] INFO: curl https://apm-ci.elastic.co/blue/rest/organizations/jenkins/pipelines/apm-agent-python/apm-agent-python-mbp/PR-850/runs/24/steps/?limit=10000 -o steps-info.json

@RyanKung
Copy link
Contributor Author

RyanKung commented Jun 3, 2020

Just signed Contributor Agreement

@beniwohli
Copy link
Contributor

Hi @RyanKung

this is awesome, thank you very much! We do have some planning work done for GraphQL, but this mostly pertains to the server side. You can find that here: https://github.com/elastic/apm/blob/master/docs/graphql.md. Maybe some of it could be relevant for the client side too.

As for the span type/subtype/action, I'd personally go with external/graphql/query. There is some prior art in the Node.js agent, where they went with db/graphql/execute, though.

To be honest, I'm not super familiar with GraphQL, so I'll have to read up and play around a bit with it before I can give you a proper review. This is probably going to take a few days, sorry about that!

@beniwohli
Copy link
Contributor

beniwohli commented Jun 4, 2020

Regarding CLA, it still fails because you used a different email address for signing the CLA than what you use for committing. Could you either sign the CLA again with the email address you used for committing, or amend the commits with the email address you signed the CLA with? Sorry about that!

Turns out there was an issue with uppercasing/lowercasing in our CLA check. It's fixed now!

Sorry about this, we really need to document how to add testing
for a new instrumentation, as it involves quite a few files.
@RyanKung
Copy link
Contributor Author

RyanKung commented Jun 4, 2020

Hi @RyanKung

this is awesome, thank you very much! We do have some planning work done for GraphQL, but this mostly pertains to the server side. You can find that here: https://github.com/elastic/apm/blob/master/docs/graphql.md. Maybe some of it could be relevant for the client side too.

As for the span type/subtype/action, I'd personally go with external/graphql/query. There is some prior art in the Node.js agent, where they went with db/graphql/execute, though.

To be honest, I'm not super familiar with GraphQL, so I'll have to read up and play around a bit with it before I can give you a proper review. This is probably going to take a few days, sorry about that!

Thanks for response, this PR is also for server side. And I will try to refine this PR according to the document. But do we really needs to show such detail informations like lex, parse, validate? Maybe just execute is good enough?

from elasticapm.instrumentation.packages.base import AbstractInstrumentedModule
from elasticapm.traces import capture_span

class GrapheneInstrumentation(AbstractInstrumentedModule):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@beniwohli
Copy link
Contributor

beniwohli commented Jun 4, 2020

@RyanKung awesome, your server side transaction naming approach is really neat!

In case you missed it, I opened a PR on your fork that adds some more necessary boilerplate to run the tests on our Jenkins CI: RyanKung#1

Agreed that execute should be enough for now. My hunch is that the lexer/parser is fast enough to not be worth the overhead of instrumenting it.

@RyanKung
Copy link
Contributor Author

RyanKung commented Jun 5, 2020

@beniwohli Thanks & Merged, According to the document, the TX name should be changed when getting a GraphQL request. So I have to modify those framework middlewares. Here is what I'm working on now. It may cost few days.

Support setup TX name when content-type = application/graphgl

  • Support Django middleware
  • Support Flask
  • Support aioHttp

Unittest for framework middlewares

  • Django
  • Flask
  • aioHttp

@beniwohli
Copy link
Contributor

beniwohli commented Jun 5, 2020

@RyanKung I wonder if instead of having to add support for all frameworks, we could hook into a deeper part of the GraphQL core library. Having played around with the debugger a bit. The document_from_string methods of the different backends seem to be a good candidate. We could e.g. write an instrumentation like this (get_graphql_tx_name would need to be modified to take a document instead of the unparsed document string)

import elasticapm
from elasticapm.instrumentation.packages.base import AbstractInstrumentedModule
from elasticapm.utils.graphql import get_graphql_tx_name


class GraphQLInstrumentation(AbstractInstrumentedModule):
    name = "graphql"

    instrument_list = [
        ("graphql.backend.core", "GraphQLCoreBackend.document_from_string"),
        ("graphql.backend.cache", "GraphQLCachedBackend.document_from_string"),
    ]

    def call(self, module, method, wrapped, instance, args, kwargs):
        graphql_document = wrapped(*args, **kwargs)
        transaction_name = get_graphql_tx_name(graphql_document.document_ast)
        elasticapm.set_transaction_name(transaction_name)
        return graphql_document

Another benefit of this would be that we don't depend on the content type to be application/graphql. Having tested both GraphiQL and the Python gql package, they both default to application/json from what I can tell.

Something similar would need to be done for the new graphql-core package, maybe here? https://github.com/graphql-python/graphql-core/blob/master/src/graphql/execution/execute.py#L245

rule += " GraphQL %s" % get_graphql_tx_name(query, op)
if request.method == "POST":
rule += " GraphQL %s" % get_graphql_tx_name(request.data.decode())
assert False

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not call assert False since python -O removes these calls. Instead callers should raise AssertionError().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@RyanKung
Copy link
Contributor Author

RyanKung commented Jun 5, 2020

@beniwohli Wow, change TX name in hooks is simpler than modify all framework support. I'll try it, Thanks. Maybe I should create a new PR for clear?

@RyanKung
Copy link
Contributor Author

RyanKung commented Jun 8, 2020

@beniwohli For now this PR is only support graphene2&graphql-core2.

I tried to support graphql-core3, but got some wired behavior when adding more than two methods of graphql.execution.executor.ExecutionContext to instrument_list such as:

class GraphQLExecutorInstrumentation(AbstractInstrumentedModule):
    name = "graphql"

    Instrument_list_2 = [
      ...
    ]

    instrument_list_3 = [
        # For graphql-core 3
        ("graphql.execution.execute", "ExecutionContext.execute_operation"),
        ("graphql.execution.execute", "ExecutionContext.execute_fields"),
    ]

    instrument_list = instrument_list_2 + instrument_list_3


    def call_graphql_2(self, module, method, wrapped, instance, args, kwargs):
       ...

    def call_graphql_3(self, module, method, wrapped, instance, args, kwargs):
        name = "GraphQL"
        info = ""

        if method == "ExecutionContext.execute_operation":
            print(method)
        if method == "ExecutionContext.execute_fields":
            print(method)

        with capture_span(
                "%s.%s" % (name, info),
                span_type="external",
                span_subtype="graphql",
                span_action="query"
        ):
            return wrapped(*args, **kwargs)

    def call(self, module, method, wrapped, instance, args, kwargs):
        if method in dict(self.instrument_list_2).values():
            return self.call_graphql_2(module, method, wrapped, instance, args, kwargs)
        if method in dict(self.instrument_list_3).values():
            return self.call_graphql_3(module, method, wrapped, instance, args, kwargs)

Only one of those method will be executed, and the whole result will be None on unittest:

@pytest.mark.integrationtest
def test_fetch_data(instrument, elasticapm_client):
    query_string = "{succ{yeah},err{__typename}}"

    schema = graphene.Schema(query=Query)

    elasticapm_client.begin_transaction("transaction.test")
    with capture_span("test_graphene", "test"):
        result = schema.execute(query_string)
        assert result.data == {"succ": {"yeah": "hello world"}, "err": {"__typename": "Error"}}
E           AssertionError: assert None == {'err': {'__typename': 'Error'}, 'succ': {'yeah': 'hello world'}}
E             +None
E             -{'succ': {'yeah': 'hello world'}, 'err': {'__typename': 'Error'}}

@RyanKung
Copy link
Contributor Author

Hi, @beniwohli

I think graphene3 is in beta stage, so maybe we can only support 2.0 version for now. Graphene3&graph-core3 supporting can be another pull request.

@beniwohli
Copy link
Contributor

Hey @RyanKung. Thanks again for all the work you are putting into this, it's shaping up to be a great addition to the agent! I agree that Graphene 3 support can be tackled later on.

I did a quick test by adapting two of our test apps, opbeans-python (a Django app, acting as the GraphQL server) and opbeans-flask (a Flask app, acting as a GraphQL client). The waterfall looks a bit noisy to me, however:

I wonder if we could either

  • only capture top level graphql executions (the GraphQL QUERY allProducts in this case)
  • or not capture executions that take very little time. Capturing spans does have some overhead, and if the operation itself is only fractions of a millisecond, we're adding an undue percentage of overhead.

@apmmachine
Copy link
Contributor

apmmachine commented Jun 10, 2020

💚 Build Succeeded

Pipeline View Test View Changes Artifacts preview

Expand to view the summary

Build stats

  • Build Cause: [Pull request #850 updated]

  • Start Time: 2020-06-17T15:31:09.998+0000

  • Duration: 32 min 53 sec

Test stats 🧪

Test Results
Failed 0
Passed 9291
Skipped 7233
Total 16524

@RyanKung
Copy link
Contributor Author

Hi @beniwohli

Thanks for reply.

* only capture top level graphql executions (the `GraphQL QUERY allProducts` in this case)

GraphQL query may contains complex/composed queries. A execution may cross a lot of Objects, so I think only top level is not enough for showing complex details.

* or not capture executions that take very little time. Capturing spans does have some overhead, and if the operation itself is only fractions of a millisecond, we're adding an undue percentage of overhead.

I added a list of basic type, such as int, str or float (https://github.com/elastic/apm-agent-python/pull/850/files#diff-a0bf214d1c9543ef09f978bf6e29eda7R55).

It may avoid capture executions that take very little time. How do you think about it?

@jamesthomasdavidson
Copy link

Is there anything I can do to contribute towards this? We are going to move our GraphQL API out of develop and into production in a few weeks, and having native APM support would be invaluable.

Copy link
Contributor

@beniwohli beniwohli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work on this @RyanKung! I'm OK with merging this as is.

Copy link
Contributor

@basepi basepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. Just one nitpick.

tests/requirements/reqs-graphene-2.txt Outdated Show resolved Hide resolved
@basepi basepi merged commit 5b54ed1 into elastic:master Jun 17, 2020
@beniwohli
Copy link
Contributor

@jamesthomasdavidson if you have the time, it would be great if you could give the current master branch a try and see if it fulfills your needs :)

]

def get_graphql_tx_name(self, graphql_doc):
op = graphql_doc.definitions[0].operation
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a bug here - the first item in the definition is not necessarily an operation.
It can be a fragment in which case you'll get an exception here.

@RyanKung

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(in fact, client libraries like Apollo send fragments first and operation last so this will always fail. Its best to iterate the list and find the operation then assume its first\last)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ekampf thanks for the heads up! Would you mind opening a new issue for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ekampf Maybe like this? Although I'm not sure how to test that....

    def get_graphql_tx_name(self, graphql_doc):
        op_def = [
            i for i in graphql_doc.definitions
            if type(i).__name__=="OperationDefinition"
        ][0]
        op = op_def.operation
        fields = op_def.selection_set.selections
        return "GraphQL %s %s" % (op.upper(), "+".join([f.name.value for f in fields]))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ekampf related PR here: #881

romulorosa pushed a commit to romulorosa/apm-agent-python that referenced this pull request Oct 15, 2020
* support graphene

* granphene

* unittest

* added graphene to test requirement

* rm unused variable

* support more executor

* rm unused import

* add missing test boilerplate

Sorry about this, we really need to document how to add testing
for a new instrumentation, as it involves quite a few files.

* support set tx name on flask and django

* add empty lines

* graphql

* rm assert

* unittest for django

* revert, dont set tx name in middleware

* updated graphql support

* rename graphene to graphql

* rm imports

* bugfixed

* rm blank line

* added missing unittest

* rm blank line

* setup name

* fixed unittest

* ignore basic type

* fixed test requirement

* Update changelog

Co-authored-by: Benjamin Wohlwend <beni@elastic.co>
Co-authored-by: Colton Myers <colton.myers@gmail.com>
romulorosa pushed a commit to romulorosa/apm-agent-python that referenced this pull request Oct 15, 2020
* support graphene

* granphene

* unittest

* added graphene to test requirement

* rm unused variable

* support more executor

* rm unused import

* add missing test boilerplate

Sorry about this, we really need to document how to add testing
for a new instrumentation, as it involves quite a few files.

* support set tx name on flask and django

* add empty lines

* graphql

* rm assert

* unittest for django

* revert, dont set tx name in middleware

* updated graphql support

* rename graphene to graphql

* rm imports

* bugfixed

* rm blank line

* added missing unittest

* rm blank line

* setup name

* fixed unittest

* ignore basic type

* fixed test requirement

* Update changelog

Co-authored-by: Benjamin Wohlwend <beni@elastic.co>
Co-authored-by: Colton Myers <colton.myers@gmail.com>
beniwohli added a commit to beniwohli/apm-agent-python that referenced this pull request Sep 14, 2021
* support graphene

* granphene

* unittest

* added graphene to test requirement

* rm unused variable

* support more executor

* rm unused import

* add missing test boilerplate

Sorry about this, we really need to document how to add testing
for a new instrumentation, as it involves quite a few files.

* support set tx name on flask and django

* add empty lines

* graphql

* rm assert

* unittest for django

* revert, dont set tx name in middleware

* updated graphql support

* rename graphene to graphql

* rm imports

* bugfixed

* rm blank line

* added missing unittest

* rm blank line

* setup name

* fixed unittest

* ignore basic type

* fixed test requirement

* Update changelog

Co-authored-by: Benjamin Wohlwend <beni@elastic.co>
Co-authored-by: Colton Myers <colton.myers@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants