pyroscope 0.3.2-x86_64-darwin → 0.5.1-x86_64-darwin

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: 04463bc7a3a932eef056c8d20e677b042fc921b5df2df4296279fd34c7dc9bfd
4
- data.tar.gz: 4fa8c6865eea79b89781600691c06c63a1160a66b7d4815881fc4ae4be37c622
3
+ metadata.gz: 9cb87b3d680d036992d9e4dc5c24623005acfc2025ec4578b3d87f62af60eef1
4
+ data.tar.gz: bf83c8dd6257c99e2a9e6bb288a446bbbddbc3b322ab4fed8a81b7a9422bf54f
5
5
  SHA512:
6
- metadata.gz: 6b23669db4195412878522947572126877e33fa0596f24086efdd80b2ad6f46874520ea3201687a78d1f1da8093ad77493eb0b0390ad5a4aeab7cdd280866c5c
7
- data.tar.gz: 4bdbccad469ba8adf06b181b60544faa04b634d9bfeedce3c048ca54fd6aa645a460cf2b79abd4f307353fa79f02ffcdc9ed69cce545c1bfa91813fc13b3b191
6
+ metadata.gz: 78b08c983b3e61158df1a9b8cf80ae79c4f947d10d6b868bf9f8d8c600f1d2c6112783ebe0b2d7c3412bc731fdb0a121170c2abc73981337e1487d2ccbe7c603
7
+ data.tar.gz: df6ea2ce9a7aeea50718f47ed8feada39324fea35e56bcfd59608d673832ea825077bcc793fee507cb7edf641dd9e272e71e91554a7f52807aacce58e099fd5d
data/README.md CHANGED
@@ -1,57 +1,71 @@
1
- Pyroscope Ruby Integration --Beta--
2
- =====================================
1
+ # Pyroscope Ruby Gem
3
2
 
4
- **note**: This is a beta release. It requires local compilation, might be
5
- buggy and is frequently updated. For the initial implementation, find it [here](https://github.com/pyroscope-io/pyroscope-ruby). Please report any [issues](https://github.com/pyroscope-io/pyroscope-rs/issues).
3
+ **Pyroscope integration for Ruby**
6
4
 
7
- ## Installation
5
+ [![license](https://img.shields.io/badge/license-Apache2.0-blue.svg)](LICENSE)
6
+ ![tests](https://github.com/pyroscope-io/pyroscope-rs/workflows/Tests/badge.svg)
7
+ ![build](https://github.com/pyroscope-io/pyroscope-rs/workflows/Build/badge.svg)
8
+ [![Gem version](https://badge.fury.io/rb/pyroscope.svg)](https://badge.fury.io/rb/pyroscope)
8
9
 
9
- 1. You need the Rust toolchain to compile the library locally. To install
10
- Rust:
10
+ ---
11
11
 
12
- ```
13
- curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y
14
- export PATH=$PATH:/root/.cargo/bin
15
- ```
12
+ ### What is Pyroscope
13
+ [Pyroscope](https://github.com/pyroscope-io/pyroscope) is a tool that lets you continuously profile your applications to prevent and debug performance issues in your code. It consists of a low-overhead agent which sends data to the Pyroscope server which includes a custom-built storage engine. This allows for you to store and query any applications profiling data in an extremely efficient and cost effective way.
16
14
 
17
- 2. Building/Insalling from Rubygems
18
15
 
19
- ```
20
- gem install pyroscope_beta
21
- ```
16
+ ### Supported platforms
22
17
 
23
- 3. Building/Installing from source
18
+ | Linux | macOS | Windows | Docker |
19
+ |:-----:|:-----:|:-------:|:------:|
20
+ | ✅ | ✅ | | ✅ |
24
21
 
25
- Change directory to `pyroscope_ffi/ruby` and run
22
+ ### Profiling Ruby applications
26
23
 
24
+ Add the `pyroscope` gem to your Gemfile:
25
+
26
+ ```bash
27
+ bundle add pyroscope
27
28
  ```
28
- gem build pyroscope.gemspec
29
- gem install ./pyroscope.gemspec
30
- ```
31
29
 
32
- ## Configuration
30
+ ### Basic Configuration
31
+
32
+ Add the following code to your application. If you're using rails, put this into `config/initializers` directory. This code will initialize pyroscope profiler and start profiling:
33
33
 
34
- Configuration is similar to the old package except for `application_name`:
34
+ ```ruby
35
+ require 'pyroscope'
35
36
 
37
+ Pyroscope.configure do |config|
38
+ config.application_name = "my.ruby.app" # replace this with some name for your application
39
+ config.server_address = "http://my-pyroscope-server:4040" # replace this with the address of your pyroscope server
40
+ # config.auth_token = "{YOUR_API_KEY}" # optionally, if authentication is enabled, specify the API key
41
+ end
36
42
  ```
37
- require 'pyroscope_beta'
43
+
44
+ ### Tags
45
+
46
+ Pyroscope ruby integration provides a number of ways to tag profiling data. For example, you can provide tags when you're initializing the profiler:
47
+
48
+ ```ruby
49
+ require 'pyroscope'
38
50
 
39
51
  Pyroscope.configure do |config|
40
- config.application_name = "ruby.app"
41
- config.server_address = "http://localhost:4040"
42
- config.detect_subprocesses = true
52
+ config.application_name = "my.ruby.app"
53
+ config.server_address = "http://my-pyroscope-server:4040"
54
+
43
55
  config.tags = {
44
- :key => "value",
56
+ "hostname" => ENV["HOSTNAME"],
45
57
  }
46
58
  end
47
59
  ```
48
60
 
49
- ## Adding tags
61
+ or you can dynamically tag certain parts of your code:
50
62
 
51
- Tags passed to configure are global. To tag code locally, you can use:
52
-
53
- ```
54
- Pyroscope.tag_wrapper({"profile": "profile-1"}) do
55
- // Tagged profile
63
+ ```ruby
64
+ Pyroscope.tag_wrapper({ "controller": "slow_controller_i_want_to_profile" }) do
65
+ slow_code
56
66
  end
57
67
  ```
68
+
69
+ ### Example
70
+
71
+ Check out this [example ruby project in our repository](https://github.com/pyroscope-io/pyroscope/tree/main/examples/ruby) for examples of how you can use these features.
data/ext/rbspy/src/lib.rs CHANGED
@@ -1,12 +1,16 @@
1
- use ffikit::Signal;
2
- use pyroscope::backend::{Report, StackFrame, Tag};
3
- use pyroscope::PyroscopeAgent;
4
- use pyroscope_rbspy::{rbspy_backend, RbspyConfig};
5
1
  use std::collections::hash_map::DefaultHasher;
2
+ use std::env;
6
3
  use std::ffi::CStr;
7
4
  use std::hash::Hasher;
8
5
  use std::os::raw::c_char;
9
- use std::env;
6
+ use std::str::FromStr;
7
+
8
+ use ffikit::Signal;
9
+ use pyroscope_rbspy::{rbspy_backend, RbspyConfig};
10
+
11
+ use pyroscope::{pyroscope::Compression, PyroscopeAgent};
12
+ use pyroscope::backend::{Report, StackFrame, Tag};
13
+ use pyroscope::pyroscope::ReportEncoding;
10
14
 
11
15
  pub fn transform_report(report: Report) -> Report {
12
16
  let cwd = env::current_dir().unwrap();
@@ -24,31 +28,25 @@ pub fn transform_report(report: Report) -> Report {
24
28
  let mut s = frame.filename.unwrap();
25
29
  match s.find(cwd) {
26
30
  Some(i) => {
27
- s = s[(i+cwd.len()+1)..].to_string();
31
+ s = s[(i + cwd.len() + 1)..].to_string();
28
32
  }
29
- None => {
30
- match s.find("/gems/") {
33
+ None => match s.find("/gems/") {
34
+ Some(i) => {
35
+ s = s[(i + 1)..].to_string();
36
+ }
37
+ None => match s.find("/ruby/") {
31
38
  Some(i) => {
32
- s = s[(i+1)..].to_string();
33
- }
34
- None => {
35
- match s.find("/ruby/") {
39
+ s = s[(i + 6)..].to_string();
40
+ match s.find("/") {
36
41
  Some(i) => {
37
- s = s[(i+6)..].to_string();
38
- match s.find("/") {
39
- Some(i) => {
40
- s = s[(i+1)..].to_string();
41
- }
42
- None => {
43
- }
44
- }
45
- }
46
- None => {
42
+ s = s[(i + 1)..].to_string();
47
43
  }
44
+ None => {}
48
45
  }
49
46
  }
50
- }
51
- }
47
+ None => {}
48
+ },
49
+ },
52
50
  }
53
51
 
54
52
  // something
@@ -76,11 +74,42 @@ pub fn transform_report(report: Report) -> Report {
76
74
  new_report
77
75
  }
78
76
 
77
+ #[no_mangle]
78
+ pub extern "C" fn initialize_logging(logging_level: u32) -> bool {
79
+ // Force rustc to display the log messages in the console.
80
+ match logging_level {
81
+ 50 => {
82
+ std::env::set_var("RUST_LOG", "error");
83
+ }
84
+ 40 => {
85
+ std::env::set_var("RUST_LOG", "warn");
86
+ }
87
+ 30 => {
88
+ std::env::set_var("RUST_LOG", "info");
89
+ }
90
+ 20 => {
91
+ std::env::set_var("RUST_LOG", "debug");
92
+ }
93
+ 10 => {
94
+ std::env::set_var("RUST_LOG", "trace");
95
+ }
96
+ _ => {
97
+ std::env::set_var("RUST_LOG", "debug");
98
+ }
99
+ }
100
+
101
+ // Initialize the logger.
102
+ pretty_env_logger::init_timed();
103
+
104
+ true
105
+ }
106
+
79
107
  #[no_mangle]
80
108
  pub extern "C" fn initialize_agent(
81
109
  application_name: *const c_char, server_address: *const c_char, auth_token: *const c_char,
82
- sample_rate: u32, detect_subprocesses: bool, on_cpu: bool, report_pid: bool,
83
- report_thread_id: bool, tags: *const c_char,
110
+ sample_rate: u32, detect_subprocesses: bool, oncpu: bool, report_pid: bool,
111
+ report_thread_id: bool, tags: *const c_char, compression: *const c_char,
112
+ report_encoding: *const c_char
84
113
  ) -> bool {
85
114
  // Initialize FFIKit
86
115
  let recv = ffikit::initialize_ffi().unwrap();
@@ -105,13 +134,27 @@ pub extern "C" fn initialize_agent(
105
134
  .unwrap()
106
135
  .to_string();
107
136
 
137
+ let compression_string = unsafe { CStr::from_ptr(compression) }
138
+ .to_str()
139
+ .unwrap()
140
+ .to_string();
141
+
142
+ let report_encoding = unsafe { CStr::from_ptr(report_encoding) }
143
+ .to_str()
144
+ .unwrap()
145
+ .to_string();
146
+
147
+ let compression = Compression::from_str(&compression_string);
148
+ let report_encoding = ReportEncoding::from_str(&report_encoding)
149
+ .unwrap_or(ReportEncoding::FOLDED);
150
+
108
151
  let pid = std::process::id();
109
152
 
110
153
  let rbspy_config = RbspyConfig::new(pid.try_into().unwrap())
111
154
  .sample_rate(sample_rate)
112
155
  .lock_process(false)
113
- .with_subprocesses(detect_subprocesses)
114
- .on_cpu(on_cpu)
156
+ .detect_subprocesses(detect_subprocesses)
157
+ .oncpu(oncpu)
115
158
  .report_pid(report_pid)
116
159
  .report_thread_id(report_thread_id);
117
160
 
@@ -122,12 +165,17 @@ pub extern "C" fn initialize_agent(
122
165
  let mut agent_builder = PyroscopeAgent::builder(server_address, application_name)
123
166
  .backend(rbspy)
124
167
  .func(transform_report)
125
- .tags(tags);
168
+ .tags(tags)
169
+ .report_encoding(report_encoding);
126
170
 
127
171
  if auth_token != "" {
128
172
  agent_builder = agent_builder.auth_token(auth_token);
129
173
  }
130
174
 
175
+ if let Ok(compression) = compression {
176
+ agent_builder = agent_builder.compression(compression);
177
+ }
178
+
131
179
  let agent = agent_builder.build().unwrap();
132
180
 
133
181
  let agent_running = agent.start().unwrap();
@@ -1,3 +1,3 @@
1
1
  module Pyroscope
2
- VERSION = '0.3.2'.freeze
2
+ VERSION = '0.5.1'.freeze
3
3
  end
data/lib/pyroscope.rb CHANGED
@@ -1,10 +1,14 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  require 'ffi'
2
5
 
3
6
  module Pyroscope
4
7
  module Rust
5
8
  extend FFI::Library
6
9
  ffi_lib File.expand_path(File.dirname(__FILE__)) + "/rbspy/rbspy.#{RbConfig::CONFIG["DLEXT"]}"
7
- attach_function :initialize_agent, [:string, :string, :string, :int, :bool, :bool, :bool, :bool, :string], :bool
10
+ attach_function :initialize_logging, [:int], :bool
11
+ attach_function :initialize_agent, [:string, :string, :string, :int, :bool, :bool, :bool, :bool, :string, :string, :string], :bool
8
12
  attach_function :add_thread_tag, [:uint64, :string, :string], :bool
9
13
  attach_function :remove_thread_tag, [:uint64, :string, :string], :bool
10
14
  attach_function :add_global_tag, [:string, :string], :bool
@@ -18,42 +22,107 @@ module Pyroscope
18
22
  attach_function :thread_id, [], :uint64
19
23
  end
20
24
 
21
- Config = Struct.new(:application_name, :app_name, :server_address, :auth_token, :sample_rate, :detect_subprocesses, :on_cpu, :report_pid, :report_thread_id, :log_level, :tags) do
25
+ if defined?(::Rails::Engine)
26
+ class Engine < ::Rails::Engine
27
+ config.after_initialize do
28
+ next unless ::Pyroscope.current_config && ::Pyroscope.current_config.autoinstrument_rails
29
+
30
+ ::Pyroscope.initialize_rails_hooks
31
+ end
32
+ end
33
+ end
34
+
35
+ Config = Struct.new(
36
+ :application_name,
37
+ :app_name,
38
+ :server_address,
39
+ :auth_token,
40
+ :log_level,
41
+ :sample_rate,
42
+ :detect_subprocesses,
43
+ :oncpu,
44
+ :report_pid,
45
+ :report_thread_id,
46
+ :tags,
47
+ :compression,
48
+ :report_encoding,
49
+ :autoinstrument_rails,
50
+ ) do
22
51
  def initialize(*)
52
+ super
53
+ # defaults:
23
54
  self.application_name = ''
24
55
  self.server_address = 'http://localhost:4040'
25
56
  self.auth_token = ''
26
57
  self.sample_rate = 100
27
58
  self.detect_subprocesses = false
28
- self.on_cpu = true
59
+ self.oncpu = true
29
60
  self.report_pid = false
30
61
  self.report_thread_id = false
31
- self.log_level = 'info'
62
+ self.log_level = 'error'
32
63
  self.tags = {}
33
- super
64
+ self.compression = 'gzip'
65
+ self.report_encoding = 'pprof'
66
+ self.autoinstrument_rails = true
34
67
  end
35
68
  end
36
69
 
37
70
  class << self
71
+ def current_config
72
+ @config
73
+ end
74
+
38
75
  def configure
39
76
  @config = Config.new
40
77
 
41
78
  # Pass config to the block
42
79
  yield @config
43
80
 
81
+ # Determine Logging level (kinda like an enum).
82
+ case @config.log_level
83
+ when 'trace'
84
+ @log_level = 10
85
+ when 'debug'
86
+ @log_level = 20
87
+ when 'info'
88
+ @log_level = 30
89
+ when 'warn'
90
+ @log_level = 40
91
+ when 'error'
92
+ @log_level = 50
93
+ else
94
+ @log_level = 50
95
+ end
96
+
97
+ Rust.initialize_logging(@log_level)
98
+
44
99
  Rust.initialize_agent(
100
+ # these are defaults in case user-provided values are nil:
45
101
  @config.app_name || @config.application_name || "",
46
102
  @config.server_address || "",
47
103
  @config.auth_token || "",
48
104
  @config.sample_rate || 100,
49
105
  @config.detect_subprocesses || false,
50
- @config.on_cpu || false,
106
+ @config.oncpu || false,
51
107
  @config.report_pid || false,
52
108
  @config.report_thread_id || false,
53
- tags_to_string(@config.tags || {})
109
+ tags_to_string(@config.tags || {}),
110
+ @config.compression || "",
111
+ @config.report_encoding || "pprof"
54
112
  )
55
113
  end
56
114
 
115
+ def initialize_rails_hooks
116
+ block = lambda do |ctrl, action|
117
+ Pyroscope.tag_wrapper({
118
+ "action" => "#{ctrl.controller_name}/#{ctrl.action_name}"
119
+ }, &action)
120
+ end
121
+
122
+ ActionController::API.__send__(:around_action, block) if defined? ActionController::API
123
+ ActionController::Base.__send__(:around_action, block) if defined? ActionController::Base
124
+ end
125
+
57
126
  def tag_wrapper(tags)
58
127
  tid = thread_id
59
128
  _add_tags(tid, tags)
@@ -72,32 +141,34 @@ module Pyroscope
72
141
  warn("deprecated. Use `Pyroscope.tag_wrapper` instead.")
73
142
  end
74
143
 
75
- # convert tags object to string
76
- def tags_to_string(tags)
77
- tags.map { |k, v| "#{k}=#{v}" }.join(',')
78
- end
79
-
80
- # get thread id
81
144
  def thread_id
82
145
  return Utils.thread_id
83
146
  end
84
147
 
85
- # add tags
86
148
  def _add_tags(thread_id, tags)
87
149
  tags.each do |tag_name, tag_value|
88
150
  Rust.add_thread_tag(thread_id, tag_name.to_s, tag_value.to_s)
89
151
  end
90
152
  end
91
153
 
92
- # remove tags
93
154
  def _remove_tags(thread_id, tags)
94
155
  tags.each do |tag_name, tag_value|
95
156
  Rust.remove_thread_tag(thread_id, tag_name.to_s, tag_value.to_s)
96
157
  end
97
158
  end
98
159
 
99
- def drop
160
+ def stop
100
161
  Rust.drop_agent
101
162
  end
163
+
164
+ def shutdown
165
+ stop
166
+ end
167
+
168
+ private
169
+
170
+ def tags_to_string(tags)
171
+ tags.map { |k, v| "#{k}=#{v}" }.join(',')
172
+ end
102
173
  end
103
174
  end
Binary file
Binary file
data/pyroscope.gemspec CHANGED
@@ -1,4 +1,11 @@
1
- require_relative "lib/pyroscope/version"
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ begin
5
+ require File.expand_path(File.join(File.dirname(__FILE__), "lib/pyroscope/version"))
6
+ rescue LoadError
7
+ puts "WARNING: Could not load Pyroscope::VERSION"
8
+ end
2
9
 
3
10
  Gem::Specification.new do |s|
4
11
  s.name = 'pyroscope'
@@ -9,6 +16,13 @@ Gem::Specification.new do |s|
9
16
  s.email = ['contact@pyroscope.io']
10
17
  s.homepage = 'https://pyroscope.io'
11
18
  s.license = 'Apache-2.0'
19
+ s.metadata = {
20
+ "homepage_uri" => "https://pyroscope.io",
21
+ "bug_tracker_uri" => "https://github.com/pyroscope-io/pyroscope-rs/issues",
22
+ "documentation_uri" => "https://pyroscope.io/docs/ruby/",
23
+ "changelog_uri" => "https://github.com/pyroscope-io/pyroscope-rs/tree/main/pyroscope_ffi/ruby/CHANGELOG.md",
24
+ "source_code_uri" => "https://github.com/pyroscope-io/pyroscope-rs/tree/main/pyroscope_ffi/ruby",
25
+ }
12
26
 
13
27
  # Specify which files should be added to the gem when it is released.
14
28
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -21,7 +35,7 @@ Gem::Specification.new do |s|
21
35
 
22
36
  s.platform = Gem::Platform::RUBY
23
37
 
24
- s.required_ruby_version = ">= 2.5.9"
38
+ s.required_ruby_version = ">= 1.9.3"
25
39
 
26
40
  s.extensions = ['ext/rbspy/extconf.rb', 'ext/thread_id/extconf.rb']
27
41
 
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "pyroscope"
4
+ require "pyroscope/version"
5
+
6
+ puts Pyroscope::VERSION
7
+ puts RUBY_VERSION
8
+
9
+ Pyroscope.configure do |config|
10
+ config.application_name = "#{ENV["PYROSCOPE_RUN_ID"]}"
11
+ config.server_address = "https://ingest.pyroscope.cloud"
12
+ config.auth_token = ENV["PYROSCOPE_API_TOKEN"]
13
+ config.detect_subprocesses = ENV["PYROSCOPE_DETECT_SUBPROCESSES"] == "1"
14
+ config.oncpu = ENV["PYROSCOPE_ONCPU"] == "1"
15
+ config.log_level = "trace"
16
+ config.report_pid = true
17
+ config.report_thread_id = true
18
+ config.tags = {
19
+ :region => "us-east",
20
+ :detect_subprocesses => ENV["PYROSCOPE_DETECT_SUBPROCESSES"],
21
+ :oncpu => ENV["PYROSCOPE_ONCPU"],
22
+ :version => ENV["RUBY_VERSION"],
23
+ :arch => ENV["PYROSCOPE_ARCH"]
24
+ }
25
+ end
26
+
27
+ def work(n)
28
+ i = 0
29
+ while i < n
30
+ i += 1
31
+ end
32
+ end
33
+
34
+ def fast_function
35
+ Pyroscope.tag_wrapper({"function": "fast"}) do
36
+ work(2001002000)
37
+ end
38
+ end
39
+
40
+ def slow_function
41
+ work(8001008000)
42
+ end
43
+
44
+ child_pid = fork do
45
+ puts "This is the child process"
46
+ Pyroscope.tag_wrapper({"fork": "forked"}) do
47
+ slow_function()
48
+ end
49
+ end
50
+
51
+ puts "This is the master process."
52
+
53
+ Pyroscope.tag_wrapper({"fork": "master"}) do
54
+ fast_function()
55
+ end
56
+
57
+ puts "The PID of the child process is #{child_pid}"
58
+
59
+ Pyroscope.shutdown()
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pyroscope
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.5.1
5
5
  platform: x86_64-darwin
6
6
  authors:
7
7
  - Pyroscope Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-22 00:00:00.000000000 Z
11
+ date: 2022-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -89,10 +89,16 @@ files:
89
89
  - lib/thread_id/thread_id.bundle
90
90
  - pyroscope.gemspec
91
91
  - scripts/docker.sh
92
+ - scripts/tests/test.rb
92
93
  homepage: https://pyroscope.io
93
94
  licenses:
94
95
  - Apache-2.0
95
- metadata: {}
96
+ metadata:
97
+ homepage_uri: https://pyroscope.io
98
+ bug_tracker_uri: https://github.com/pyroscope-io/pyroscope-rs/issues
99
+ documentation_uri: https://pyroscope.io/docs/ruby/
100
+ changelog_uri: https://github.com/pyroscope-io/pyroscope-rs/tree/main/pyroscope_ffi/ruby/CHANGELOG.md
101
+ source_code_uri: https://github.com/pyroscope-io/pyroscope-rs/tree/main/pyroscope_ffi/ruby
96
102
  post_install_message:
97
103
  rdoc_options: []
98
104
  require_paths:
@@ -101,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
107
  requirements:
102
108
  - - ">="
103
109
  - !ruby/object:Gem::Version
104
- version: 2.5.9
110
+ version: 1.9.3
105
111
  required_rubygems_version: !ruby/object:Gem::Requirement
106
112
  requirements:
107
113
  - - ">="