pyroscope 0.3.2-x86_64-darwin → 0.4.0-x86_64-darwin
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +47 -33
- data/ext/rbspy/src/lib.rs +66 -28
- data/lib/pyroscope/version.rb +1 -1
- data/lib/pyroscope.rb +37 -8
- data/lib/rbspy/rbspy.bundle +0 -0
- data/lib/thread_id/thread_id.bundle +0 -0
- data/pyroscope.gemspec +16 -2
- data/scripts/tests/test.rb +59 -0
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 636eab1f55b6b4961f65f17715ea677e97c7f3d09db8f23a01f61efc05eb25d5
|
4
|
+
data.tar.gz: 15caf72125e714c5bebcbaa632ceccc805a03ebffef76b8612bf81f83fed2a40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a286732b2b19067b530a354fceba3612c450f7b675d77711d1b88a60492a74a5f2f5133edd8e527b2ef46b08862d61ba450c64632d615fb84fa58ac5571aa6b
|
7
|
+
data.tar.gz: 273e2663bbd27c73265baa46442ebd8fe05695cdcb493ad14e84c555c42f14d903c40625b8db01c9f47317dfc7b2393d39f5ee315e500c3540bffafc78007b36
|
data/README.md
CHANGED
@@ -1,57 +1,71 @@
|
|
1
|
-
Pyroscope Ruby
|
2
|
-
=====================================
|
1
|
+
# Pyroscope Ruby Gem
|
3
2
|
|
4
|
-
**
|
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
|
-
|
5
|
+
[](LICENSE)
|
6
|
+

|
7
|
+

|
8
|
+
[](https://badge.fury.io/rb/pyroscope)
|
8
9
|
|
9
|
-
|
10
|
-
Rust:
|
10
|
+
---
|
11
11
|
|
12
|
-
|
13
|
-
|
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
|
-
|
18
|
+
| Linux | macOS | Windows | Docker |
|
19
|
+
|:-----:|:-----:|:-------:|:------:|
|
20
|
+
| ✅ | ✅ | | ✅ |
|
24
21
|
|
25
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
42
|
-
|
52
|
+
config.application_name = "my.ruby.app"
|
53
|
+
config.server_address = "http://my-pyroscope-server:4040"
|
54
|
+
|
43
55
|
config.tags = {
|
44
|
-
|
56
|
+
"hostname" => ENV["HOSTNAME"],
|
45
57
|
}
|
46
58
|
end
|
47
59
|
```
|
48
60
|
|
49
|
-
|
61
|
+
or you can dynamically tag certain parts of your code:
|
50
62
|
|
51
|
-
|
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::
|
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
|
-
|
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+
|
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+
|
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,
|
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
|
-
.
|
114
|
-
.
|
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();
|
data/lib/pyroscope/version.rb
CHANGED
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 :
|
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, :
|
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.
|
34
|
+
self.oncpu = true
|
29
35
|
self.report_pid = false
|
30
36
|
self.report_thread_id = false
|
31
|
-
self.log_level = '
|
37
|
+
self.log_level = 'error'
|
32
38
|
self.tags = {}
|
33
|
-
|
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.
|
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
|
128
|
+
def shutdown
|
100
129
|
Rust.drop_agent
|
101
130
|
end
|
102
131
|
end
|
data/lib/rbspy/rbspy.bundle
CHANGED
Binary file
|
Binary file
|
data/pyroscope.gemspec
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
|
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 = ">=
|
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.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: x86_64-darwin
|
6
6
|
authors:
|
7
7
|
- Pyroscope Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
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,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
107
|
requirements:
|
102
108
|
- - ">="
|
103
109
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
110
|
+
version: 1.9.3
|
105
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
112
|
requirements:
|
107
113
|
- - ">="
|