fluent-plugin-calyptia-monitoring 0.1.0.rc9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e42e4240470d5d46bcf2d098699d82d1d0eb6440f88fd89ff004d7c79b5789f7
4
- data.tar.gz: 7f164695485c5202e003a31defc1b5a4022b67ed25ac71550011eb6400946f43
3
+ metadata.gz: d30951908ffe3e99416a83ed235545394503652e2052ff85423bbb2216d68c8c
4
+ data.tar.gz: c0d7fa6e044914592e8dc35bb88c3868e97d0344adf01640c2f517441e32bfc6
5
5
  SHA512:
6
- metadata.gz: ce39e348d421451fda13460ec7072d35e6e79df6c5bc74dfb48fb8f5d9237ff3c4a97bee8034d6e69ba76540b0c375b0cc599b78606b18adecb146a8b316d24a
7
- data.tar.gz: 171bf4f4c6230b68174aafb76d042059956f0404294157c06b6a763ffb4cd2d726fb93cf9dc9956aa598c12ed5cda1aebdba1fac0a8a7af293907d230e91ef18
6
+ metadata.gz: fe9a55bda096a86b3dd945a42d147da4cd39ace0a11c53ec8effeb70512334104fc2a22c9b853c4fd4a8dd5691a1a0139c7a6a16f2b0029d1bf4b8d98397ecb4
7
+ data.tar.gz: 7274a5ad7cce4240861e71e480b3706c2b43b782abcfc7c5173ff10a9f3ee22810cba67d31521c54e29c0e414b4cc08f858f1dba11aeb92c939f8663519f3ca0
data/README.md CHANGED
@@ -40,10 +40,11 @@ $ bundle
40
40
 
41
41
  |parameter|type|description|default|
42
42
  |---|---|---|---|
43
- |endpoint|string (optional)|The endpoint for Monitoring API HTTP request, e.g. http://example.com/api|`TBD`|
43
+ |endpoint|string (optional)|The endpoint for Monitoring API HTTP request, e.g. http://example.com/api|`"https://cloud-api.calyptia.com"`|
44
44
  |api_key|string (required)|The API KEY for Monitoring API HTTP request||
45
45
  |rate|time (optional)|Emit monitoring values interval. (minimum interval is 30 seconds.)|`30`|
46
46
  |pending_metrics_size|size (optional)|Setup pending metrics capacity size|`100`|
47
+ |fluentd_conf_path|string (optional)|Specify Fluentd config file path for RPC not to be available case|`nil`|
47
48
 
48
49
  ### Example
49
50
 
@@ -84,6 +85,44 @@ And enabling RPC and configDump endpoint is required if sending Fluentd configur
84
85
  </source>
85
86
  ```
86
87
 
88
+ And also retrieving configuration from actual file is also supported:
89
+
90
+ ```aconf
91
+ <system>
92
+ # If users want to use multi workers feature which corresponds to logical number of CPUs, please comment out this line.
93
+ # workers "#{require 'etc'; Etc.nprocessors}"
94
+ enable_input_metrics true
95
+ # This record size measuring settings might impact for performance.
96
+ # Please be careful for high loaded environment to turn on.
97
+ enable_size_metrics true
98
+ <metrics>
99
+ @type cmetrics
100
+ </metrics>
101
+ </system>
102
+ # And other configurations....
103
+
104
+ ## Fill YOUR_API_KEY with your Calyptia API KEY
105
+ <source>
106
+ @type calyptia_monitoring
107
+ @id input_caplyptia_moniroting
108
+ <cloud_monitoring>
109
+ # endpoint http://development-environment-or-production.fqdn:5000
110
+ api_key YOUR_API_KEY
111
+ rate 30
112
+ pending_metrics_size 100 # Specify capacity for pending metrics
113
+ fluentd_conf_path /path/to/fluent.conf
114
+ </cloud_monitoring>
115
+ <storage>
116
+ @type local
117
+ path /path/to/agent/accessible/directories/agent_states
118
+ </storage>
119
+ </source>
120
+ ```
121
+
122
+ **Note:** We recommend to use RPC version due to some circumstances should differ between a loaded configuration and a saved Fluentd configuration.
123
+ This is because calling dumping config RPC feature can obtain from configuration contents which are loaded on memory. But retrieving configuration from the specified file is just read from the file contents and it cannot handle/retrieve loaded configurations on Fluentd.
124
+ When users just update their Fluentd configurations and forgot to restart/reload their Fluentd instances, loaded configurations differ from just edited ones.
125
+
87
126
  ## Calyptia Monitoring API config generator
88
127
 
89
128
  Usage:
@@ -104,10 +143,12 @@ Options:
104
143
  --disable-get-dump Disable RPC getDump procedure. getDump is enabled by default.
105
144
  --storage-agent-token-dir DIR
106
145
  Specify accesible storage token dir. (default: /path/to/accesible/dir)
146
+ --fluentd-conf-path PATH Specify fluentd configuration file path. (default: nil)
107
147
  ```
108
148
 
109
149
  ## Copyright
110
150
 
111
- * Copyright(c) 2021- Hiroshi Hatake
151
+ * Copyright(c) 2021- Calyptia Inc.
152
+ * Maintainer: Hiroshi Hatake <hatake@calyptia.com>
112
153
  * License
113
154
  * Apache License, Version 2.0
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = "fluent-plugin-calyptia-monitoring"
6
- spec.version = "0.1.0.rc9"
6
+ spec.version = "0.1.0"
7
7
  spec.authors = ["Hiroshi Hatake"]
8
8
  spec.email = ["hatake@calyptia.com"]
9
9
 
@@ -23,6 +23,6 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 2.2.15"
24
24
  spec.add_development_dependency "rake", "~> 13.0"
25
25
  spec.add_development_dependency "test-unit", "~> 3.3"
26
- spec.add_runtime_dependency "fluentd", [">= 1.14.0.rc", "< 2"]
26
+ spec.add_runtime_dependency "fluentd", [">= 1.14.0", "< 2"]
27
27
  spec.add_runtime_dependency "fluent-plugin-metrics-cmetrics", ">= 0.1.0.rc3"
28
28
  end
@@ -33,6 +33,8 @@ class CalyptiaConfigGenerator
33
33
  @enable_get_dump = true
34
34
  @rpc_endpoint = "127.0.0.1:24444"
35
35
  @storage_agent_token_dir = default_storage_dir
36
+ @fluentd_conf_path = nil
37
+ @disable_rpc = false
36
38
 
37
39
  prepare_option_parser
38
40
  end
@@ -96,6 +98,10 @@ BANNER
96
98
  @parser.on("--storage-agent-token-dir DIR", "Specify accesible storage token dir. (default: #{default_storage_dir})") do |s|
97
99
  @storage_agent_token_dir = s
98
100
  end
101
+ @parser.on("--fluentd-conf-path PATH", "Specify fluentd configuration file path. (default: nil)") do |s|
102
+ @fluentd_conf_path = s
103
+ @disable_rpc = true
104
+ end
99
105
  end
100
106
 
101
107
  def usage(message = nil)
@@ -125,6 +131,8 @@ BANNER
125
131
  size_metrics: @enable_size_metrics,
126
132
  enable_get_dump: @enable_get_dump,
127
133
  storage_agent_token_dir: @storage_agent_token_dir,
134
+ fluentd_conf_path: @fluentd_conf_path,
135
+ disable_rpc: @disable_rpc,
128
136
  }
129
137
  rescue => e
130
138
  usage(e)
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fluent/env'
4
+ require 'fluent/engine'
5
+ require 'fluent/log'
6
+ require 'fluent/config'
7
+ require 'fluent/configurable'
8
+ require 'fluent/system_config'
9
+ require 'fluent/config/element'
10
+ require 'serverengine'
11
+ require 'stringio'
12
+
13
+ include Fluent::Configurable
14
+
15
+ def init_log
16
+ dl_opts = {}
17
+ dl_opts[:log_level] = ServerEngine::DaemonLogger::WARN
18
+ @sio = StringIO.new('', 'r+')
19
+ logger = ServerEngine::DaemonLogger.new(@sio, dl_opts)
20
+ $log = Fluent::Log.new(logger)
21
+ end
22
+
23
+ init_log
24
+
25
+ File.open(ENV["FLUENT_CONFIG_PATH"], "r") do |f|
26
+ config = Fluent::Config.parse(f.read, '(supervisor)', '(readFromFile)', true)
27
+ system_config = Fluent::SystemConfig.create(config)
28
+ Fluent::Engine.init(system_config, supervisor_mode: true)
29
+ Fluent::Engine.run_configure(config, dry_run: true)
30
+ confs = []
31
+ masked_element = config.to_masked_element
32
+ masked_element.elements.each{|e|
33
+ confs << e.to_s
34
+ }
35
+ puts confs.join
36
+ end
@@ -0,0 +1,87 @@
1
+ #
2
+ # fluent-plugin-calyptia-monitoring
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'fluent/plugin/in_monitor_agent'
17
+
18
+ module Fluent::Plugin
19
+ class CalyptiaMonitoringBufferExtInput < MonitorAgentInput
20
+ CALYPTIA_PLUGIN_BUFFER_METRIC_INFO = {
21
+ 'buffer_total_queued_size' => ->() {
22
+ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
23
+ @buffer.total_queued_size_metrics.cmetrics.to_msgpack
24
+ },
25
+ 'buffer_stage_length' => ->() {
26
+ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
27
+ @buffer.stage_length_metrics.cmetrics.to_msgpack
28
+ },
29
+ 'buffer_stage_byte_size' => ->() {
30
+ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
31
+ @buffer.stage_size_metrics.cmetrics.to_msgpack
32
+ },
33
+ 'buffer_queue_length' => ->() {
34
+ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
35
+ @buffer.queue_length_metrics.cmetrics.to_msgpack
36
+ },
37
+ 'buffer_queue_byte_size' => ->() {
38
+ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
39
+ @buffer.queue_size_metrics.cmetrics.to_msgpack
40
+ },
41
+ 'available_buffer_space_ratios' => ->() {
42
+ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
43
+ @buffer.available_buffer_space_ratios_metrics.cmetrics.to_msgpack
44
+ },
45
+ 'newest_timekey' => ->() {
46
+ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
47
+ @buffer.newest_timekey_metrics.cmetrics.to_msgpack
48
+ },
49
+ 'oldest_timekey' => ->() {
50
+ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
51
+ @buffer.oldest_timekey_metrics.cmetrics.to_msgpack
52
+ },
53
+ }
54
+
55
+ def get_monitor_info(pe, opts = {})
56
+ obj = {}
57
+
58
+ obj['metrics'] = get_plugin_metric(pe)
59
+
60
+ obj
61
+ end
62
+
63
+ def get_plugin_metric(pe)
64
+ # Nop for non output plugin
65
+ return {} if plugin_category(pe) != "output"
66
+
67
+ metrics = {}
68
+
69
+ if pe.respond_to?(:statistics)
70
+ # Force to update buffers' metrics values
71
+ pe.statistics
72
+ end
73
+
74
+ CALYPTIA_PLUGIN_BUFFER_METRIC_INFO.each_pair { |key, code|
75
+ begin
76
+ v = pe.instance_exec(&code)
77
+ unless v.nil?
78
+ metrics[key] = v
79
+ end
80
+ rescue
81
+ end
82
+ }
83
+
84
+ metrics
85
+ end
86
+ end
87
+ end
@@ -27,9 +27,25 @@ module Fluent::Plugin
27
27
  @emit_records_metrics.cmetrics.to_msgpack
28
28
  },
29
29
  'retry_count' => ->(){
30
- throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer)
30
+ throw(:skip) if @num_errors_metrics.get.nil?
31
31
  @num_errors_metrics.cmetrics.to_msgpack
32
32
  },
33
+ 'write_count' => ->(){
34
+ throw(:skip) if @write_count_metrics.get.nil?
35
+ @write_count_metrics.cmetrics.to_msgpack
36
+ },
37
+ 'rollback_count' => ->(){
38
+ throw(:skip) if @rollback_count_metrics.get.nil?
39
+ @rollback_count_metrics.cmetrics.to_msgpack
40
+ },
41
+ 'flush_time_count' => ->(){
42
+ throw(:skip) if @flush_time_count_metrics.get.nil?
43
+ @flush_time_count_metrics.cmetrics.to_msgpack
44
+ },
45
+ 'slow_flush_count' => ->(){
46
+ throw(:skip) if @slow_flush_count_metrics.get.nil?
47
+ @slow_flush_count_metrics.cmetrics.to_msgpack
48
+ },
33
49
  }
34
50
 
35
51
  def get_monitor_info(pe, opts = {})
@@ -17,10 +17,11 @@ require 'net/http'
17
17
  require 'monitor'
18
18
  require 'time'
19
19
  require 'fluent/version'
20
- require 'fluent/config/element'
21
- require 'fluent/plugin/metrics'
20
+ require 'fluent/env'
22
21
  require "fluent/plugin/input"
22
+ require "serverengine"
23
23
  require_relative "calyptia_monitoring_ext"
24
+ require_relative "calyptia_monitoring_buffer_ext"
24
25
  require_relative "calyptia_monitoring_calyptia_api_requester"
25
26
 
26
27
  module Fluent
@@ -31,7 +32,7 @@ module Fluent
31
32
  class CreateAgentError < Fluent::ConfigError; end
32
33
  class UpdateAgentError < Fluent::ConfigError; end
33
34
 
34
- helpers :timer, :storage
35
+ helpers :timer, :storage, :child_process
35
36
 
36
37
  RPC_CONFIG_DUMP_ENDPOINT = "/api/config.getDump".freeze
37
38
  DEFAULT_STORAGE_TYPE = 'local'
@@ -52,6 +53,8 @@ module Fluent
52
53
  config_param :rate, :time, default: 30
53
54
  desc 'Setup pending metrics capacity size'
54
55
  config_param :pending_metrics_size, :size, default: DEFAULT_PENDING_METRICS_SIZE
56
+ desc 'Specify Fluentd config file path for RPC not to be available case'
57
+ config_param :fluentd_conf_path, :string, default: nil
55
58
  end
56
59
 
57
60
  def multi_workers_ready?
@@ -67,6 +70,7 @@ module Fluent
67
70
 
68
71
  def configure(conf)
69
72
  super
73
+
70
74
  config = conf.elements.select{|e| e.name == 'storage' }.first
71
75
  @storage_agent = storage_create(usage: 'calyptia_monitoring_agent', conf: config, default_type: DEFAULT_STORAGE_TYPE)
72
76
  end
@@ -83,6 +87,43 @@ module Fluent
83
87
  confs.join
84
88
  end
85
89
 
90
+ def get_masked_conf_from_conf_file
91
+ return "" unless File.exist?(@cloud_monitoring.fluentd_conf_path) # check file existence.
92
+
93
+ conf = ""
94
+ callback = ->(status) {
95
+ if status && status.success?
96
+ #nop
97
+ elsif status
98
+ log.warn "config dumper exits with error code", prog: prog, status: status.exitstatus, signal: status.termsig
99
+ else
100
+ log.warn "config dumper unexpectedly exits without exit status", prog: prog
101
+ end
102
+ }
103
+ spawn_command, arguments = if Fluent.windows?
104
+ [::ServerEngine.ruby_bin_path, File.join(File.dirname(__FILE__), "calyptia_config_dumper.rb")]
105
+ else
106
+ [File.join(File.dirname(__FILE__), "calyptia_config_dumper.rb")]
107
+ end
108
+
109
+ retval = child_process_execute(:exec_calyptia_config_dumper, spawn_command, arguments: arguments, immediate: true,
110
+ env: {"FLUENT_CONFIG_PATH" => @cloud_monitoring.fluentd_conf_path}, parallel: true, mode: [:read_with_stderr],
111
+ on_exit_callback: callback) do |io|
112
+ io.set_encoding(Encoding::ASCII_8BIT)
113
+ conf = io.read
114
+ end
115
+ unless retval.nil?
116
+ begin
117
+ Timeout.timeout(10) do
118
+ sleep 0.1 until !conf.empty?
119
+ end
120
+ rescue Timeout::Error
121
+ log.warn "cannot retrive configuration contents on #{@cloud_monitoring.fluentd_conf_path} within 10 seconds."
122
+ end
123
+ end
124
+ conf
125
+ end
126
+
86
127
  def start
87
128
  super
88
129
 
@@ -93,13 +134,16 @@ module Fluent
93
134
  end
94
135
  raise Fluent::ConfigError, "cmetrics plugin should be used to collect metrics on Calyptia Cloud" unless enabled_cmetrics
95
136
  @monitor_agent = Fluent::Plugin::CalyptiaMonitoringExtInput.new
137
+ @monitor_agent_buffer = Fluent::Plugin::CalyptiaMonitoringBufferExtInput.new
96
138
  @api_requester = Fluent::Plugin::CalyptiaAPI::Requester.new(@cloud_monitoring.endpoint,
97
139
  @cloud_monitoring.api_key,
98
140
  log,
99
141
  fluentd_worker_id)
100
- if check_config_sending_usability
101
- @current_config = get_current_config_from_rpc
102
- end
142
+ @current_config = if !@cloud_monitoring.fluentd_conf_path.nil?
143
+ get_masked_conf_from_conf_file
144
+ elsif check_config_sending_usability
145
+ get_current_config_from_rpc
146
+ end
103
147
 
104
148
  if @cloud_monitoring.rate < 30
105
149
  log.warn "High frequency events ingestion is not supported. Set up 30s as ingestion interval"
@@ -222,6 +266,12 @@ module Fluent
222
266
  buffer += v
223
267
  end
224
268
  }
269
+ @monitor_agent_buffer.plugins_info_all(opts).each {|record|
270
+ metrics = record["metrics"]
271
+ metrics.each_pair do |k, v|
272
+ buffer += v
273
+ end
274
+ }
225
275
  if buffer.empty?
226
276
  log.debug "No initialized metrics is found. Trying to send cmetrics on the next tick."
227
277
  else
@@ -4,8 +4,10 @@
4
4
  </metrics>
5
5
  enable_input_metrics <%= @enable_input_metrics %>
6
6
  enable_size_metrics <%= @enable_size_metrics %>
7
+ <%- unless @disable_rpc -%>
7
8
  rpc_endpoint <%= @rpc_endpoint %>
8
9
  enable_get_dump <%= @enable_get_dump %>
10
+ <%- end -%>
9
11
  <system>
10
12
  <source>
11
13
  @type calyptia_monitoring
@@ -15,6 +17,9 @@
15
17
  endpoint <%= @endpoint %>
16
18
  <%- end -%>
17
19
  api_key <%= @api_key %>
20
+ <%- if @fluentd_conf_path -%>
21
+ fluentd_conf_path <%= @fluentd_conf_path %>
22
+ <%- end -%>
18
23
  </cloud_monitoring>
19
24
  <storage>
20
25
  @type local
@@ -192,6 +192,37 @@ TEXT
192
192
  path #{storage_dir}/agent_state
193
193
  </storage>
194
194
  </source>
195
+ TEXT
196
+ assert_equal(expected, dumped_config)
197
+ end
198
+
199
+ test "with api_key and fluentd_config_path" do
200
+ storage_dir = Dir.tmpdir
201
+ conf_dir = Dir.tmpdir
202
+ conf_path = File.join(conf_dir, "fluent.conf")
203
+ dumped_config = capture_stdout do
204
+ CalyptiaConfigGenerator.new(["YOUR_API_KEY", "--storage_agent_token_dir", storage_dir, "--fluentd-conf-path", conf_path]).call
205
+ end
206
+ expected =<<TEXT
207
+ <system>
208
+ <metrics>
209
+ @type cmetrics
210
+ </metrics>
211
+ enable_input_metrics true
212
+ enable_size_metrics false
213
+ <system>
214
+ <source>
215
+ @type calyptia_monitoring
216
+ @id input_caplyptia_monitoring
217
+ <cloud_monitoring>
218
+ api_key YOUR_API_KEY
219
+ fluentd_conf_path #{conf_path}
220
+ </cloud_monitoring>
221
+ <storage>
222
+ @type local
223
+ path #{storage_dir}/agent_state
224
+ </storage>
225
+ </source>
195
226
  TEXT
196
227
  assert_equal(expected, dumped_config)
197
228
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-calyptia-monitoring
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.rc9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroshi Hatake
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-17 00:00:00.000000000 Z
11
+ date: 2021-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,7 +58,7 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 1.14.0.rc
61
+ version: 1.14.0
62
62
  - - "<"
63
63
  - !ruby/object:Gem::Version
64
64
  version: '2'
@@ -68,7 +68,7 @@ dependencies:
68
68
  requirements:
69
69
  - - ">="
70
70
  - !ruby/object:Gem::Version
71
- version: 1.14.0.rc
71
+ version: 1.14.0
72
72
  - - "<"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '2'
@@ -102,6 +102,8 @@ files:
102
102
  - bin/calyptia-config-generator
103
103
  - fluent-plugin-calyptia-monitoring.gemspec
104
104
  - lib/fluent/command/config_generator.rb
105
+ - lib/fluent/plugin/calyptia_config_dumper.rb
106
+ - lib/fluent/plugin/calyptia_monitoring_buffer_ext.rb
105
107
  - lib/fluent/plugin/calyptia_monitoring_calyptia_api_requester.rb
106
108
  - lib/fluent/plugin/calyptia_monitoring_ext.rb
107
109
  - lib/fluent/plugin/calyptia_monitoring_machine_id.rb
@@ -127,9 +129,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
129
  version: '0'
128
130
  required_rubygems_version: !ruby/object:Gem::Requirement
129
131
  requirements:
130
- - - ">"
132
+ - - ">="
131
133
  - !ruby/object:Gem::Version
132
- version: 1.3.1
134
+ version: '0'
133
135
  requirements: []
134
136
  rubygems_version: 3.2.22
135
137
  signing_key: