pyroscope 0.3.0-x86_64-linux → 0.4.0-x86_64-linux

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: 1188a88450d24dff3c8011794c82bfa76cad0300fc86512b06d910a8445d294e
4
- data.tar.gz: f3a789ad8e81d790edd880451e612800231635e8913452001aec0b35b635d284
3
+ metadata.gz: e7e0a308394bd54ce968d7649712148526d1696b363c3d6e37f8b62bf8d83ceb
4
+ data.tar.gz: 7527ddda6ca70869a9115e8264510fc09ea4880aaa3e3da749efa07bd83334da
5
5
  SHA512:
6
- metadata.gz: 51b4ba379c9bd336382f0fd18300bcfdcc0a79cea9de7f95bcb0e52ac635364a411ff47497921e929e9e51ac644dfcd87f9e0720b7ba8c7da8954989b5046d76
7
- data.tar.gz: b45daeecf3f158e7c353acf982e1860608515877dc5702e74d18528b373ccf445ee87d027fc536b65ff4e12e6a21c07184690a7c099f1e64ec492e382a51c4e8
6
+ metadata.gz: ef8491839fcb25cb469c8d44ab1a57ccfc8100fb6d08b8ba12192063dc89289e741cde042e1b66f73fc4345ec2c7418535968d8399d5f41a54b3918b26046693
7
+ data.tar.gz: 48d7c8c58f94ba89ad36728a998fc04ed49e38a4bb4809eb0d602c1a1a3f7b7168cdeb4f498cc3b84d28b4eeb9a0dd72634c3653b7417f7c0ac5281041e07db7
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/lib/rbspy/rbspy.so CHANGED
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
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.0
4
+ version: 0.4.0
5
5
  platform: x86_64-linux
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
@@ -98,11 +98,17 @@ files:
98
98
  - lib/thread_id/thread_id.so
99
99
  - pyroscope.gemspec
100
100
  - scripts/docker.sh
101
+ - scripts/tests/test.rb
101
102
  homepage: https://pyroscope.io
102
103
  licenses:
103
104
  - Apache-2.0
104
- metadata: {}
105
- post_install_message:
105
+ metadata:
106
+ homepage_uri: https://pyroscope.io
107
+ bug_tracker_uri: https://github.com/pyroscope-io/pyroscope-rs/issues
108
+ documentation_uri: https://pyroscope.io/docs/ruby/
109
+ changelog_uri: https://github.com/pyroscope-io/pyroscope-rs/tree/main/pyroscope_ffi/ruby/CHANGELOG.md
110
+ source_code_uri: https://github.com/pyroscope-io/pyroscope-rs/tree/main/pyroscope_ffi/ruby
111
+ post_install_message:
106
112
  rdoc_options: []
107
113
  require_paths:
108
114
  - lib
@@ -110,15 +116,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
116
  requirements:
111
117
  - - ">="
112
118
  - !ruby/object:Gem::Version
113
- version: 2.5.9
119
+ version: 1.9.3
114
120
  required_rubygems_version: !ruby/object:Gem::Requirement
115
121
  requirements:
116
122
  - - ">="
117
123
  - !ruby/object:Gem::Version
118
124
  version: '0'
119
125
  requirements: []
120
- rubygems_version: 3.3.15
121
- signing_key:
126
+ rubygems_version: 3.3.7
127
+ signing_key:
122
128
  specification_version: 4
123
129
  summary: Pyroscope
124
130
  test_files: []