pyroscope 0.3.0 → 0.4.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: d844d0ba44d32a1201923e772b917ec927b3c95f0e09a051f7d212e33a603d1c
4
- data.tar.gz: ebf2419e55b0fb78cdb8701fce737e274215b8dcec1da30c84c3c91b1cd51643
3
+ metadata.gz: eba4490cd4dc65fb1219814e002baab05754afe2270e083e8bb697cfa5c452ea
4
+ data.tar.gz: 69e27707297c593ca5aacd3978fe318dd92219e54caa66c2d2451d24a2a0d70b
5
5
  SHA512:
6
- metadata.gz: 0aa05eaa6246a501c9e41a7843b13dd91fedbb1ec553e79cad75a03760222a3f8d8b292b12a23364b84e066ea8d5114a4d49eff961d78d894de6bc74b86de723
7
- data.tar.gz: ac00d00f2daebcfec6e2cd49665f2406e9ebc238805bef87aa69a3d6a98638aef91f02d765bc7708c605e215dda6eac2176cb18139183587ae269b747d5de2f9
6
+ metadata.gz: 6c9950536925d36afc03c2461d62793f33ebb514e81b3bc308708bdea33fa4dba560d19ef1b5ccd450e0c5b58604e36d1231caa218bb5d1861dd7e3149f932f0
7
+ data.tar.gz: d08dcba721bf53f1ea3ce929c3bbbe2dd8b6866da347151d442f0d9281fbc779ccc08c16ef37dd7ec1c1b38846b64d2c8e6357d5906e3b81c15908cd3106f546
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/Cargo.toml CHANGED
@@ -12,6 +12,8 @@ crate-type = ["cdylib"]
12
12
  pyroscope = { path = "../../../../" }
13
13
  #pyroscope_rbspy = { version = "0.2" }
14
14
  pyroscope_rbspy = { path = "../../../../pyroscope_backends/pyroscope_rbspy" }
15
+ ffikit = { path = "../../../ffikit" }
16
+ pretty_env_logger = "0.4.0"
15
17
 
16
18
  [patch.crates-io]
17
19
  read-process-memory = {git = "https://github.com/omarabid/read-process-memory.git", branch = "0.1.4-fix"}
data/ext/rbspy/src/lib.rs CHANGED
@@ -1,45 +1,117 @@
1
- use pyroscope::backend::Tag;
2
- use pyroscope::PyroscopeAgent;
3
- use pyroscope_rbspy::{rbspy_backend, RbspyConfig};
1
+ use std::collections::hash_map::DefaultHasher;
2
+ use std::env;
4
3
  use std::ffi::CStr;
5
- use std::mem::MaybeUninit;
4
+ use std::hash::Hasher;
6
5
  use std::os::raw::c_char;
7
- use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
8
- use std::sync::{Mutex, Once};
6
+ use std::str::FromStr;
9
7
 
10
- pub enum Signal {
11
- Kill,
12
- AddTag(u64, String, String),
13
- RemoveTag(u64, String, String),
14
- }
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
+
14
+ pub fn transform_report(report: Report) -> Report {
15
+ let cwd = env::current_dir().unwrap();
16
+ let cwd = cwd.to_str().unwrap_or("");
17
+
18
+ let data = report
19
+ .data
20
+ .iter()
21
+ .map(|(stacktrace, count)| {
22
+ let new_frames = stacktrace
23
+ .frames
24
+ .iter()
25
+ .map(|frame| {
26
+ let frame = frame.to_owned();
27
+ let mut s = frame.filename.unwrap();
28
+ match s.find(cwd) {
29
+ Some(i) => {
30
+ s = s[(i + cwd.len() + 1)..].to_string();
31
+ }
32
+ None => match s.find("/gems/") {
33
+ Some(i) => {
34
+ s = s[(i + 1)..].to_string();
35
+ }
36
+ None => match s.find("/ruby/") {
37
+ Some(i) => {
38
+ s = s[(i + 6)..].to_string();
39
+ match s.find("/") {
40
+ Some(i) => {
41
+ s = s[(i + 1)..].to_string();
42
+ }
43
+ None => {}
44
+ }
45
+ }
46
+ None => {}
47
+ },
48
+ },
49
+ }
50
+
51
+ // something
52
+ StackFrame::new(
53
+ frame.module,
54
+ frame.name,
55
+ Some(s.to_string()),
56
+ frame.relative_path,
57
+ frame.absolute_path,
58
+ frame.line,
59
+ )
60
+ })
61
+ .collect();
62
+
63
+ let mut mystack = stacktrace.to_owned();
64
+
65
+ mystack.frames = new_frames;
15
66
 
16
- pub struct SignalPass {
17
- inner_sender: Mutex<SyncSender<Signal>>,
18
- inner_receiver: Mutex<Receiver<Signal>>,
67
+ (mystack, count.to_owned())
68
+ })
69
+ .collect();
70
+
71
+ let new_report = Report::new(data).metadata(report.metadata.clone());
72
+
73
+ new_report
19
74
  }
20
75
 
21
- fn signalpass() -> &'static SignalPass {
22
- static mut SIGNAL_PASS: MaybeUninit<SignalPass> = MaybeUninit::uninit();
23
- static ONCE: Once = Once::new();
24
-
25
- ONCE.call_once(|| unsafe {
26
- let (sender, receiver) = sync_channel(1);
27
- let singleton = SignalPass {
28
- inner_sender: Mutex::new(sender),
29
- inner_receiver: Mutex::new(receiver),
30
- };
31
- SIGNAL_PASS = MaybeUninit::new(singleton);
32
- });
76
+ #[no_mangle]
77
+ pub extern "C" fn initialize_logging(logging_level: u32) -> bool {
78
+ // Force rustc to display the log messages in the console.
79
+ match logging_level {
80
+ 50 => {
81
+ std::env::set_var("RUST_LOG", "error");
82
+ }
83
+ 40 => {
84
+ std::env::set_var("RUST_LOG", "warn");
85
+ }
86
+ 30 => {
87
+ std::env::set_var("RUST_LOG", "info");
88
+ }
89
+ 20 => {
90
+ std::env::set_var("RUST_LOG", "debug");
91
+ }
92
+ 10 => {
93
+ std::env::set_var("RUST_LOG", "trace");
94
+ }
95
+ _ => {
96
+ std::env::set_var("RUST_LOG", "debug");
97
+ }
98
+ }
33
99
 
34
- unsafe { SIGNAL_PASS.assume_init_ref() }
100
+ // Initialize the logger.
101
+ pretty_env_logger::init_timed();
102
+
103
+ true
35
104
  }
36
105
 
37
106
  #[no_mangle]
38
107
  pub extern "C" fn initialize_agent(
39
108
  application_name: *const c_char, server_address: *const c_char, auth_token: *const c_char,
40
- sample_rate: u32, detect_subprocesses: bool, on_cpu: bool, report_pid: bool,
41
- report_thread_id: bool, tags: *const c_char,
109
+ sample_rate: u32, detect_subprocesses: bool, oncpu: bool, report_pid: bool,
110
+ report_thread_id: bool, tags: *const c_char, compression: *const c_char
42
111
  ) -> bool {
112
+ // Initialize FFIKit
113
+ let recv = ffikit::initialize_ffi().unwrap();
114
+
43
115
  let application_name = unsafe { CStr::from_ptr(application_name) }
44
116
  .to_str()
45
117
  .unwrap()
@@ -60,46 +132,64 @@ pub extern "C" fn initialize_agent(
60
132
  .unwrap()
61
133
  .to_string();
62
134
 
135
+ let compression_string = unsafe { CStr::from_ptr(compression) }
136
+ .to_str()
137
+ .unwrap()
138
+ .to_string();
139
+
140
+ let compression = Compression::from_str(&compression_string);
141
+
63
142
  let pid = std::process::id();
64
143
 
65
- let s = signalpass();
144
+ let rbspy_config = RbspyConfig::new(pid.try_into().unwrap())
145
+ .sample_rate(sample_rate)
146
+ .lock_process(false)
147
+ .detect_subprocesses(detect_subprocesses)
148
+ .oncpu(oncpu)
149
+ .report_pid(report_pid)
150
+ .report_thread_id(report_thread_id);
66
151
 
67
- std::thread::spawn(move || {
68
- let rbspy_config = RbspyConfig::new(pid.try_into().unwrap())
69
- .sample_rate(sample_rate)
70
- .lock_process(false)
71
- .with_subprocesses(detect_subprocesses)
72
- .on_cpu(on_cpu)
73
- .report_pid(report_pid)
74
- .report_thread_id(report_thread_id);
75
-
76
- let tags_ref = tags_string.as_str();
77
- let tags = string_to_tags(tags_ref);
78
- let rbspy = rbspy_backend(rbspy_config);
79
-
80
- let mut agent_builder = PyroscopeAgent::builder(server_address, application_name)
81
- .backend(rbspy)
82
- .tags(tags);
83
-
84
- if auth_token != "" {
85
- agent_builder = agent_builder.auth_token(auth_token);
86
- }
152
+ let tags_ref = tags_string.as_str();
153
+ let tags = string_to_tags(tags_ref);
154
+ let rbspy = rbspy_backend(rbspy_config);
155
+
156
+ let mut agent_builder = PyroscopeAgent::builder(server_address, application_name)
157
+ .backend(rbspy)
158
+ .func(transform_report)
159
+ .tags(tags);
160
+
161
+ if auth_token != "" {
162
+ agent_builder = agent_builder.auth_token(auth_token);
163
+ }
164
+
165
+ if let Ok(compression) = compression {
166
+ agent_builder = agent_builder.compression(compression);
167
+ }
87
168
 
88
- let agent = agent_builder.build().unwrap();
169
+ let agent = agent_builder.build().unwrap();
89
170
 
90
- let agent_running = agent.start().unwrap();
171
+ let agent_running = agent.start().unwrap();
91
172
 
92
- while let Ok(signal) = s.inner_receiver.lock().unwrap().recv() {
173
+ std::thread::spawn(move || {
174
+ while let Ok(signal) = recv.recv() {
93
175
  match signal {
94
176
  Signal::Kill => {
95
177
  agent_running.stop().unwrap();
96
178
  break;
97
179
  }
98
- Signal::AddTag(thread_id, key, value) => {
180
+ Signal::AddGlobalTag(name, value) => {
181
+ agent_running.add_global_tag(Tag::new(name, value)).unwrap();
182
+ }
183
+ Signal::RemoveGlobalTag(name, value) => {
184
+ agent_running
185
+ .remove_global_tag(Tag::new(name, value))
186
+ .unwrap();
187
+ }
188
+ Signal::AddThreadTag(thread_id, key, value) => {
99
189
  let tag = Tag::new(key, value);
100
190
  agent_running.add_thread_tag(thread_id, tag).unwrap();
101
191
  }
102
- Signal::RemoveTag(thread_id, key, value) => {
192
+ Signal::RemoveThreadTag(thread_id, key, value) => {
103
193
  let tag = Tag::new(key, value);
104
194
  agent_running.remove_thread_tag(thread_id, tag).unwrap();
105
195
  }
@@ -112,40 +202,73 @@ pub extern "C" fn initialize_agent(
112
202
 
113
203
  #[no_mangle]
114
204
  pub extern "C" fn drop_agent() -> bool {
115
- let s = signalpass();
116
- s.inner_sender.lock().unwrap().send(Signal::Kill).unwrap();
205
+ // Send Kill signal to the FFI merge channel.
206
+ ffikit::send(ffikit::Signal::Kill).unwrap();
207
+
117
208
  true
118
209
  }
119
210
 
120
211
  #[no_mangle]
121
- pub extern "C" fn add_tag(thread_id: u64, key: *const c_char, value: *const c_char) -> bool {
122
- let s = signalpass();
212
+ pub extern "C" fn add_thread_tag(thread_id: u64, key: *const c_char, value: *const c_char) -> bool {
123
213
  let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
124
214
  let value = unsafe { CStr::from_ptr(value) }
125
215
  .to_str()
126
216
  .unwrap()
127
217
  .to_owned();
128
- s.inner_sender
129
- .lock()
218
+
219
+ let pid = std::process::id();
220
+ let mut hasher = DefaultHasher::new();
221
+ hasher.write_u64(thread_id % pid as u64);
222
+ let id = hasher.finish();
223
+
224
+ ffikit::send(ffikit::Signal::AddThreadTag(id, key, value)).unwrap();
225
+
226
+ true
227
+ }
228
+
229
+ #[no_mangle]
230
+ pub extern "C" fn remove_thread_tag(
231
+ thread_id: u64, key: *const c_char, value: *const c_char,
232
+ ) -> bool {
233
+ let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
234
+ let value = unsafe { CStr::from_ptr(value) }
235
+ .to_str()
130
236
  .unwrap()
131
- .send(Signal::AddTag(thread_id, key, value))
132
- .unwrap();
237
+ .to_owned();
238
+
239
+ let pid = std::process::id();
240
+ let mut hasher = DefaultHasher::new();
241
+ hasher.write_u64(thread_id % pid as u64);
242
+ let id = hasher.finish();
243
+
244
+ ffikit::send(ffikit::Signal::RemoveThreadTag(id, key, value)).unwrap();
245
+
133
246
  true
134
247
  }
135
248
 
136
249
  #[no_mangle]
137
- pub extern "C" fn remove_tag(thread_id: u64, key: *const c_char, value: *const c_char) -> bool {
138
- let s = signalpass();
250
+ pub extern "C" fn add_global_tag(key: *const c_char, value: *const c_char) -> bool {
139
251
  let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
140
252
  let value = unsafe { CStr::from_ptr(value) }
141
253
  .to_str()
142
254
  .unwrap()
143
255
  .to_owned();
144
- s.inner_sender
145
- .lock()
256
+
257
+ ffikit::send(ffikit::Signal::AddGlobalTag(key, value)).unwrap();
258
+
259
+ true
260
+ }
261
+
262
+ #[no_mangle]
263
+ pub extern "C" fn remove_global_tag(key: *const c_char, value: *const c_char) -> bool {
264
+ let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
265
+ let value = unsafe { CStr::from_ptr(value) }
266
+ .to_str()
146
267
  .unwrap()
147
- .send(Signal::RemoveTag(thread_id, key, value))
148
- .unwrap();
268
+ .to_owned();
269
+
270
+ ffikit::send(ffikit::Signal::RemoveGlobalTag(key, value)).unwrap();
271
+
149
272
  true
150
273
  }
151
274
 
@@ -1,3 +1,3 @@
1
1
  module Pyroscope
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
data/lib/pyroscope.rb CHANGED
@@ -1,34 +1,42 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  require 'ffi'
2
5
 
3
- module Rust
4
- extend FFI::Library
5
- ffi_lib File.expand_path(File.dirname(__FILE__)) + "/rbspy/rbspy.#{RbConfig::CONFIG["DLEXT"]}"
6
- attach_function :initialize_agent, [:string, :string, :string, :int, :bool, :bool, :bool, :bool, :string], :bool
7
- attach_function :add_tag, [:uint64, :string, :string], :bool
8
- attach_function :remove_tag, [:uint64, :string, :string], :bool
9
- attach_function :drop_agent, [], :bool
10
- end
6
+ module Pyroscope
7
+ module Rust
8
+ extend FFI::Library
9
+ ffi_lib File.expand_path(File.dirname(__FILE__)) + "/rbspy/rbspy.#{RbConfig::CONFIG["DLEXT"]}"
10
+ attach_function :initialize_logging, [:int], :bool
11
+ attach_function :initialize_agent, [:string, :string, :string, :int, :bool, :bool, :bool, :bool, :string, :string], :bool
12
+ attach_function :add_thread_tag, [:uint64, :string, :string], :bool
13
+ attach_function :remove_thread_tag, [:uint64, :string, :string], :bool
14
+ attach_function :add_global_tag, [:string, :string], :bool
15
+ attach_function :remove_global_tag, [:string, :string], :bool
16
+ attach_function :drop_agent, [], :bool
17
+ end
11
18
 
12
- module Utils
13
- extend FFI::Library
14
- ffi_lib File.expand_path(File.dirname(__FILE__)) + "/thread_id/thread_id.#{RbConfig::CONFIG["DLEXT"]}"
15
- attach_function :thread_id, [], :uint64
16
- end
19
+ module Utils
20
+ extend FFI::Library
21
+ ffi_lib File.expand_path(File.dirname(__FILE__)) + "/thread_id/thread_id.#{RbConfig::CONFIG["DLEXT"]}"
22
+ attach_function :thread_id, [], :uint64
23
+ end
17
24
 
18
- module Pyroscope
19
- 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
+ Config = Struct.new(:application_name, :app_name, :server_address, :auth_token, :log_level, :sample_rate, :detect_subprocesses, :oncpu, :report_pid, :report_thread_id, :tags, :compression) do
20
26
  def initialize(*)
21
27
  super
22
- self.application_name ||= ''
23
- self.server_address ||= 'http://localhost:4040'
24
- self.auth_token ||= ''
25
- self.sample_rate ||= 100
26
- self.detect_subprocesses ||= true
27
- self.on_cpu ||= true
28
- self.report_pid ||= false
29
- self.report_thread_id ||= false
30
- self.log_level ||= 'info'
31
- self.tags ||= []
28
+ # defaults:
29
+ self.application_name = ''
30
+ self.server_address = 'http://localhost:4040'
31
+ self.auth_token = ''
32
+ self.sample_rate = 100
33
+ self.detect_subprocesses = false
34
+ self.oncpu = true
35
+ self.report_pid = false
36
+ self.report_thread_id = false
37
+ self.log_level = 'error'
38
+ self.tags = {}
39
+ self.compression = 'gzip'
32
40
  end
33
41
  end
34
42
 
@@ -39,16 +47,39 @@ module Pyroscope
39
47
  # Pass config to the block
40
48
  yield @config
41
49
 
50
+ # Determine Logging level (kinda like an enum).
51
+ case @config.log_level
52
+ when 'trace'
53
+ @log_level = 10
54
+ when 'debug'
55
+ @log_level = 20
56
+ when 'info'
57
+ @log_level = 30
58
+ when 'warn'
59
+ @log_level = 40
60
+ when 'error'
61
+ @log_level = 50
62
+ else
63
+ @log_level = 50
64
+ end
65
+
66
+ # Initialize Logging
67
+ Rust.initialize_logging(@log_level)
68
+
69
+
70
+ # initialize Pyroscope Agent
42
71
  Rust.initialize_agent(
43
- @config.app_name || @config.application_name,
44
- @config.server_address,
45
- @config.auth_token,
46
- @config.sample_rate,
47
- @config.detect_subprocesses,
48
- @config.on_cpu,
49
- @config.report_pid,
50
- @config.report_thread_id,
51
- tags_to_string(@config.tags)
72
+ # these are defaults in case user-provided values are nil:
73
+ @config.app_name || @config.application_name || "",
74
+ @config.server_address || "",
75
+ @config.auth_token || "",
76
+ @config.sample_rate || 100,
77
+ @config.detect_subprocesses || false,
78
+ @config.oncpu || false,
79
+ @config.report_pid || false,
80
+ @config.report_thread_id || false,
81
+ tags_to_string(@config.tags || {}),
82
+ @config.compression || ""
52
83
  )
53
84
  end
54
85
 
@@ -83,18 +114,18 @@ module Pyroscope
83
114
  # add tags
84
115
  def _add_tags(thread_id, tags)
85
116
  tags.each do |tag_name, tag_value|
86
- Rust.add_tag(thread_id, tag_name.to_s, tag_value.to_s)
117
+ Rust.add_thread_tag(thread_id, tag_name.to_s, tag_value.to_s)
87
118
  end
88
119
  end
89
120
 
90
121
  # remove tags
91
122
  def _remove_tags(thread_id, tags)
92
123
  tags.each do |tag_name, tag_value|
93
- Rust.remove_tag(thread_id, tag_name.to_s, tag_value.to_s)
124
+ Rust.remove_thread_tag(thread_id, tag_name.to_s, tag_value.to_s)
94
125
  end
95
126
  end
96
127
 
97
- def drop
128
+ def shutdown
98
129
  Rust.drop_agent
99
130
  end
100
131
  end
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.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pyroscope Team
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-30 00:00:00.000000000 Z
11
+ date: 2022-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -89,11 +89,17 @@ files:
89
89
  - lib/pyroscope/version.rb
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
- post_install_message:
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
102
+ post_install_message:
97
103
  rdoc_options: []
98
104
  require_paths:
99
105
  - lib
@@ -101,15 +107,15 @@ 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
  - - ">="
108
114
  - !ruby/object:Gem::Version
109
115
  version: '0'
110
116
  requirements: []
111
- rubygems_version: 3.3.15
112
- signing_key:
117
+ rubygems_version: 3.3.7
118
+ signing_key:
113
119
  specification_version: 4
114
120
  summary: Pyroscope
115
121
  test_files: []