pyroscope 0.3.2 → 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: 8e4579716329cb055e247d5c05419d38889bae214ad4167dff49aa298c52f3b0
4
- data.tar.gz: c2679ebbd856b7603c49ab20b956470ee32aaf03f8c37e145ea2bd0467dd7f94
3
+ metadata.gz: eba4490cd4dc65fb1219814e002baab05754afe2270e083e8bb697cfa5c452ea
4
+ data.tar.gz: 69e27707297c593ca5aacd3978fe318dd92219e54caa66c2d2451d24a2a0d70b
5
5
  SHA512:
6
- metadata.gz: a7f059b8a98c2b9c3bf553f296524a5004017f07fb1a7ea52821e6c2f4111f101a501f4edd1bd6d4a82a14a3e75aed3bb543bd2fff0d0c5e40d5a99395f7af61
7
- data.tar.gz: 90dddc7d21658e6fa87d66dca7460e9856d771455464b3ca05776345496d3fe19fc9eb4f85a8bcee5cc480e89a6280a4a43a0f4598548ff00e8f7866d8b32d18
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/src/lib.rs CHANGED
@@ -1,12 +1,15 @@
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};
10
13
 
11
14
  pub fn transform_report(report: Report) -> Report {
12
15
  let cwd = env::current_dir().unwrap();
@@ -24,31 +27,25 @@ pub fn transform_report(report: Report) -> Report {
24
27
  let mut s = frame.filename.unwrap();
25
28
  match s.find(cwd) {
26
29
  Some(i) => {
27
- s = s[(i+cwd.len()+1)..].to_string();
30
+ s = s[(i + cwd.len() + 1)..].to_string();
28
31
  }
29
- None => {
30
- match s.find("/gems/") {
32
+ None => match s.find("/gems/") {
33
+ Some(i) => {
34
+ s = s[(i + 1)..].to_string();
35
+ }
36
+ None => match s.find("/ruby/") {
31
37
  Some(i) => {
32
- s = s[(i+1)..].to_string();
33
- }
34
- None => {
35
- match s.find("/ruby/") {
38
+ s = s[(i + 6)..].to_string();
39
+ match s.find("/") {
36
40
  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 => {
41
+ s = s[(i + 1)..].to_string();
47
42
  }
43
+ None => {}
48
44
  }
49
45
  }
50
- }
51
- }
46
+ None => {}
47
+ },
48
+ },
52
49
  }
53
50
 
54
51
  // something
@@ -76,11 +73,41 @@ pub fn transform_report(report: Report) -> Report {
76
73
  new_report
77
74
  }
78
75
 
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
+ }
99
+
100
+ // Initialize the logger.
101
+ pretty_env_logger::init_timed();
102
+
103
+ true
104
+ }
105
+
79
106
  #[no_mangle]
80
107
  pub extern "C" fn initialize_agent(
81
108
  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,
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
84
111
  ) -> bool {
85
112
  // Initialize FFIKit
86
113
  let recv = ffikit::initialize_ffi().unwrap();
@@ -105,13 +132,20 @@ pub extern "C" fn initialize_agent(
105
132
  .unwrap()
106
133
  .to_string();
107
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
+
108
142
  let pid = std::process::id();
109
143
 
110
144
  let rbspy_config = RbspyConfig::new(pid.try_into().unwrap())
111
145
  .sample_rate(sample_rate)
112
146
  .lock_process(false)
113
- .with_subprocesses(detect_subprocesses)
114
- .on_cpu(on_cpu)
147
+ .detect_subprocesses(detect_subprocesses)
148
+ .oncpu(oncpu)
115
149
  .report_pid(report_pid)
116
150
  .report_thread_id(report_thread_id);
117
151
 
@@ -128,6 +162,10 @@ pub extern "C" fn initialize_agent(
128
162
  agent_builder = agent_builder.auth_token(auth_token);
129
163
  }
130
164
 
165
+ if let Ok(compression) = compression {
166
+ agent_builder = agent_builder.compression(compression);
167
+ }
168
+
131
169
  let agent = agent_builder.build().unwrap();
132
170
 
133
171
  let agent_running = agent.start().unwrap();
@@ -1,3 +1,3 @@
1
1
  module Pyroscope
2
- VERSION = '0.3.2'.freeze
2
+ VERSION = '0.4.0'.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], :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,19 +22,21 @@ 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
+ 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
22
26
  def initialize(*)
27
+ super
28
+ # defaults:
23
29
  self.application_name = ''
24
30
  self.server_address = 'http://localhost:4040'
25
31
  self.auth_token = ''
26
32
  self.sample_rate = 100
27
33
  self.detect_subprocesses = false
28
- self.on_cpu = true
34
+ self.oncpu = true
29
35
  self.report_pid = false
30
36
  self.report_thread_id = false
31
- self.log_level = 'info'
37
+ self.log_level = 'error'
32
38
  self.tags = {}
33
- super
39
+ self.compression = 'gzip'
34
40
  end
35
41
  end
36
42
 
@@ -41,16 +47,39 @@ module Pyroscope
41
47
  # Pass config to the block
42
48
  yield @config
43
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
44
71
  Rust.initialize_agent(
72
+ # these are defaults in case user-provided values are nil:
45
73
  @config.app_name || @config.application_name || "",
46
74
  @config.server_address || "",
47
75
  @config.auth_token || "",
48
76
  @config.sample_rate || 100,
49
77
  @config.detect_subprocesses || false,
50
- @config.on_cpu || false,
78
+ @config.oncpu || false,
51
79
  @config.report_pid || false,
52
80
  @config.report_thread_id || false,
53
- tags_to_string(@config.tags || {})
81
+ tags_to_string(@config.tags || {}),
82
+ @config.compression || ""
54
83
  )
55
84
  end
56
85
 
@@ -96,7 +125,7 @@ module Pyroscope
96
125
  end
97
126
  end
98
127
 
99
- def drop
128
+ def shutdown
100
129
  Rust.drop_agent
101
130
  end
102
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.2
4
+ version: 0.4.0
5
5
  platform: ruby
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-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/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
+ 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
  - - ">="