{"action":"created","comment":{"url":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/comments/85268961","pull_request_review_id":5993713,"id":85268961,"diff_hunk":"@@ -0,0 +1,64 @@\n+---\n+title: Schema — Instrumentation\n+---\n+\n+Instrumentation provides hooks for inserting custom code around field resolution and query execution.\n+\n+## Field Instrumentation\n+\n+Field instrumentation can be attached during schema definition:\n+\n+```ruby\n+MySchema = GraphQL::Schema.define do\n+  instrument(:field, MyFieldInstrumentation.new)\n+end\n+```\n+\n+The instrumenter is an object which responds to `#instrument(type, field)`. `#instrument` should return a `GraphQL::Field` instance which will be used during query execution. `#instrument` is called with each type-field pair for _all_ Object types and Interface types in your schema.\n+\n+Here's an example field instrumenter:\n+\n+```ruby\n+class MyFieldInstrumentation\n+  # If a field was flagged to be timed,\n+  # wrap its resolve proc with a timer.\n+  def instrument(type, field)\n+    if field.metadata[:timed]\n+      old_resolve_proc = field.resolve_proc\n+      new_resolve_proc = ->(obj, args, ctx) {\n+        Rails.logger.info(\"#{type.name}.#{field.name} START: #{Time.now.to_i}\")\n+        old_resolve_proc.call(obj, args, ctx)\n+        Rails.logger.info(\"#{type.name}.#{field.name} END: #{Time.now.to_i}\")\n+      }\n+    end\n+  end\n+end\n+```\n+\n+It can be attached as shown above. This implementation will _modify_ the underlying `GraphQL::Field` instance... be warned!\n+\n+## Query Instrumetation\n+\n+\n+Query instrumentation can be attached during schema definition:\n+\n+```ruby\n+MySchema = GraphQL::Schema.define do\n+  instrument(:query, MyQueryInstrumentation.new)\n+end\n+```\n+\n+The instrumenter must implement `#before_query(query)` and `#after_query(query)`. The return value of these methods are not used. They receive the `GraphQL::Query` instance.","path":"guides/schema/instrumentation.md","position":51,"original_position":51,"commit_id":"f9c2ecf459702fc56a45f57b889682deb13b1df4","original_commit_id":"f9c2ecf459702fc56a45f57b889682deb13b1df4","user":{"login":"cjoudrey","id":385270,"avatar_url":"https://avatars.githubusercontent.com/u/385270?v=3","gravatar_id":"","url":"https://api.github.com/users/cjoudrey","html_url":"https://github.com/cjoudrey","followers_url":"https://api.github.com/users/cjoudrey/followers","following_url":"https://api.github.com/users/cjoudrey/following{/other_user}","gists_url":"https://api.github.com/users/cjoudrey/gists{/gist_id}","starred_url":"https://api.github.com/users/cjoudrey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjoudrey/subscriptions","organizations_url":"https://api.github.com/users/cjoudrey/orgs","repos_url":"https://api.github.com/users/cjoudrey/repos","events_url":"https://api.github.com/users/cjoudrey/events{/privacy}","received_events_url":"https://api.github.com/users/cjoudrey/received_events","type":"User","site_admin":false},"body":"Other than calculating query time, can you think of a use case of providing this `before`/`after` granularity? Made me wonder if we should do like http://guides.rubyonrails.org/active_support_instrumentation.html#process-action-action-controller and just provide `def query` and the query time would be calculate already.\r\n\r\nHow would one be able to get the `start_time` when `after_query` gets triggered? Would this involve keeping a hash like: `@queries[query] = Time.now` and in `after_query` it would do: `Time.now - @queries[query]` and `@queries.delete(query)`?","created_at":"2016-10-27T05:42:40Z","updated_at":"2016-10-27T05:42:40Z","html_url":"https://github.com/rmosolgo/graphql-ruby/pull/354#discussion_r85268961","pull_request_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/354","_links":{"self":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/comments/85268961"},"html":{"href":"https://github.com/rmosolgo/graphql-ruby/pull/354#discussion_r85268961"},"pull_request":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/354"}}},"pull_request":{"url":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/354","id":91003709,"html_url":"https://github.com/rmosolgo/graphql-ruby/pull/354","diff_url":"https://github.com/rmosolgo/graphql-ruby/pull/354.diff","patch_url":"https://github.com/rmosolgo/graphql-ruby/pull/354.patch","issue_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/354","number":354,"state":"open","locked":false,"title":"Instrumentation","user":{"login":"rmosolgo","id":2231765,"avatar_url":"https://avatars.githubusercontent.com/u/2231765?v=3","gravatar_id":"","url":"https://api.github.com/users/rmosolgo","html_url":"https://github.com/rmosolgo","followers_url":"https://api.github.com/users/rmosolgo/followers","following_url":"https://api.github.com/users/rmosolgo/following{/other_user}","gists_url":"https://api.github.com/users/rmosolgo/gists{/gist_id}","starred_url":"https://api.github.com/users/rmosolgo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmosolgo/subscriptions","organizations_url":"https://api.github.com/users/rmosolgo/orgs","repos_url":"https://api.github.com/users/rmosolgo/repos","events_url":"https://api.github.com/users/rmosolgo/events{/privacy}","received_events_url":"https://api.github.com/users/rmosolgo/received_events","type":"User","site_admin":false},"body":"A hot take on #186 \r\n\r\n\r\n- Apply field instrumentation at build time \r\n- Apply query instrumentation at runtime \r\n- _Very_ specific implementation of instrumentation hooks \r\n\r\nBuyer beware: if you _modify_ the passed-in type or field, it will be changed _everywhere_ it's used (since it's the same object). I want to provide a shallow-copy API for these objects so that wrapping them is easier. \r\n\r\n\r\nIf there just _happened_ to be any [widely used extensions](https://github.com/Shopify/graphql-batch) to this gem, they could accept instrumentation of their own: \r\n\r\n```ruby \r\nMySchema = GraphQL::Schema.define do \r\n  instrument(:batch, MyBatchInstrumentation) \r\nend \r\n```\r\n\r\nAnd fetch it out & apply it as they see fit: \r\n\r\n```ruby \r\nMySchema.instrumenters[:batch] # => array of instrumenters (empty if `instrument` was not called)\r\n```\r\n\r\n__Todo__ \r\n\r\n- [ ] Benchmark: what's the overhead if you don't use it? \r\n- [ ] Shallow-copy API for schema members ","created_at":"2016-10-26T13:27:03Z","updated_at":"2016-10-27T05:42:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a9e7e3d35e7bdf5f1831e75c620adb02d0886920","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/354/commits","review_comments_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/354/comments","review_comment_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/354/comments","statuses_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/statuses/f9c2ecf459702fc56a45f57b889682deb13b1df4","head":{"label":"rmosolgo:instrumentation","ref":"instrumentation","sha":"f9c2ecf459702fc56a45f57b889682deb13b1df4","user":{"login":"rmosolgo","id":2231765,"avatar_url":"https://avatars.githubusercontent.com/u/2231765?v=3","gravatar_id":"","url":"https://api.github.com/users/rmosolgo","html_url":"https://github.com/rmosolgo","followers_url":"https://api.github.com/users/rmosolgo/followers","following_url":"https://api.github.com/users/rmosolgo/following{/other_user}","gists_url":"https://api.github.com/users/rmosolgo/gists{/gist_id}","starred_url":"https://api.github.com/users/rmosolgo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmosolgo/subscriptions","organizations_url":"https://api.github.com/users/rmosolgo/orgs","repos_url":"https://api.github.com/users/rmosolgo/repos","events_url":"https://api.github.com/users/rmosolgo/events{/privacy}","received_events_url":"https://api.github.com/users/rmosolgo/received_events","type":"User","site_admin":false},"repo":{"id":30337170,"name":"graphql-ruby","full_name":"rmosolgo/graphql-ruby","owner":{"login":"rmosolgo","id":2231765,"avatar_url":"https://avatars.githubusercontent.com/u/2231765?v=3","gravatar_id":"","url":"https://api.github.com/users/rmosolgo","html_url":"https://github.com/rmosolgo","followers_url":"https://api.github.com/users/rmosolgo/followers","following_url":"https://api.github.com/users/rmosolgo/following{/other_user}","gists_url":"https://api.github.com/users/rmosolgo/gists{/gist_id}","starred_url":"https://api.github.com/users/rmosolgo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmosolgo/subscriptions","organizations_url":"https://api.github.com/users/rmosolgo/orgs","repos_url":"https://api.github.com/users/rmosolgo/repos","events_url":"https://api.github.com/users/rmosolgo/events{/privacy}","received_events_url":"https://api.github.com/users/rmosolgo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rmosolgo/graphql-ruby","description":"Ruby implementation of GraphQL: https://rmosolgo.github.io/graphql-ruby/","fork":false,"url":"https://api.github.com/repos/rmosolgo/graphql-ruby","forks_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/forks","keys_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/teams","hooks_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/hooks","issue_events_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/events{/number}","events_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/events","assignees_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/assignees{/user}","branches_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/branches{/branch}","tags_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/tags","blobs_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/refs{/sha}","trees_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/statuses/{sha}","languages_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/languages","stargazers_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/stargazers","contributors_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/contributors","subscribers_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/subscribers","subscription_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/subscription","commits_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/commits{/sha}","git_commits_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/commits{/sha}","comments_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/comments{/number}","issue_comment_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/comments{/number}","contents_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/contents/{+path}","compare_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/merges","archive_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/downloads","issues_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues{/number}","pulls_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls{/number}","milestones_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/milestones{/number}","notifications_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/labels{/name}","releases_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/releases{/id}","deployments_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/deployments","created_at":"2015-02-05T04:11:22Z","updated_at":"2016-10-27T02:49:23Z","pushed_at":"2016-10-27T02:16:10Z","git_url":"git://github.com/rmosolgo/graphql-ruby.git","ssh_url":"git@github.com:rmosolgo/graphql-ruby.git","clone_url":"https://github.com/rmosolgo/graphql-ruby.git","svn_url":"https://github.com/rmosolgo/graphql-ruby","homepage":"","size":2736,"stargazers_count":1180,"watchers_count":1180,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":106,"mirror_url":null,"open_issues_count":17,"forks":106,"open_issues":17,"watchers":1180,"default_branch":"master"}},"base":{"label":"rmosolgo:master","ref":"master","sha":"3d503971f49e68a35581914fb1bf7e5cd012f621","user":{"login":"rmosolgo","id":2231765,"avatar_url":"https://avatars.githubusercontent.com/u/2231765?v=3","gravatar_id":"","url":"https://api.github.com/users/rmosolgo","html_url":"https://github.com/rmosolgo","followers_url":"https://api.github.com/users/rmosolgo/followers","following_url":"https://api.github.com/users/rmosolgo/following{/other_user}","gists_url":"https://api.github.com/users/rmosolgo/gists{/gist_id}","starred_url":"https://api.github.com/users/rmosolgo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmosolgo/subscriptions","organizations_url":"https://api.github.com/users/rmosolgo/orgs","repos_url":"https://api.github.com/users/rmosolgo/repos","events_url":"https://api.github.com/users/rmosolgo/events{/privacy}","received_events_url":"https://api.github.com/users/rmosolgo/received_events","type":"User","site_admin":false},"repo":{"id":30337170,"name":"graphql-ruby","full_name":"rmosolgo/graphql-ruby","owner":{"login":"rmosolgo","id":2231765,"avatar_url":"https://avatars.githubusercontent.com/u/2231765?v=3","gravatar_id":"","url":"https://api.github.com/users/rmosolgo","html_url":"https://github.com/rmosolgo","followers_url":"https://api.github.com/users/rmosolgo/followers","following_url":"https://api.github.com/users/rmosolgo/following{/other_user}","gists_url":"https://api.github.com/users/rmosolgo/gists{/gist_id}","starred_url":"https://api.github.com/users/rmosolgo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmosolgo/subscriptions","organizations_url":"https://api.github.com/users/rmosolgo/orgs","repos_url":"https://api.github.com/users/rmosolgo/repos","events_url":"https://api.github.com/users/rmosolgo/events{/privacy}","received_events_url":"https://api.github.com/users/rmosolgo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rmosolgo/graphql-ruby","description":"Ruby implementation of GraphQL: https://rmosolgo.github.io/graphql-ruby/","fork":false,"url":"https://api.github.com/repos/rmosolgo/graphql-ruby","forks_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/forks","keys_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/teams","hooks_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/hooks","issue_events_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/events{/number}","events_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/events","assignees_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/assignees{/user}","branches_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/branches{/branch}","tags_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/tags","blobs_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/refs{/sha}","trees_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/statuses/{sha}","languages_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/languages","stargazers_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/stargazers","contributors_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/contributors","subscribers_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/subscribers","subscription_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/subscription","commits_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/commits{/sha}","git_commits_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/git/commits{/sha}","comments_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/comments{/number}","issue_comment_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/comments{/number}","contents_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/contents/{+path}","compare_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/merges","archive_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/downloads","issues_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues{/number}","pulls_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls{/number}","milestones_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/milestones{/number}","notifications_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/labels{/name}","releases_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/releases{/id}","deployments_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/deployments","created_at":"2015-02-05T04:11:22Z","updated_at":"2016-10-27T02:49:23Z","pushed_at":"2016-10-27T02:16:10Z","git_url":"git://github.com/rmosolgo/graphql-ruby.git","ssh_url":"git@github.com:rmosolgo/graphql-ruby.git","clone_url":"https://github.com/rmosolgo/graphql-ruby.git","svn_url":"https://github.com/rmosolgo/graphql-ruby","homepage":"","size":2736,"stargazers_count":1180,"watchers_count":1180,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":106,"mirror_url":null,"open_issues_count":17,"forks":106,"open_issues":17,"watchers":1180,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/354"},"html":{"href":"https://github.com/rmosolgo/graphql-ruby/pull/354"},"issue":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/354"},"comments":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/354/comments"},"review_comments":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/354/comments"},"review_comment":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/pulls/354/commits"},"statuses":{"href":"https://api.github.com/repos/rmosolgo/graphql-ruby/statuses/f9c2ecf459702fc56a45f57b889682deb13b1df4"}}}}
{"actor":{"display_login":"cjoudrey"}}