graphql-hive 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa05eaf88fa4240d8ee2364b48a2b7152eec226c2d657156a87efdb5f98eb2c3
4
- data.tar.gz: 72e529bf8227f49d5a6c3602c5375feee671263f0e3df31c6b60cd034aff0910
3
+ metadata.gz: b4c1afad31aef320c5c3994eeadba81a4e87fcf92c44f7bb3a1a1559ff1e3429
4
+ data.tar.gz: 604b0f65a3292a15154fb4f3808b4cf62f7d31d9a8c157c920d4882988ece36f
5
5
  SHA512:
6
- metadata.gz: 3669a7e7bedabc6b8dfd3b471fa921bfb34aafed0a5fcc927baca80d55766903ff9ea7aad55460cb72ab8fd38d3f54cf91b1ef345ddb7789048b7c898f4b36fd
7
- data.tar.gz: 003c658d94088ea6f89b4a37b2124f907fad3240bf9e2150fffe5ca62d9e2d78ab096f7fe6363e2b7a361f82e7fb2a711c3670ce5e8477986cacae5c8991fbb4
6
+ metadata.gz: 3a6e1de7d61c15382ab4270769f8f9e6647dadb58d6eeffe9c042663cc448cb0c263ef79dbeed85db220abb1c8b97e54df1a0fadba8f550538b0b6ce489eb83d
7
+ data.tar.gz: bd16af0fba744194dd093cef087f1bb04c4170a7f4d491939e6ceb8f4d0fc380e179ce7b0b721c655e2f606f463f82da0945df0308572c4c46fd20d8f5176608
@@ -8,33 +8,26 @@ on:
8
8
  - master
9
9
 
10
10
  jobs:
11
- rubocop:
11
+ standard:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v4
15
-
16
- - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f
17
- with:
18
- ruby-version: '3.3'
19
- bundler-cache: true
20
-
21
- - run: bundle exec rake rubocop
22
-
14
+ - name: Standard Ruby
15
+ uses: standardrb/standard-ruby-action@v1
23
16
  test:
24
17
  strategy:
25
18
  fail-fast: false
26
19
  matrix:
27
20
  ruby-version:
28
- - '3.1'
29
- - '3.2'
30
- - '3.3'
21
+ - "3.1"
22
+ - "3.2"
23
+ - "3.3"
31
24
  runs-on: ubuntu-latest
32
25
  steps:
33
- - uses: actions/checkout@v4
26
+ - uses: actions/checkout@v4
34
27
 
35
- - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f
36
- with:
37
- ruby-version: ${{ matrix.ruby-version }}
38
- bundler-cache: true
28
+ - uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f
29
+ with:
30
+ ruby-version: ${{ matrix.ruby-version }}
31
+ bundler-cache: true
39
32
 
40
- - run: bundle exec rake spec
33
+ - run: bundle exec rake spec
data/.gitignore CHANGED
@@ -11,3 +11,9 @@
11
11
  .rspec_status
12
12
  *.gem
13
13
  k6/node_modules/
14
+
15
+ # IDEs
16
+ .idea
17
+
18
+ # k6
19
+ node_modules
data/.rubocop.yml CHANGED
@@ -1,41 +1,10 @@
1
- AllCops:
2
- TargetRubyVersion: 2.6
3
- NewCops: enable
4
- Exclude:
5
- - 'examples/**/*'
6
- - 'k6/**/*'
7
- - 'gemfiles/**/*'
8
- - 'tmp/**/*'
9
- - 'vendor/**/*'
10
-
11
- Metrics/BlockLength:
12
- Exclude:
13
- - 'spec/**/*'
14
-
15
- Layout/LineLength:
16
- Exclude:
17
- - 'spec/**/*'
18
-
19
- Naming/FileName:
20
- Enabled: false
21
-
22
- Style/ClassVars:
23
- Enabled: false
24
-
25
- Metrics/AbcSize:
26
- Enabled: false
27
-
28
- Metrics/PerceivedComplexity:
29
- Enabled: false
30
-
31
- Metrics/CyclomaticComplexity:
32
- Enabled: false
33
-
34
- Metrics/MethodLength:
35
- Enabled: false
36
-
37
- Metrics/ClassLength:
38
- Enabled: false
39
-
40
- Gemspec/DevelopmentDependencies:
41
- EnforcedStyle: 'gemspec'
1
+ require:
2
+ - standard
3
+ - standard-custom
4
+ - standard-performance
5
+ - rubocop-performance
6
+
7
+ inherit_gem:
8
+ standard: config/base.yml
9
+ standard-custom: config/base.yml
10
+ standard-performance: config/base.yml
data/Gemfile CHANGED
@@ -1,8 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
6
 
7
7
  # Specify your gem's dependencies in graphql-hive.gemspec
8
8
  gemspec
9
+
10
+ group :development do
11
+ gem "bundler", "~> 2"
12
+ gem "rake", "~> 13"
13
+ gem "rspec", "~> 3"
14
+ gem "standardrb", "~> 1"
15
+ end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphql-hive (0.4.1)
4
+ graphql-hive (0.5.0)
5
5
  graphql (>= 2.3, < 3)
6
6
 
7
7
  GEM
@@ -14,16 +14,16 @@ GEM
14
14
  base64
15
15
  json (2.7.2)
16
16
  language_server-protocol (3.17.0.3)
17
- parallel (1.25.1)
18
- parser (3.3.3.0)
17
+ lint_roller (1.1.0)
18
+ parallel (1.26.3)
19
+ parser (3.3.5.0)
19
20
  ast (~> 2.4.1)
20
21
  racc
21
- racc (1.8.0)
22
+ racc (1.8.1)
22
23
  rainbow (3.1.1)
23
24
  rake (13.2.1)
24
25
  regexp_parser (2.9.2)
25
- rexml (3.3.1)
26
- strscan
26
+ rexml (3.3.8)
27
27
  rspec (3.13.0)
28
28
  rspec-core (~> 3.13.0)
29
29
  rspec-expectations (~> 3.13.0)
@@ -37,22 +37,38 @@ GEM
37
37
  diff-lcs (>= 1.2.0, < 2.0)
38
38
  rspec-support (~> 3.13.0)
39
39
  rspec-support (3.13.1)
40
- rubocop (1.64.1)
40
+ rubocop (1.65.1)
41
41
  json (~> 2.3)
42
42
  language_server-protocol (>= 3.17.0)
43
43
  parallel (~> 1.10)
44
44
  parser (>= 3.3.0.2)
45
45
  rainbow (>= 2.2.2, < 4.0)
46
- regexp_parser (>= 1.8, < 3.0)
46
+ regexp_parser (>= 2.4, < 3.0)
47
47
  rexml (>= 3.2.5, < 4.0)
48
48
  rubocop-ast (>= 1.31.1, < 2.0)
49
49
  ruby-progressbar (~> 1.7)
50
50
  unicode-display_width (>= 2.4.0, < 3.0)
51
- rubocop-ast (1.31.3)
51
+ rubocop-ast (1.32.3)
52
52
  parser (>= 3.3.1.0)
53
+ rubocop-performance (1.21.1)
54
+ rubocop (>= 1.48.1, < 2.0)
55
+ rubocop-ast (>= 1.31.1, < 2.0)
53
56
  ruby-progressbar (1.13.0)
54
- strscan (3.1.0)
55
- unicode-display_width (2.5.0)
57
+ standard (1.40.1)
58
+ language_server-protocol (~> 3.17.0.2)
59
+ lint_roller (~> 1.0)
60
+ rubocop (~> 1.65.0)
61
+ standard-custom (~> 1.0.0)
62
+ standard-performance (~> 1.4)
63
+ standard-custom (1.0.2)
64
+ lint_roller (~> 1.0)
65
+ rubocop (~> 1.50)
66
+ standard-performance (1.4.0)
67
+ lint_roller (~> 1.1)
68
+ rubocop-performance (~> 1.21.0)
69
+ standardrb (1.0.1)
70
+ standard
71
+ unicode-display_width (2.6.0)
56
72
 
57
73
  PLATFORMS
58
74
  arm64-darwin-23
@@ -63,7 +79,7 @@ DEPENDENCIES
63
79
  graphql-hive!
64
80
  rake (~> 13)
65
81
  rspec (~> 3)
66
- rubocop (~> 1)
82
+ standardrb (~> 1)
67
83
 
68
84
  BUNDLED WITH
69
85
  2.5.15
data/README.md CHANGED
@@ -154,9 +154,9 @@ class MySchema < GraphQL::Schema
154
154
  debug: false, # verbose logs
155
155
  logger: MyLogger.new,
156
156
  endpoint: 'app.graphql-hive.com',
157
- port: 80,
158
- buffer_size: 50, # forward the operations data to Hive every 50 requests
159
-
157
+ port: 80,
158
+ buffer_size: 50, # how many operations can be sent to hive in a single batch (AFTER sampling)
159
+
160
160
  collect_usage: true, # report usage to Hive
161
161
  collect_usage_sampling: {
162
162
  # optional members of `collect_usage_sampling`
@@ -164,8 +164,7 @@ class MySchema < GraphQL::Schema
164
164
  sampler: proc { |context| context.operation_name.includes?('someQuery') 1 : 0.5 }, # assign custom sampling rates (overrides `sampling rate`)
165
165
  at_least_once: true, # sample every distinct operation at least once
166
166
  key_generator: proc { |context| context.operation_name } # assign custom keys to distinguish between distinct operations
167
- }
168
-
167
+ },
169
168
  report_schema: true, # publish schema to Hive
170
169
  # mandatory if `report_schema: true`
171
170
  reporting: {
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require 'rubocop/rake_task'
8
+ require "rubocop/rake_task"
9
9
  RuboCop::RakeTask.new
10
10
 
11
11
  task(default: %i[spec rubocop])
@@ -1,8 +1,8 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
- gem 'graphql'
4
- gem 'graphql-hive', path: '../../'
5
- gem 'puma'
6
- gem 'rack-contrib'
7
- gem 'sinatra'
8
- gem 'sinatra-contrib'
3
+ gem "graphql"
4
+ gem "graphql-hive", path: "../../"
5
+ gem "puma"
6
+ gem "rack-contrib"
7
+ gem "sinatra"
8
+ gem "sinatra-contrib"
@@ -1,8 +1,8 @@
1
- require 'sinatra'
2
- require 'sinatra/json'
3
- require 'rack/contrib'
1
+ require "sinatra"
2
+ require "sinatra/json"
3
+ require "rack/contrib"
4
4
 
5
- require_relative 'schema'
5
+ require_relative "schema"
6
6
 
7
7
  # Test query:
8
8
  #
@@ -16,14 +16,14 @@ require_relative 'schema'
16
16
  class DemoApp < Sinatra::Base
17
17
  use Rack::JSONBodyParser
18
18
 
19
- post '/graphql' do
19
+ post "/graphql" do
20
20
  result = Schema.execute(
21
- params['query'],
21
+ params["query"],
22
22
  variables: params[:variables],
23
23
  operation_name: params[:operationName],
24
24
  context: {
25
- client_name: 'GraphQL Client',
26
- client_version: '1.0'
25
+ client_name: "GraphQL Client",
26
+ client_version: "1.0"
27
27
  }
28
28
  )
29
29
  json result
@@ -1,2 +1,2 @@
1
- require './app'
1
+ require "./app"
2
2
  run DemoApp
@@ -1,9 +1,9 @@
1
- require 'graphql'
2
- require 'graphql-hive'
1
+ require "graphql"
2
+ require "graphql-hive"
3
3
 
4
4
  module Types
5
5
  class PostType < GraphQL::Schema::Object
6
- description 'A blog post'
6
+ description "A blog post"
7
7
  field :id, ID, null: false
8
8
  field :title, String, null: false
9
9
  # fields should be queried in camel-case (this will be `truncatedPreview`)
@@ -12,29 +12,29 @@ module Types
12
12
  end
13
13
 
14
14
  class Types::PostInput < GraphQL::Schema::InputObject
15
- description 'Query Post arguments'
15
+ description "Query Post arguments"
16
16
  argument :id, ID, required: true
17
17
  end
18
18
 
19
19
  class Types::TestEnum < GraphQL::Schema::Enum
20
- value 'TEST1'
21
- value 'TEST2'
22
- value 'TEST3'
20
+ value "TEST1"
21
+ value "TEST2"
22
+ value "TEST3"
23
23
  end
24
24
 
25
25
  class QueryType < GraphQL::Schema::Object
26
- description 'The query root of this schema'
26
+ description "The query root of this schema"
27
27
 
28
28
  # First describe the field signature:
29
- field :post, Types::PostType, 'Find a post by ID' do
29
+ field :post, Types::PostType, "Find a post by ID" do
30
30
  argument :input, [Types::PostInput]
31
31
  argument :test, Types::TestEnum
32
32
  end
33
33
 
34
34
  # Then provide an implementation:
35
35
  def post(input:, test:)
36
- { id: 1, title: 'GraphQL Hive with `graphql-ruby`',
37
- truncated_preview: 'Monitor operations, inspect your queries and publish your GraphQL schema with GraphQL Hive' }
36
+ {id: 1, title: "GraphQL Hive with `graphql-ruby`",
37
+ truncated_preview: "Monitor operations, inspect your queries and publish your GraphQL schema with GraphQL Hive"}
38
38
  end
39
39
  end
40
40
 
@@ -44,9 +44,9 @@ class Schema < GraphQL::Schema
44
44
  use(
45
45
  GraphQL::Hive,
46
46
  buffer_size: 2,
47
- token: 'YOUR_TOKEN',
47
+ token: "YOUR_TOKEN",
48
48
  debug: true,
49
- reporting: { author: 'Charly Poly', commit: '109bb1e748bae21bdfe663c0ffc7e830' },
50
- client_info: proc { |context|{ name: context[:client_name], version: context[:client_version] }}
49
+ reporting: {author: "Charly Poly", commit: "109bb1e748bae21bdfe663c0ffc7e830"},
50
+ client_info: proc { |context| {name: context[:client_name], version: context[:client_version]} }
51
51
  )
52
52
  end
data/graphql-hive.gemspec CHANGED
@@ -1,33 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('lib', __dir__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'graphql-hive/version'
5
+ require "graphql-hive/version"
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.name = 'graphql-hive'
9
- spec.version = Graphql::Hive::VERSION
10
- spec.authors = ['Charly POLY']
11
- spec.email = ['cpoly55@gmail.com']
8
+ spec.name = "graphql-hive"
9
+ spec.version = Graphql::Hive::VERSION
10
+ spec.authors = ["Charly POLY"]
11
+ spec.email = ["cpoly55@gmail.com"]
12
12
 
13
- spec.summary = '"GraphQL Hive integration for `graphql-ruby`"'
14
- spec.description = '"Monitor operations, inspect your queries and publish your GraphQL schema with GraphQL Hive"'
15
- spec.homepage = 'https://docs.graphql-hive.com/specs/integrations'
16
- spec.license = 'MIT'
13
+ spec.summary = '"GraphQL Hive integration for `graphql-ruby`"'
14
+ spec.description = '"Monitor operations, inspect your queries and publish your GraphQL schema with GraphQL Hive"'
15
+ spec.homepage = "https://docs.graphql-hive.com/specs/integrations"
16
+ spec.license = "MIT"
17
17
 
18
- spec.metadata = { 'rubygems_mfa_required' => 'true' }
18
+ spec.metadata = {"rubygems_mfa_required" => "true"}
19
19
 
20
- spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
20
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
21
21
 
22
- spec.require_paths = ['lib']
23
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ spec.require_paths = ["lib"]
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
24
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
25
25
  end
26
26
 
27
- spec.add_dependency 'graphql', '>= 2.3', '< 3'
28
-
29
- spec.add_development_dependency 'bundler', '~> 2'
30
- spec.add_development_dependency 'rake', '~> 13'
31
- spec.add_development_dependency 'rspec', '~> 3'
32
- spec.add_development_dependency 'rubocop', '~> 1'
27
+ spec.add_dependency "graphql", ">= 2.3", "< 3"
33
28
  end
data/k6/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # k6 (Integration Tests)
2
+
3
+ This directory contains integration tests for the k6 project. In
4
+ summary, this folder does the following:
5
+ 1. Start a ruby server, with hive enabled
6
+ 2. Start a ruby server, with hive disabled
7
+ 3. Start a mock GraphQL Hive `/usage` api
8
+ 4. Run GraphQL Requests against the 2 servers
9
+ 5. Compare the results
10
+
11
+ ## Prerequisites
12
+ 1. Ruby > 3.0.0
13
+ 2. Node > 14.0.0
14
+ 3. [k6 installed](https://grafana.com/docs/k6/latest/set-up/install-k6/)
15
+
16
+ ## Running the tests (locally)
17
+
18
+ Start the ruby server with HIVE_ENABLED=true
19
+ ```bash
20
+ cd graphql-api
21
+ HIVE_ENABLED=true bundle exec puma -t 0:1 -p 9292
22
+ ```
23
+
24
+ Start the ruby server with HIVE_ENABLED=false
25
+ ```bash
26
+ HIVE_ENABLED=false bundle exec puma -t 0:1 -p 9291
27
+ ```
28
+
29
+ Start the usage mock server
30
+ ```bash
31
+ node usage-mock.js
32
+ ```
33
+
34
+ Run k6 tests:
35
+ ```bash
36
+ k6 run k6.js
37
+ ```
@@ -1,9 +1,9 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
- gem 'graphql', '~> 2'
4
- gem 'graphql-hive', path: '../../'
5
- gem 'puma', '~> 6'
6
- gem 'racc'
7
- gem 'rack-contrib', '~> 2'
8
- gem 'sinatra', '~> 2'
9
- gem 'sinatra-contrib'
3
+ gem "graphql", "~> 2"
4
+ gem "graphql-hive", path: "../../"
5
+ gem "puma", "~> 6"
6
+ gem "racc"
7
+ gem "rack-contrib", "~> 2"
8
+ gem "sinatra", "~> 2"
9
+ gem "sinatra-contrib"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- graphql-hive (0.4.1)
4
+ graphql-hive (0.5.0)
5
5
  graphql (>= 2.3, < 3)
6
6
 
7
7
  GEM
@@ -1,24 +1,24 @@
1
- require 'sinatra'
2
- require 'sinatra/json'
3
- require 'rack/contrib'
1
+ require "sinatra"
2
+ require "sinatra/json"
3
+ require "rack/contrib"
4
4
 
5
- require_relative 'schema'
5
+ require_relative "schema"
6
6
 
7
7
  class DemoApp < Sinatra::Base
8
8
  use Rack::JSONBodyParser
9
9
 
10
- get '/' do
10
+ get "/" do
11
11
  status 200
12
12
  end
13
13
 
14
- post '/graphql' do
14
+ post "/graphql" do
15
15
  result = Schema.execute(
16
- params['query'],
16
+ params["query"],
17
17
  variables: params[:variables],
18
18
  operation_name: params[:operationName],
19
19
  context: {
20
- client_name: 'GraphQL Client',
21
- client_version: '1.0'
20
+ client_name: "GraphQL Client",
21
+ client_version: "1.0"
22
22
  }
23
23
  )
24
24
  json result
@@ -1,2 +1,2 @@
1
- require './app'
1
+ require "./app"
2
2
  run DemoApp
@@ -1,9 +1,9 @@
1
- require 'graphql'
2
- require 'graphql-hive'
1
+ require "graphql"
2
+ require "graphql-hive"
3
3
 
4
4
  module Types
5
5
  class PostType < GraphQL::Schema::Object
6
- description 'A blog post'
6
+ description "A blog post"
7
7
  field :id, ID, null: false
8
8
  field :title, String, null: false
9
9
  # fields should be queried in camel-case (this will be `truncatedPreview`)
@@ -12,17 +12,17 @@ module Types
12
12
  end
13
13
 
14
14
  class QueryType < GraphQL::Schema::Object
15
- description 'The query root of this schema'
15
+ description "The query root of this schema"
16
16
 
17
17
  # First describe the field signature:
18
- field :post, Types::PostType, 'Find a post by ID' do
18
+ field :post, Types::PostType, "Find a post by ID" do
19
19
  argument :id, [ID]
20
20
  end
21
21
 
22
22
  # Then provide an implementation:
23
23
  def post(id:)
24
- { id: 1, title: 'GraphQL Hive with `graphql-ruby`',
25
- truncated_preview: 'Monitor operations, inspect your queries and publish your GraphQL schema with GraphQL Hive' }
24
+ {id: 1, title: "GraphQL Hive with `graphql-ruby`",
25
+ truncated_preview: "Monitor operations, inspect your queries and publish your GraphQL schema with GraphQL Hive"}
26
26
  end
27
27
  end
28
28
 
@@ -31,11 +31,11 @@ class Schema < GraphQL::Schema
31
31
 
32
32
  use(
33
33
  GraphQL::Hive,
34
- enabled: ENV['HIVE_ENABLED'] === 'true',
35
- endpoint: 'localhost',
34
+ enabled: ENV["HIVE_ENABLED"] === "true",
35
+ endpoint: "localhost",
36
36
  debug: true,
37
37
  port: 8888,
38
- token: 'stress-token',
38
+ token: "stress-token",
39
39
  report_schema: false
40
40
  )
41
41
  end
@@ -73,7 +73,7 @@ module GraphQL
73
73
  end
74
74
 
75
75
  def make_id(*tokens)
76
- tokens.join('.')
76
+ tokens.join(".")
77
77
  end
78
78
  end
79
79
  end
@@ -0,0 +1,26 @@
1
+ module GraphQL
2
+ class Hive < GraphQL::Tracing::PlatformTracing
3
+ # BoundedQueue is being used so that the queue does not grow indefinitely
4
+ # We do not use `SizedQueue` because it blocks the thread when the queue is full with a .wait call
5
+ # This would go against us not impacting the application performance with the usage reporter
6
+ class BoundedQueue < Thread::Queue
7
+ def initialize(bound:, logger:)
8
+ @bound = bound
9
+ @logger = logger
10
+ @lock = Mutex.new
11
+
12
+ super()
13
+ end
14
+
15
+ def push(item)
16
+ @lock.synchronize do
17
+ if size >= @bound
18
+ @logger.error("BoundedQueue is full, discarding operation")
19
+ return
20
+ end
21
+ super
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'net/http'
4
- require 'uri'
3
+ require "net/http"
4
+ require "uri"
5
5
 
6
6
  module GraphQL
7
7
  class Hive < GraphQL::Tracing::PlatformTracing
@@ -14,9 +14,9 @@ module GraphQL
14
14
  def send(path, body, _log_type)
15
15
  uri =
16
16
  URI::HTTP.build(
17
- scheme: @options[:port].to_s == '443' ? 'https' : 'http',
18
- host: @options[:endpoint] || 'app.graphql-hive.com',
19
- port: @options[:port] || '443',
17
+ scheme: (@options[:port].to_s == "443") ? "https" : "http",
18
+ host: @options[:endpoint] || "app.graphql-hive.com",
19
+ port: @options[:port] || "443",
20
20
  path: path
21
21
  )
22
22
 
@@ -26,26 +26,25 @@ module GraphQL
26
26
 
27
27
  @options[:logger].debug(response.inspect)
28
28
  @options[:logger].debug(response.body.inspect)
29
- rescue StandardError => e
29
+ rescue => e
30
30
  @options[:logger].fatal("Failed to send data: #{e}")
31
- raise e
32
31
  end
33
32
 
34
33
  def setup_http(uri)
35
34
  http = ::Net::HTTP.new(uri.host, uri.port)
36
- http.use_ssl = @options[:port].to_s == '443'
35
+ http.use_ssl = @options[:port].to_s == "443"
37
36
  http.read_timeout = 2
38
37
  http
39
38
  end
40
39
 
41
40
  def build_request(uri, body)
42
41
  request = Net::HTTP::Post.new(uri.request_uri)
43
- request['Authorization'] = @options[:token]
44
- request['X-Usage-API-Version'] = '2'
45
- request['content-type'] = 'application/json'
46
- request['User-Agent'] = "Hive@#{Graphql::Hive::VERSION}"
47
- request['graphql-client-name'] = 'Hive Ruby Client'
48
- request['graphql-client-version'] = Graphql::Hive::VERSION
42
+ request["Authorization"] = @options[:token]
43
+ request["X-Usage-API-Version"] = "2"
44
+ request["content-type"] = "application/json"
45
+ request["User-Agent"] = "Hive@#{Graphql::Hive::VERSION}"
46
+ request["graphql-client-name"] = "Hive Ruby Client"
47
+ request["graphql-client-version"] = Graphql::Hive::VERSION
49
48
  request.body = JSON.generate(body)
50
49
  request
51
50
  end
@@ -10,12 +10,12 @@ module GraphQL
10
10
  @out.append(str)
11
11
  end
12
12
 
13
- def print_node(node, indent: '')
13
+ def print_node(node, indent: "")
14
14
  case node
15
15
  when Float, Integer
16
- print_string '0'
16
+ print_string "0"
17
17
  when String
18
- print_string ''
18
+ print_string ""
19
19
  else
20
20
  super
21
21
  end
@@ -23,16 +23,16 @@ module GraphQL
23
23
 
24
24
  # from GraphQL::Language::Printer with sort_by name
25
25
  # ignores aliases
26
- def print_field(field, indent: '')
26
+ def print_field(field, indent: "")
27
27
  print_string(indent)
28
28
  print_string(field.name)
29
29
  if field.arguments.any?
30
- print_string('(')
30
+ print_string("(")
31
31
  field.arguments.sort_by(&:name).each_with_index do |a, i|
32
32
  print_argument(a)
33
- print_string(', ') if i < field.arguments.size - 1
33
+ print_string(", ") if i < field.arguments.size - 1
34
34
  end
35
- print_string(')')
35
+ print_string(")")
36
36
  end
37
37
  print_directives(field.directives)
38
38
  print_selections(field.selections, indent: indent)
@@ -43,7 +43,7 @@ module GraphQL
43
43
  end
44
44
 
45
45
  # from GraphQL::Language::Printer with sort_by name
46
- def print_selections(selections, indent: '')
46
+ def print_selections(selections, indent: "")
47
47
  sorted_nodes = selections.sort_by do |s|
48
48
  next s.name if s.respond_to?(:name)
49
49
  next s.type.name if s.respond_to?(:type)
@@ -55,35 +55,35 @@ module GraphQL
55
55
 
56
56
  # from GraphQL::Language::Printer with sort_by name
57
57
  def print_directive(directive)
58
- print_string('@')
58
+ print_string("@")
59
59
  print_string(directive.name)
60
60
 
61
61
  return if directive.arguments.blank?
62
62
 
63
- print_string('(')
63
+ print_string("(")
64
64
  directive.arguments.sort_by(&:name).each_with_index do |a, i|
65
65
  print_argument(a)
66
- print_string(', ') if i < directive.arguments.size - 1
66
+ print_string(", ") if i < directive.arguments.size - 1
67
67
  end
68
- print_string(')')
68
+ print_string(")")
69
69
  end
70
70
 
71
71
  # from GraphQL::Language::Printer with sort_by name
72
- def print_operation_definition(operation_definition, indent: '')
72
+ def print_operation_definition(operation_definition, indent: "")
73
73
  print_string(indent)
74
74
  print_string(operation_definition.operation_type)
75
75
  if operation_definition.name
76
- print_string(' ')
76
+ print_string(" ")
77
77
  print_string(operation_definition.name)
78
78
  end
79
79
 
80
80
  if operation_definition.variables.any?
81
- print_string('(')
81
+ print_string("(")
82
82
  operation_definition.variables.sort_by(&:name).each_with_index do |v, i|
83
83
  print_variable_definition(v)
84
- print_string(', ') if i < operation_definition.variables.size - 1
84
+ print_string(", ") if i < operation_definition.variables.size - 1
85
85
  end
86
- print_string(')')
86
+ print_string(")")
87
87
  end
88
88
 
89
89
  print_directives(operation_definition.directives)
@@ -8,28 +8,28 @@ module GraphQL
8
8
  # backwards compatibility with old `collect_usage_sampling` field
9
9
  if sampling_options.is_a?(Numeric)
10
10
  logger&.warn(
11
- '`collect_usage_sampling` is deprecated for fixed sampling rates, ' \
12
- 'use `collect_usage_sampling: { sample_rate: XX }` instead'
11
+ "`collect_usage_sampling` is deprecated for fixed sampling rates, " \
12
+ "use `collect_usage_sampling: { sample_rate: XX }` instead"
13
13
  )
14
14
  passed_sampling_rate = sampling_options
15
- sampling_options = { sample_rate: passed_sampling_rate }
15
+ sampling_options = {sample_rate: passed_sampling_rate}
16
16
  end
17
17
 
18
18
  sampling_options ||= {}
19
19
 
20
20
  @sampler = if sampling_options[:sampler]
21
- Sampling::DynamicSampler.new(
22
- sampling_options[:sampler],
23
- sampling_options[:at_least_once],
24
- sampling_options[:key_generator]
25
- )
26
- else
27
- Sampling::BasicSampler.new(
28
- sampling_options[:sample_rate],
29
- sampling_options[:at_least_once],
30
- sampling_options[:key_generator]
31
- )
32
- end
21
+ Sampling::DynamicSampler.new(
22
+ sampling_options[:sampler],
23
+ sampling_options[:at_least_once],
24
+ sampling_options[:key_generator]
25
+ )
26
+ else
27
+ Sampling::BasicSampler.new(
28
+ sampling_options[:sample_rate],
29
+ sampling_options[:at_least_once],
30
+ sampling_options[:key_generator]
31
+ )
32
+ end
33
33
  end
34
34
 
35
35
  def sample?(operation)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'graphql-hive/sampling/sampling_context'
3
+ require "graphql-hive/sampling/sampling_context"
4
4
 
5
5
  module GraphQL
6
6
  class Hive
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'graphql-hive/sampling/sampling_context'
3
+ require "graphql-hive/sampling/sampling_context"
4
4
 
5
5
  module GraphQL
6
6
  class Hive
@@ -16,7 +16,7 @@ module GraphQL
16
16
  def get_sample_context(operation)
17
17
  _, queries, results, = operation
18
18
 
19
- operation_name = queries.map(&:operations).map(&:keys).flatten.compact.join(', ')
19
+ operation_name = queries.map(&:operations).map(&:keys).flatten.compact.join(", ")
20
20
 
21
21
  parsed_definitions = []
22
22
  queries.each do |query|
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'digest'
4
- require 'graphql-hive/analyzer'
5
- require 'graphql-hive/printer'
3
+ require "digest"
4
+ require "graphql-hive/analyzer"
5
+ require "graphql-hive/printer"
6
+ require "graphql-hive/bounded_queue"
6
7
 
7
8
  module GraphQL
8
9
  class Hive < GraphQL::Tracing::PlatformTracing
@@ -16,14 +17,11 @@ module GraphQL
16
17
 
17
18
  def initialize(options, client)
18
19
  @@instance = self
19
-
20
20
  @options = options
21
21
  @client = client
22
-
23
22
  @options_mutex = Mutex.new
24
- @queue = Queue.new
25
-
26
23
  @sampler = Sampler.new(options[:collect_usage_sampling], options[:logger]) # NOTE: logs for deprecated field
24
+ @queue = BoundedQueue.new(bound: options[:buffer_size], logger: options[:logger])
27
25
 
28
26
  start_thread
29
27
  end
@@ -45,36 +43,38 @@ module GraphQL
45
43
 
46
44
  def start_thread
47
45
  if @thread&.alive?
48
- @options[:logger].warn('Tried to start operations flushing thread but it was already alive')
46
+ @options[:logger].warn("Tried to start operations flushing thread but it was already alive")
49
47
  return
50
48
  end
51
49
 
52
50
  @thread = Thread.new do
53
51
  buffer = []
54
52
  while (operation = @queue.pop(false))
55
- @options[:logger].debug("processing operation from queue: #{operation}")
56
- buffer << operation if @sampler.sample?(operation)
57
-
58
- @options_mutex.synchronize do
59
- if buffer.size >= @options[:buffer_size]
60
- @options[:logger].debug('buffer is full, sending!')
61
- process_operations(buffer)
62
- buffer = []
53
+ begin
54
+ @options[:logger].debug("processing operation from queue: #{operation}")
55
+ buffer << operation if @sampler.sample?(operation)
56
+
57
+ @options_mutex.synchronize do
58
+ if buffer.size >= @options[:buffer_size]
59
+ @options[:logger].debug("buffer is full, sending!")
60
+ process_operations(buffer)
61
+ buffer = []
62
+ end
63
63
  end
64
+ rescue => e
65
+ buffer = []
66
+ @options[:logger].error(e)
64
67
  end
65
68
  end
66
69
 
67
70
  unless buffer.empty?
68
- @options[:logger].debug('shuting down with buffer, sending!')
71
+ @options[:logger].debug("shuting down with buffer, sending!")
69
72
  process_operations(buffer)
70
73
  end
71
- rescue StandardError => e
74
+ rescue => e
72
75
  # ensure configured logger receives exception as well in setups where STDERR might not be
73
76
  # monitored.
74
- @options[:logger].error('GraphQL Hive usage collection thread terminating')
75
77
  @options[:logger].error(e)
76
-
77
- raise e
78
78
  end
79
79
  end
80
80
 
@@ -91,7 +91,7 @@ module GraphQL
91
91
 
92
92
  @options[:logger].debug("sending report: #{report}")
93
93
 
94
- @client.send('/usage', report, :usage)
94
+ @client.send(:"/usage", report, :usage)
95
95
  end
96
96
 
97
97
  def add_operation_to_report(report, operation)
@@ -99,8 +99,8 @@ module GraphQL
99
99
 
100
100
  errors = errors_from_results(results)
101
101
 
102
- operation_name = queries.map(&:operations).map(&:keys).flatten.compact.join(', ')
103
- operation = ''
102
+ operation_name = queries.map(&:operations).map(&:keys).flatten.compact.join(", ")
103
+ operation = ""
104
104
  fields = Set.new
105
105
 
106
106
  queries.each do |query|
@@ -134,7 +134,7 @@ module GraphQL
134
134
 
135
135
  if results[0]
136
136
  context = results[0].query.context
137
- operation_record[:metadata] = { client: @options[:client_info].call(context) } if @options[:client_info]
137
+ operation_record[:metadata] = {client: @options[:client_info].call(context)} if @options[:client_info]
138
138
  end
139
139
 
140
140
  report[:map][operation_map_key] = {
@@ -147,9 +147,9 @@ module GraphQL
147
147
  end
148
148
 
149
149
  def errors_from_results(results)
150
- acc = { errorsTotal: 0 }
150
+ acc = {errorsTotal: 0}
151
151
  results.each do |result|
152
- errors = result.to_h.fetch('errors', [])
152
+ errors = result.to_h.fetch("errors", [])
153
153
  errors.each do
154
154
  acc[:errorsTotal] += 1
155
155
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Graphql
4
4
  module Hive
5
- VERSION = '0.4.1'
5
+ VERSION = "0.5.0"
6
6
  end
7
7
  end
data/lib/graphql-hive.rb CHANGED
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
4
- require 'securerandom'
3
+ require "logger"
4
+ require "securerandom"
5
5
 
6
- require 'graphql-hive/version'
7
- require 'graphql-hive/usage_reporter'
8
- require 'graphql-hive/client'
6
+ require "graphql-hive/version"
7
+ require "graphql-hive/usage_reporter"
8
+ require "graphql-hive/client"
9
9
 
10
- require 'graphql-hive/sampler'
11
- require 'graphql-hive/sampling/basic_sampler'
12
- require 'graphql-hive/sampling/dynamic_sampler'
10
+ require "graphql-hive/sampler"
11
+ require "graphql-hive/sampling/basic_sampler"
12
+ require "graphql-hive/sampling/dynamic_sampler"
13
13
 
14
14
  module GraphQL
15
15
  # GraphQL Hive usage collector and schema reporter
@@ -31,7 +31,7 @@ module GraphQL
31
31
  DEFAULT_OPTIONS = {
32
32
  enabled: true,
33
33
  debug: false,
34
- port: '443',
34
+ port: "443",
35
35
  collect_usage: true,
36
36
  read_operations: true,
37
37
  report_schema: true,
@@ -41,14 +41,14 @@ module GraphQL
41
41
  }.freeze
42
42
 
43
43
  self.platform_keys = {
44
- 'lex' => 'lex',
45
- 'parse' => 'parse',
46
- 'validate' => 'validate',
47
- 'analyze_query' => 'analyze_query',
48
- 'analyze_multiplex' => 'analyze_multiplex',
49
- 'execute_multiplex' => 'execute_multiplex',
50
- 'execute_query' => 'execute_query',
51
- 'execute_query_lazy' => 'execute_query_lazy'
44
+ "lex" => "lex",
45
+ "parse" => "parse",
46
+ "validate" => "validate",
47
+ "analyze_query" => "analyze_query",
48
+ "analyze_multiplex" => "analyze_multiplex",
49
+ "execute_multiplex" => "execute_multiplex",
50
+ "execute_query" => "execute_query",
51
+ "execute_query_lazy" => "execute_query_lazy"
52
52
  }
53
53
 
54
54
  def initialize(options = {})
@@ -84,7 +84,7 @@ module GraphQL
84
84
  def platform_trace(platform_key, _key, data)
85
85
  return yield unless @options[:enabled] && @options[:collect_usage]
86
86
 
87
- if platform_key == 'execute_multiplex'
87
+ if platform_key == "execute_multiplex"
88
88
  if data[:multiplex]
89
89
  queries = data[:multiplex].queries
90
90
  timestamp = (Time.now.utc.to_f * 1000).to_i
@@ -134,25 +134,26 @@ module GraphQL
134
134
  options[:logger] = Logger.new($stderr)
135
135
  original_formatter = Logger::Formatter.new
136
136
  options[:logger].formatter = proc { |severity, datetime, progname, msg|
137
- original_formatter.call(severity, datetime, progname, "[hive] #{msg.dump}")
137
+ msg = msg.respond_to?(:dump) ? msg.dump : msg
138
+ original_formatter.call(severity, datetime, progname, "[hive] #{msg}")
138
139
  }
139
140
  options[:logger].level = options[:debug] ? Logger::DEBUG : Logger::INFO
140
141
  end
141
142
  if !options.include?(:token) && (!options.include?(:enabled) || options.enabled)
142
- options[:logger].warn('`token` options is missing')
143
+ options[:logger].warn("`token` options is missing")
143
144
  options[:enabled] = false
144
145
  false
145
146
  elsif options[:report_schema] &&
147
+ (
148
+ !options.include?(:reporting) ||
146
149
  (
147
- !options.include?(:reporting) ||
148
- (
149
- options.include?(:reporting) && (
150
- !options[:reporting].include?(:author) || !options[:reporting].include?(:commit)
151
- )
150
+ options.include?(:reporting) && (
151
+ !options[:reporting].include?(:author) || !options[:reporting].include?(:commit)
152
152
  )
153
153
  )
154
+ )
154
155
 
155
- options[:logger].warn('`reporting.author` and `reporting.commit` options are required')
156
+ options[:logger].warn("`reporting.author` and `reporting.commit` options are required")
156
157
  false
157
158
  end
158
159
  true
@@ -167,7 +168,7 @@ module GraphQL
167
168
 
168
169
  body = {
169
170
  query: REPORT_SCHEMA_MUTATION,
170
- operationName: 'schemaPublish',
171
+ operationName: "schemaPublish",
171
172
  variables: {
172
173
  input: {
173
174
  sdl: sdl,
@@ -180,7 +181,7 @@ module GraphQL
180
181
  }
181
182
  }
182
183
 
183
- @client.send('/registry', body, :'report-schema')
184
+ @client.send(:"/registry", body, :"report-schema")
184
185
  end
185
186
  end
186
187
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-hive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charly POLY
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-26 00:00:00.000000000 Z
11
+ date: 2024-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -30,62 +30,6 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '3'
33
- - !ruby/object:Gem::Dependency
34
- name: bundler
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '2'
40
- type: :development
41
- prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '2'
47
- - !ruby/object:Gem::Dependency
48
- name: rake
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '13'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '13'
61
- - !ruby/object:Gem::Dependency
62
- name: rspec
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '3'
68
- type: :development
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: '3'
75
- - !ruby/object:Gem::Dependency
76
- name: rubocop
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '1'
82
- type: :development
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: '1'
89
33
  description: '"Monitor operations, inspect your queries and publish your GraphQL schema
90
34
  with GraphQL Hive"'
91
35
  email:
@@ -112,6 +56,7 @@ files:
112
56
  - examples/simple-api/config.ru
113
57
  - examples/simple-api/schema.rb
114
58
  - graphql-hive.gemspec
59
+ - k6/README.md
115
60
  - k6/graphql-api/Gemfile
116
61
  - k6/graphql-api/Gemfile.lock
117
62
  - k6/graphql-api/app.rb
@@ -123,6 +68,7 @@ files:
123
68
  - k6/yarn.lock
124
69
  - lib/graphql-hive.rb
125
70
  - lib/graphql-hive/analyzer.rb
71
+ - lib/graphql-hive/bounded_queue.rb
126
72
  - lib/graphql-hive/client.rb
127
73
  - lib/graphql-hive/printer.rb
128
74
  - lib/graphql-hive/sampler.rb