pyroscope 0.3.0-arm64-darwin → 0.4.0-arm64-darwin

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: 07e893dbb1d344a6408adf69d7e6692a9722f4afa6ceb1f30441596fa85a0529
4
- data.tar.gz: 5d2fc262abf78dceb05a567f621f33c057dfc60f05a463c8b982db98509037e0
3
+ metadata.gz: 8d97d4e0b7e0fe010ec2db8e909afa56cafdce7fd92a82ec5032d594e39108f0
4
+ data.tar.gz: 2aa2e41ecdf127d0cefbc6165f7c78aa744d7ef75dff23fcb952bba7fcfdd977
5
5
  SHA512:
6
- metadata.gz: 3cf54f64e8830c63de312845c1da9d052ef2e054ae8e174fa28cbed6f6108d9101fcf957ccd61364b0b4354ddddfa71b5c0cbe9b7903c9aceea46b5071c632af
7
- data.tar.gz: 7e8ca2f80a04a5e28f474540eafd1b4cad83e974ef2d6a410eeba33d017dec8a04f167f8979137dd648190845704e67d0385be6894be0fb040eb1978c0a35e57
6
+ metadata.gz: 486beaa9b96dea0b29a24353f92243954074437a43a7ecc7013a314d3d14031018bea098f39a2e2b9dbb534c74b1dd5b15c40782e3abc31a0027b99fde7272d7
7
+ data.tar.gz: 211d3a5a3b7eddd7b6ef138b00cc8843d181eb191c267f58c9aec5b8ad784bef31653b64df72d7855cdb8cf242aa7b6a843ebcdd0af8d90f831669a00186acfe
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.
@@ -2,20 +2,20 @@
2
2
  set -e
3
3
 
4
4
  # Install tooling
5
- #yum -y -q install wget gcc libffi-devel openssl-devel
5
+ yum -y -q install wget gcc libffi-devel openssl-devel
6
6
 
7
7
  # Install Rust
8
- #curl https://sh.rustup.rs -sSf | sh -s -- -y
9
- #export PATH=~/.cargo/bin:$PATH
8
+ curl https://sh.rustup.rs -sSf | sh -s -- -y
9
+ export PATH=~/.cargo/bin:$PATH
10
10
 
11
11
  # Build wheels
12
- #/opt/python/cp37-cp37m/bin/python setup.py bdist_wheel
12
+ /opt/python/cp37-cp37m/bin/python setup.py bdist_wheel
13
13
 
14
14
  # Audit wheels
15
- #for wheel in dist/*.whl; do
16
- #auditwheel repair $wheel -w dist/
17
- #rm $wheel
18
- #done
15
+ for wheel in dist/*.whl; do
16
+ auditwheel repair $wheel -w dist/
17
+ rm $wheel
18
+ done
19
19
 
20
20
  # Extract wheels
21
21
  for wheel in dist/*.whl; do
@@ -2,20 +2,20 @@
2
2
  set -e
3
3
 
4
4
  # Install tooling
5
- #yum -y -q install wget gcc libffi-devel openssl-devel
5
+ yum -y -q install wget gcc libffi-devel openssl-devel
6
6
 
7
7
  # Install Rust
8
- #curl https://sh.rustup.rs -sSf | sh -s -- -y
9
- #export PATH=~/.cargo/bin:$PATH
8
+ curl https://sh.rustup.rs -sSf | sh -s -- -y
9
+ export PATH=~/.cargo/bin:$PATH
10
10
 
11
11
  # Build wheels
12
- #/opt/python/cp37-cp37m/bin/python setup.py bdist_wheel
12
+ /opt/python/cp37-cp37m/bin/python setup.py bdist_wheel
13
13
 
14
14
  # Audit wheels
15
- #for wheel in dist/*.whl; do
16
- #auditwheel repair $wheel -w dist/
17
- #rm $wheel
18
- #done
15
+ for wheel in dist/*.whl; do
16
+ auditwheel repair $wheel -w dist/
17
+ rm $wheel
18
+ done
19
19
 
20
20
  # Extract wheels
21
21
  for wheel in dist/*.whl; do
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,27 +47,49 @@ 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
-
54
- puts @config
55
84
  end
56
85
 
57
86
  def tag_wrapper(tags)
58
- add_tags(tags)
87
+ tid = thread_id
88
+ _add_tags(tid, tags)
59
89
  begin
60
90
  yield
61
91
  ensure
62
- remove_tags(tags)
92
+ _remove_tags(tid, tags)
63
93
  end
64
94
  end
65
95
 
@@ -67,33 +97,35 @@ module Pyroscope
67
97
  warn("deprecated. Use `Pyroscope.tag_wrapper` instead.")
68
98
  end
69
99
 
70
- # convert tags object to string
71
- def tags_to_string(tags)
72
- tags.map { |k, v| "#{k}=#{v}" }.join(',')
73
- end
100
+ def remove_tags(*tags)
101
+ warn("deprecated. Use `Pyroscope.tag_wrapper` instead.")
102
+ end
74
103
 
75
- # get thread id
76
- def thread_id
77
- return Utils.thread_id()
78
- end
104
+ # convert tags object to string
105
+ def tags_to_string(tags)
106
+ tags.map { |k, v| "#{k}=#{v}" }.join(',')
107
+ end
79
108
 
80
- # add tags
81
- def add_tags(tags)
82
- tags.each do |tag_name, tag_value|
83
- thread_id = thread_id()
84
- Rust.add_tag(thread_id, tag_name.to_s, tag_value.to_s)
85
- end
86
- end
109
+ # get thread id
110
+ def thread_id
111
+ return Utils.thread_id
112
+ end
87
113
 
88
- # remove tags
89
- def remove_tags(tags)
90
- tags.each do |tag_name, tag_value|
91
- thread_id = thread_id()
92
- Rust.remove_tag(thread_id, tag_name.to_s, tag_value.to_s)
93
- end
94
- end
114
+ # add tags
115
+ def _add_tags(thread_id, tags)
116
+ tags.each do |tag_name, tag_value|
117
+ Rust.add_thread_tag(thread_id, tag_name.to_s, tag_value.to_s)
118
+ end
119
+ end
120
+
121
+ # remove tags
122
+ def _remove_tags(thread_id, tags)
123
+ tags.each do |tag_name, tag_value|
124
+ Rust.remove_thread_tag(thread_id, tag_name.to_s, tag_value.to_s)
125
+ end
126
+ end
95
127
 
96
- def drop
128
+ def shutdown
97
129
  Rust.drop_agent
98
130
  end
99
131
  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.0
4
+ version: 0.4.0
5
5
  platform: arm64-darwin
6
6
  authors:
7
7
  - Pyroscope Team
8
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,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,14 +107,14 @@ 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.2.3
117
+ rubygems_version: 3.3.7
112
118
  signing_key:
113
119
  specification_version: 4
114
120
  summary: Pyroscope