graphql-hive 0.4.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,8 @@
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
6
 
7
7
  module GraphQL
8
8
  class Hive < GraphQL::Tracing::PlatformTracing
@@ -16,20 +16,19 @@ module GraphQL
16
16
 
17
17
  def initialize(options, client)
18
18
  @@instance = self
19
-
20
19
  @options = options
21
20
  @client = client
22
-
23
21
  @options_mutex = Mutex.new
24
- @queue = Queue.new
25
-
26
22
  @sampler = Sampler.new(options[:collect_usage_sampling], options[:logger]) # NOTE: logs for deprecated field
23
+ @queue = Thread::SizedQueue.new(options[:queue_size])
27
24
 
28
25
  start_thread
29
26
  end
30
27
 
31
28
  def add_operation(operation)
32
- @queue.push(operation)
29
+ @queue.push(operation, true)
30
+ rescue ThreadError
31
+ @options[:logger].error("SizedQueue is full, discarding operation. Size: #{@queue.size}, Max: #{@queue.max}")
33
32
  end
34
33
 
35
34
  def on_exit
@@ -45,30 +44,35 @@ module GraphQL
45
44
 
46
45
  def start_thread
47
46
  if @thread&.alive?
48
- @options[:logger].warn('Tried to start operations flushing thread but it was already alive')
47
+ @options[:logger].warn("Tried to start operations flushing thread but it was already alive")
49
48
  return
50
49
  end
51
50
 
52
51
  @thread = Thread.new do
53
52
  buffer = []
54
53
  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 = []
54
+ begin
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 = []
63
+ end
63
64
  end
65
+ rescue => e
66
+ buffer = []
67
+ @options[:logger].error(e)
64
68
  end
65
69
  end
66
70
 
67
71
  unless buffer.empty?
68
- @options[:logger].debug('shuting down with buffer, sending!')
72
+ @options[:logger].debug("shuting down with buffer, sending!")
69
73
  process_operations(buffer)
70
74
  end
71
- rescue StandardError => e
75
+ rescue => e
72
76
  # ensure configured logger receives exception as well in setups where STDERR might not be
73
77
  # monitored.
74
78
  @options[:logger].error(e)
@@ -88,7 +92,7 @@ module GraphQL
88
92
 
89
93
  @options[:logger].debug("sending report: #{report}")
90
94
 
91
- @client.send('/usage', report, :usage)
95
+ @client.send(:"/usage", report, :usage)
92
96
  end
93
97
 
94
98
  def add_operation_to_report(report, operation)
@@ -96,8 +100,8 @@ module GraphQL
96
100
 
97
101
  errors = errors_from_results(results)
98
102
 
99
- operation_name = queries.map(&:operations).map(&:keys).flatten.compact.join(', ')
100
- operation = ''
103
+ operation_name = queries.map(&:operations).map(&:keys).flatten.compact.join(", ")
104
+ operation = ""
101
105
  fields = Set.new
102
106
 
103
107
  queries.each do |query|
@@ -131,7 +135,7 @@ module GraphQL
131
135
 
132
136
  if results[0]
133
137
  context = results[0].query.context
134
- operation_record[:metadata] = { client: @options[:client_info].call(context) } if @options[:client_info]
138
+ operation_record[:metadata] = {client: @options[:client_info].call(context)} if @options[:client_info]
135
139
  end
136
140
 
137
141
  report[:map][operation_map_key] = {
@@ -144,9 +148,9 @@ module GraphQL
144
148
  end
145
149
 
146
150
  def errors_from_results(results)
147
- acc = { errorsTotal: 0 }
151
+ acc = {errorsTotal: 0}
148
152
  results.each do |result|
149
- errors = result.to_h.fetch('errors', [])
153
+ errors = result.to_h.fetch("errors", [])
150
154
  errors.each do
151
155
  acc[:errorsTotal] += 1
152
156
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Graphql
4
4
  module Hive
5
- VERSION = '0.4.2'
5
+ VERSION = "0.5.1"
6
6
  end
7
7
  end
data/lib/graphql-hive.rb CHANGED
@@ -1,15 +1,16 @@
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
+ require "graphql"
13
14
 
14
15
  module GraphQL
15
16
  # GraphQL Hive usage collector and schema reporter
@@ -31,24 +32,25 @@ module GraphQL
31
32
  DEFAULT_OPTIONS = {
32
33
  enabled: true,
33
34
  debug: false,
34
- port: '443',
35
+ port: "443",
35
36
  collect_usage: true,
36
37
  read_operations: true,
37
38
  report_schema: true,
38
39
  buffer_size: 50,
40
+ queue_size: 1000,
39
41
  logger: nil,
40
42
  collect_usage_sampling: 1.0
41
43
  }.freeze
42
44
 
43
45
  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'
46
+ "lex" => "lex",
47
+ "parse" => "parse",
48
+ "validate" => "validate",
49
+ "analyze_query" => "analyze_query",
50
+ "analyze_multiplex" => "analyze_multiplex",
51
+ "execute_multiplex" => "execute_multiplex",
52
+ "execute_query" => "execute_query",
53
+ "execute_query_lazy" => "execute_query_lazy"
52
54
  }
53
55
 
54
56
  def initialize(options = {})
@@ -84,7 +86,7 @@ module GraphQL
84
86
  def platform_trace(platform_key, _key, data)
85
87
  return yield unless @options[:enabled] && @options[:collect_usage]
86
88
 
87
- if platform_key == 'execute_multiplex'
89
+ if platform_key == "execute_multiplex"
88
90
  if data[:multiplex]
89
91
  queries = data[:multiplex].queries
90
92
  timestamp = (Time.now.utc.to_f * 1000).to_i
@@ -134,25 +136,26 @@ module GraphQL
134
136
  options[:logger] = Logger.new($stderr)
135
137
  original_formatter = Logger::Formatter.new
136
138
  options[:logger].formatter = proc { |severity, datetime, progname, msg|
137
- original_formatter.call(severity, datetime, progname, "[hive] #{msg.dump}")
139
+ msg = msg.respond_to?(:dump) ? msg.dump : msg
140
+ original_formatter.call(severity, datetime, progname, "[hive] #{msg}")
138
141
  }
139
142
  options[:logger].level = options[:debug] ? Logger::DEBUG : Logger::INFO
140
143
  end
141
144
  if !options.include?(:token) && (!options.include?(:enabled) || options.enabled)
142
- options[:logger].warn('`token` options is missing')
145
+ options[:logger].warn("`token` options is missing")
143
146
  options[:enabled] = false
144
147
  false
145
148
  elsif options[:report_schema] &&
149
+ (
150
+ !options.include?(:reporting) ||
146
151
  (
147
- !options.include?(:reporting) ||
148
- (
149
- options.include?(:reporting) && (
150
- !options[:reporting].include?(:author) || !options[:reporting].include?(:commit)
151
- )
152
+ options.include?(:reporting) && (
153
+ !options[:reporting].include?(:author) || !options[:reporting].include?(:commit)
152
154
  )
153
155
  )
156
+ )
154
157
 
155
- options[:logger].warn('`reporting.author` and `reporting.commit` options are required')
158
+ options[:logger].warn("`reporting.author` and `reporting.commit` options are required")
156
159
  false
157
160
  end
158
161
  true
@@ -167,7 +170,7 @@ module GraphQL
167
170
 
168
171
  body = {
169
172
  query: REPORT_SCHEMA_MUTATION,
170
- operationName: 'schemaPublish',
173
+ operationName: "schemaPublish",
171
174
  variables: {
172
175
  input: {
173
176
  sdl: sdl,
@@ -180,7 +183,7 @@ module GraphQL
180
183
  }
181
184
  }
182
185
 
183
- @client.send('/registry', body, :'report-schema')
186
+ @client.send(:"/registry", body, :"report-schema")
184
187
  end
185
188
  end
186
189
  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.2
4
+ version: 0.5.1
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-10-04 00:00:00.000000000 Z
11
+ date: 2024-11-05 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:
@@ -94,11 +38,11 @@ executables: []
94
38
  extensions: []
95
39
  extra_rdoc_files: []
96
40
  files:
97
- - ".github/workflows/benchmark.yml"
98
41
  - ".github/workflows/ci.yml"
99
42
  - ".gitignore"
100
43
  - ".rspec"
101
44
  - ".rubocop.yml"
45
+ - ".ruby-version"
102
46
  - Gemfile
103
47
  - Gemfile.lock
104
48
  - LICENSE
@@ -106,21 +50,7 @@ files:
106
50
  - RELEASING.md
107
51
  - Rakefile
108
52
  - cover.png
109
- - examples/simple-api/Gemfile
110
- - examples/simple-api/Gemfile.lock
111
- - examples/simple-api/app.rb
112
- - examples/simple-api/config.ru
113
- - examples/simple-api/schema.rb
114
53
  - graphql-hive.gemspec
115
- - k6/graphql-api/Gemfile
116
- - k6/graphql-api/Gemfile.lock
117
- - k6/graphql-api/app.rb
118
- - k6/graphql-api/config.ru
119
- - k6/graphql-api/schema.rb
120
- - k6/k6.js
121
- - k6/package.json
122
- - k6/usage-api.js
123
- - k6/yarn.lock
124
54
  - lib/graphql-hive.rb
125
55
  - lib/graphql-hive/analyzer.rb
126
56
  - lib/graphql-hive/client.rb
@@ -1,67 +0,0 @@
1
- name: Benchmark
2
- on:
3
- pull_request:
4
- branches:
5
- - master
6
-
7
- jobs:
8
- benchmarks:
9
- runs-on: ubuntu-latest
10
- steps:
11
- - name: Checkout Repository
12
- uses: actions/checkout@v4
13
-
14
- - name: Use Node
15
- uses: actions/setup-node@v4
16
- with:
17
- node-version: 22
18
- cache: 'yarn'
19
- cache-dependency-path: 'k6/yarn.lock'
20
-
21
- - name: Use Ruby
22
- uses: ruby/setup-ruby@2a9a743e19810b9f3c38060637daf594dbd7b37f
23
- with:
24
- working-directory: ./k6/graphql-api
25
- ruby-version: '3.3'
26
- bundler-cache: true
27
-
28
- - name: Start GraphQL API with hive enabled
29
- working-directory: ./k6/graphql-api
30
- run: |
31
- bundle
32
- bundle exec puma -t 0:1 -p 9292 &
33
- npx wait-on http://localhost:9292 --timeout 5s
34
- env:
35
- HIVE_ENABLED: 'true'
36
-
37
- - name: Start GraphQL API with hive disabled
38
- working-directory: ./k6/graphql-api
39
- run: |
40
- bundle
41
- bundle exec puma -t 0:1 -p 9291 &
42
- npx wait-on http://localhost:9291 --timeout 5s
43
- env:
44
- HIVE_ENABLED: 'false'
45
-
46
- - name: Start Fake Usage API
47
- working-directory: ./k6/
48
- run: |
49
- yarn
50
- node usage-api.js &
51
- npx wait-on http://localhost:8888 --timeout 5s
52
-
53
- - name: Install k6
54
- working-directory: ./k6
55
- env:
56
- K6_RELEASE_ARTIFACT_URL:
57
- https://github.com/grafana/k6/releases/download/v0.37.0/k6-v0.37.0-linux-amd64.tar.gz
58
- run: curl "${K6_RELEASE_ARTIFACT_URL}" -L | tar xvz --strip-components 1
59
-
60
- - name: Run Benchmark
61
- working-directory: ./k6
62
- run: |
63
- ./k6 \
64
- -e GITHUB_PR=${{ github.event.number }} \
65
- -e GITHUB_SHA=${{ github.sha }} \
66
- -e GITHUB_TOKEN=${{secrets.GH_PA_TOKEN}} \
67
- run k6.js
@@ -1,8 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'graphql'
4
- gem 'graphql-hive', path: '../../'
5
- gem 'puma'
6
- gem 'rack-contrib'
7
- gem 'sinatra'
8
- gem 'sinatra-contrib'
@@ -1,48 +0,0 @@
1
- PATH
2
- remote: ../..
3
- specs:
4
- graphql-hive (0.3.3)
5
- graphql (~> 2.0.9)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- graphql (2.0.9)
11
- multi_json (1.15.0)
12
- mustermann (1.1.1)
13
- ruby2_keywords (~> 0.0.1)
14
- nio4r (2.5.8)
15
- puma (5.6.4)
16
- nio4r (~> 2.0)
17
- rack (2.2.3.1)
18
- rack-contrib (2.3.0)
19
- rack (~> 2.0)
20
- rack-protection (2.2.0)
21
- rack
22
- ruby2_keywords (0.0.5)
23
- sinatra (2.2.0)
24
- mustermann (~> 1.0)
25
- rack (~> 2.2)
26
- rack-protection (= 2.2.0)
27
- tilt (~> 2.0)
28
- sinatra-contrib (2.2.0)
29
- multi_json
30
- mustermann (~> 1.0)
31
- rack-protection (= 2.2.0)
32
- sinatra (= 2.2.0)
33
- tilt (~> 2.0)
34
- tilt (2.0.10)
35
-
36
- PLATFORMS
37
- ruby
38
-
39
- DEPENDENCIES
40
- graphql
41
- graphql-hive!
42
- puma
43
- rack-contrib
44
- sinatra
45
- sinatra-contrib
46
-
47
- BUNDLED WITH
48
- 2.5.15
@@ -1,31 +0,0 @@
1
- require 'sinatra'
2
- require 'sinatra/json'
3
- require 'rack/contrib'
4
-
5
- require_relative 'schema'
6
-
7
- # Test query:
8
- #
9
- # query GetPost($input: [PostInput!]!) {
10
- # post(input: $input, test: TEST1) {
11
- # title
12
- # myId: id
13
- # }
14
- # }
15
-
16
- class DemoApp < Sinatra::Base
17
- use Rack::JSONBodyParser
18
-
19
- post '/graphql' do
20
- result = Schema.execute(
21
- params['query'],
22
- variables: params[:variables],
23
- operation_name: params[:operationName],
24
- context: {
25
- client_name: 'GraphQL Client',
26
- client_version: '1.0'
27
- }
28
- )
29
- json result
30
- end
31
- end
@@ -1,2 +0,0 @@
1
- require './app'
2
- run DemoApp
@@ -1,52 +0,0 @@
1
- require 'graphql'
2
- require 'graphql-hive'
3
-
4
- module Types
5
- class PostType < GraphQL::Schema::Object
6
- description 'A blog post'
7
- field :id, ID, null: false
8
- field :title, String, null: false
9
- # fields should be queried in camel-case (this will be `truncatedPreview`)
10
- field :truncated_preview, String, null: false
11
- end
12
- end
13
-
14
- class Types::PostInput < GraphQL::Schema::InputObject
15
- description 'Query Post arguments'
16
- argument :id, ID, required: true
17
- end
18
-
19
- class Types::TestEnum < GraphQL::Schema::Enum
20
- value 'TEST1'
21
- value 'TEST2'
22
- value 'TEST3'
23
- end
24
-
25
- class QueryType < GraphQL::Schema::Object
26
- description 'The query root of this schema'
27
-
28
- # First describe the field signature:
29
- field :post, Types::PostType, 'Find a post by ID' do
30
- argument :input, [Types::PostInput]
31
- argument :test, Types::TestEnum
32
- end
33
-
34
- # Then provide an implementation:
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' }
38
- end
39
- end
40
-
41
- class Schema < GraphQL::Schema
42
- query QueryType
43
-
44
- use(
45
- GraphQL::Hive,
46
- buffer_size: 2,
47
- token: 'YOUR_TOKEN',
48
- debug: true,
49
- reporting: { author: 'Charly Poly', commit: '109bb1e748bae21bdfe663c0ffc7e830' },
50
- client_info: proc { |context|{ name: context[:client_name], version: context[:client_version] }}
51
- )
52
- end
@@ -1,9 +0,0 @@
1
- source 'https://rubygems.org'
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'
@@ -1,52 +0,0 @@
1
- PATH
2
- remote: ../..
3
- specs:
4
- graphql-hive (0.4.2)
5
- graphql (>= 2.3, < 3)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- base64 (0.2.0)
11
- graphql (2.3.7)
12
- base64
13
- multi_json (1.15.0)
14
- mustermann (2.0.2)
15
- ruby2_keywords (~> 0.0.1)
16
- nio4r (2.7.3)
17
- puma (6.4.2)
18
- nio4r (~> 2.0)
19
- racc (1.8.0)
20
- rack (2.2.9)
21
- rack-contrib (2.5.0)
22
- rack (< 4)
23
- rack-protection (2.2.4)
24
- rack
25
- ruby2_keywords (0.0.5)
26
- sinatra (2.2.4)
27
- mustermann (~> 2.0)
28
- rack (~> 2.2)
29
- rack-protection (= 2.2.4)
30
- tilt (~> 2.0)
31
- sinatra-contrib (2.2.4)
32
- multi_json
33
- mustermann (~> 2.0)
34
- rack-protection (= 2.2.4)
35
- sinatra (= 2.2.4)
36
- tilt (~> 2.0)
37
- tilt (2.4.0)
38
-
39
- PLATFORMS
40
- ruby
41
-
42
- DEPENDENCIES
43
- graphql (~> 2)
44
- graphql-hive!
45
- puma (~> 6)
46
- racc
47
- rack-contrib (~> 2)
48
- sinatra (~> 2)
49
- sinatra-contrib
50
-
51
- BUNDLED WITH
52
- 2.5.15