pyroscope 1.0.1 → 1.0.8
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/Gemfile.lock +5 -4
- data/README.md +7 -53
- data/ext/rbspy/Cargo.lock +2743 -0
- data/ext/rbspy/Cargo.toml +7 -12
- data/ext/rbspy/Rakefile +1 -1
- data/ext/rbspy/include/rbspy.h +12 -0
- data/ext/rbspy/src/backend.rs +199 -0
- data/ext/rbspy/src/lib.rs +122 -35
- data/lib/pyroscope/version.rb +1 -1
- data/pyroscope.gemspec +7 -18
- metadata +10 -14
- data/ext/rbspy/build.rs +0 -12
data/ext/rbspy/Cargo.toml
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "ffiruby"
|
|
3
|
-
version = "
|
|
3
|
+
version = "1.0.8" # x-release-please-version
|
|
4
4
|
edition = "2021"
|
|
5
|
-
rust-version = "1.
|
|
5
|
+
rust-version = "1.66"
|
|
6
6
|
|
|
7
7
|
[lib]
|
|
8
8
|
name = "rbspy"
|
|
9
9
|
crate-type = ["cdylib"]
|
|
10
10
|
|
|
11
11
|
[dependencies]
|
|
12
|
-
pyroscope = {
|
|
13
|
-
rbspy = { version="0.
|
|
14
|
-
remoteprocess = "0.5
|
|
15
|
-
anyhow = "1.0"
|
|
16
|
-
# todo remove this dependency
|
|
12
|
+
pyroscope = { version="2.0.0", default-features = false, features = ["native-tls"] }
|
|
13
|
+
rbspy = { version = "0.48" }
|
|
14
|
+
remoteprocess = "0.5"
|
|
17
15
|
pretty_env_logger = "0.5"
|
|
18
16
|
log = "0.4"
|
|
19
|
-
libc = "0.2
|
|
20
|
-
|
|
21
|
-
[build-dependencies]
|
|
22
|
-
cbindgen = "0.29"
|
|
23
|
-
|
|
17
|
+
libc = "0.2"
|
|
18
|
+
anyhow = "1.0"
|
data/ext/rbspy/Rakefile
CHANGED
data/ext/rbspy/include/rbspy.h
CHANGED
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
|
|
13
13
|
bool initialize_logging(uint32_t logging_level);
|
|
14
14
|
|
|
15
|
+
/*
|
|
16
|
+
# Safety
|
|
17
|
+
All pointer arguments must be valid, non-null, null-terminated C strings.
|
|
18
|
+
*/
|
|
15
19
|
bool initialize_agent(const char *application_name,
|
|
16
20
|
const char *server_address,
|
|
17
21
|
const char *basic_auth_user,
|
|
@@ -26,8 +30,16 @@ bool initialize_agent(const char *application_name,
|
|
|
26
30
|
|
|
27
31
|
bool drop_agent(void);
|
|
28
32
|
|
|
33
|
+
/*
|
|
34
|
+
# Safety
|
|
35
|
+
`key` and `value` must be valid, non-null, null-terminated C strings.
|
|
36
|
+
*/
|
|
29
37
|
bool add_thread_tag(const char *key, const char *value);
|
|
30
38
|
|
|
39
|
+
/*
|
|
40
|
+
# Safety
|
|
41
|
+
`key` and `value` must be valid, non-null, null-terminated C strings.
|
|
42
|
+
*/
|
|
31
43
|
bool remove_thread_tag(const char *key, const char *value);
|
|
32
44
|
|
|
33
45
|
#endif /* RBSPY_H_ */
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
use pyroscope::{
|
|
2
|
+
backend::{
|
|
3
|
+
Backend, BackendConfig, Report, ReportBatch, ReportData, StackBuffer, StackFrame,
|
|
4
|
+
StackTrace, ThreadTag, ThreadTagsSet,
|
|
5
|
+
},
|
|
6
|
+
error::{PyroscopeError, Result},
|
|
7
|
+
};
|
|
8
|
+
use rbspy::sampler::Sampler;
|
|
9
|
+
use std::{
|
|
10
|
+
ops::Deref,
|
|
11
|
+
sync::{
|
|
12
|
+
mpsc::{channel, sync_channel, Receiver, Sender, SyncSender},
|
|
13
|
+
Arc, Mutex,
|
|
14
|
+
},
|
|
15
|
+
thread::JoinHandle,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const LOG_TAG: &str = "Pyroscope::Rbspy";
|
|
19
|
+
|
|
20
|
+
pub struct Rbspy {
|
|
21
|
+
sample_rate: u32,
|
|
22
|
+
backend_config: BackendConfig,
|
|
23
|
+
sampler: Sampler,
|
|
24
|
+
/// Error Receiver
|
|
25
|
+
error_receiver: Option<Receiver<std::result::Result<(), anyhow::Error>>>,
|
|
26
|
+
/// Profiling buffer
|
|
27
|
+
buffer: Arc<Mutex<StackBuffer>>,
|
|
28
|
+
/// Rulset
|
|
29
|
+
ruleset: ThreadTagsSet,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
impl std::fmt::Debug for Rbspy {
|
|
33
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
34
|
+
write!(f, "Rbspy Backend")
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
impl Rbspy {
|
|
39
|
+
/// Create a new Rbspy instance
|
|
40
|
+
pub fn new(sampler: Sampler, sample_rate: u32, backend_config: BackendConfig) -> Self {
|
|
41
|
+
Rbspy {
|
|
42
|
+
sample_rate,
|
|
43
|
+
sampler,
|
|
44
|
+
backend_config,
|
|
45
|
+
error_receiver: None,
|
|
46
|
+
buffer: Arc::new(Mutex::new(StackBuffer::default())),
|
|
47
|
+
ruleset: ThreadTagsSet::default(),
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Type aliases
|
|
53
|
+
type ErrorSender = Sender<std::result::Result<(), anyhow::Error>>;
|
|
54
|
+
type ErrorReceiver = Receiver<std::result::Result<(), anyhow::Error>>;
|
|
55
|
+
|
|
56
|
+
impl Backend for Rbspy {
|
|
57
|
+
fn add_tag(&self, tag: ThreadTag) -> Result<()> {
|
|
58
|
+
self.ruleset.add(tag)?;
|
|
59
|
+
|
|
60
|
+
Ok(())
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn remove_tag(&self, tag: ThreadTag) -> Result<()> {
|
|
64
|
+
self.ruleset.remove(tag)?;
|
|
65
|
+
|
|
66
|
+
Ok(())
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// Initialize the backend
|
|
70
|
+
fn initialize(&mut self) -> Result<()> {
|
|
71
|
+
// Channel for Errors generated by the RubySpy Sampler
|
|
72
|
+
let (error_sender, error_receiver): (ErrorSender, ErrorReceiver) = channel();
|
|
73
|
+
|
|
74
|
+
// This is provides enough space for 100 threads.
|
|
75
|
+
// It might be a better idea to figure out how many threads are running and determine the
|
|
76
|
+
// size of the channel based on that.
|
|
77
|
+
let queue_size: usize = self.sample_rate as usize * 10 * 100;
|
|
78
|
+
|
|
79
|
+
// Channel for StackTraces generated by the RubySpy Sampler
|
|
80
|
+
let (stack_sender, stack_receiver): (
|
|
81
|
+
SyncSender<rbspy::StackTrace>,
|
|
82
|
+
Receiver<rbspy::StackTrace>,
|
|
83
|
+
) = sync_channel(queue_size);
|
|
84
|
+
|
|
85
|
+
// Set Error and Stack Receivers
|
|
86
|
+
// self.stack_receiver = Some(stack_receiver);
|
|
87
|
+
self.error_receiver = Some(error_receiver);
|
|
88
|
+
|
|
89
|
+
self.sampler
|
|
90
|
+
.start(stack_sender, error_sender)
|
|
91
|
+
.map_err(|e| PyroscopeError::new(&format!("Rbspy: Sampler Error: {}", e)))?;
|
|
92
|
+
|
|
93
|
+
// Start own thread
|
|
94
|
+
//
|
|
95
|
+
// Get an Arc reference to the Report Buffer
|
|
96
|
+
let buffer = self.buffer.clone();
|
|
97
|
+
|
|
98
|
+
// ruleset reference
|
|
99
|
+
let ruleset = self.ruleset.clone();
|
|
100
|
+
|
|
101
|
+
let backend_config = self.backend_config;
|
|
102
|
+
|
|
103
|
+
let _: JoinHandle<Result<()>> = std::thread::spawn(move || {
|
|
104
|
+
// Iterate over the StackTrace
|
|
105
|
+
while let Ok(stack_trace) = stack_receiver.recv() {
|
|
106
|
+
// convert StackTrace
|
|
107
|
+
let own_trace: StackTrace =
|
|
108
|
+
Into::<StackTraceWrapper>::into((stack_trace, &backend_config)).into();
|
|
109
|
+
|
|
110
|
+
let stacktrace = own_trace.add_tag_rules(&ruleset);
|
|
111
|
+
|
|
112
|
+
buffer.lock()?.record(stacktrace)?;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
Ok(())
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
Ok(())
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
fn shutdown(self: Box<Self>) -> Result<()> {
|
|
122
|
+
log::trace!(target: LOG_TAG, "Shutting down sampler thread");
|
|
123
|
+
|
|
124
|
+
self.sampler.stop();
|
|
125
|
+
|
|
126
|
+
Ok(())
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fn report(&mut self) -> Result<ReportBatch> {
|
|
130
|
+
let v8: StackBuffer = self.buffer.lock()?.deref().to_owned();
|
|
131
|
+
let reports: Vec<Report> = v8.into();
|
|
132
|
+
|
|
133
|
+
self.buffer.lock()?.clear();
|
|
134
|
+
|
|
135
|
+
Ok(ReportBatch {
|
|
136
|
+
profile_type: "process_cpu".into(),
|
|
137
|
+
data: ReportData::Reports(reports),
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
struct StackFrameWrapper(StackFrame);
|
|
143
|
+
|
|
144
|
+
impl From<StackFrameWrapper> for StackFrame {
|
|
145
|
+
fn from(frame: StackFrameWrapper) -> Self {
|
|
146
|
+
frame.0
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
impl From<rbspy::StackFrame> for StackFrameWrapper {
|
|
151
|
+
fn from(frame: rbspy::StackFrame) -> Self {
|
|
152
|
+
StackFrameWrapper(StackFrame {
|
|
153
|
+
module: None,
|
|
154
|
+
name: Some(frame.name),
|
|
155
|
+
filename: Some(frame.relative_path.clone()),
|
|
156
|
+
relative_path: Some(frame.relative_path),
|
|
157
|
+
absolute_path: frame.absolute_path,
|
|
158
|
+
line: frame.lineno.map(|l| l as u32),
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
struct StackTraceWrapper(StackTrace);
|
|
164
|
+
|
|
165
|
+
impl From<StackTraceWrapper> for StackTrace {
|
|
166
|
+
fn from(trace: StackTraceWrapper) -> Self {
|
|
167
|
+
trace.0
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
impl From<(rbspy::StackTrace, &BackendConfig)> for StackTraceWrapper {
|
|
172
|
+
fn from(arg: (rbspy::StackTrace, &BackendConfig)) -> Self {
|
|
173
|
+
let (trace, config) = arg;
|
|
174
|
+
|
|
175
|
+
let thread_id = trace.thread_id.map(|tid| {
|
|
176
|
+
// for rbspy we use pthread_t as thread id
|
|
177
|
+
// https://github.com/ruby/ruby/blob/54a74c42033e42869e69e7dc9e67efa1faf225be/include/ruby/thread_native.h#L41
|
|
178
|
+
let thread_id = tid as libc::pthread_t;
|
|
179
|
+
thread_id.into()
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
StackTraceWrapper(StackTrace::new(
|
|
183
|
+
config,
|
|
184
|
+
trace.pid.map(|pid| pid as u32),
|
|
185
|
+
thread_id,
|
|
186
|
+
None,
|
|
187
|
+
trace
|
|
188
|
+
.iter()
|
|
189
|
+
.map(|frame| Into::<StackFrameWrapper>::into(frame.clone()).into())
|
|
190
|
+
.collect(),
|
|
191
|
+
))
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
pub fn self_thread_id() -> pyroscope::ThreadId {
|
|
196
|
+
// for rbspy we use pthread_t as thread id
|
|
197
|
+
// https://github.com/ruby/ruby/blob/54a74c42033e42869e69e7dc9e67efa1faf225be/include/ruby/thread_native.h#L41
|
|
198
|
+
pyroscope::ThreadId::pthread_self()
|
|
199
|
+
}
|
data/ext/rbspy/src/lib.rs
CHANGED
|
@@ -7,18 +7,20 @@ use std::ffi::CStr;
|
|
|
7
7
|
use std::os::raw::c_char;
|
|
8
8
|
|
|
9
9
|
use crate::backend::Rbspy;
|
|
10
|
-
use pyroscope;
|
|
11
10
|
use pyroscope::backend::{BackendConfig, BackendImpl, Report, StackFrame, Tag};
|
|
12
11
|
use pyroscope::pyroscope::PyroscopeAgentBuilder;
|
|
13
12
|
|
|
14
13
|
const LOG_TAG: &str = "Pyroscope::rbspy::ffi";
|
|
15
14
|
const RBSPY_NAME: &str = "rbspy";
|
|
16
|
-
const RBSPY_VERSION: &str = "
|
|
15
|
+
const RBSPY_VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
let cwd = env::current_dir().
|
|
20
|
-
let cwd = cwd.
|
|
17
|
+
fn transform_report_with_current_dir(report: Report) -> Report {
|
|
18
|
+
let cwd = env::current_dir().ok();
|
|
19
|
+
let cwd = cwd.as_deref().and_then(|p| p.to_str());
|
|
20
|
+
transform_report(report, cwd)
|
|
21
|
+
}
|
|
21
22
|
|
|
23
|
+
pub fn transform_report(report: Report, cwd: Option<&str>) -> Report {
|
|
22
24
|
let data = report
|
|
23
25
|
.data
|
|
24
26
|
.iter()
|
|
@@ -29,27 +31,18 @@ pub fn transform_report(report: Report) -> Report {
|
|
|
29
31
|
.map(|frame| {
|
|
30
32
|
let frame = frame.to_owned();
|
|
31
33
|
let mut s = frame.filename.unwrap();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
let stripped = cwd
|
|
35
|
+
.and_then(|c| s.strip_prefix(c))
|
|
36
|
+
.and_then(|rest| rest.strip_prefix('/'));
|
|
37
|
+
if let Some(rest) = stripped {
|
|
38
|
+
s = rest.to_string();
|
|
39
|
+
} else if let Some(i) = s.find("/gems/") {
|
|
40
|
+
s = s[(i + 1)..].to_string();
|
|
41
|
+
} else if let Some(i) = s.find("/ruby/") {
|
|
42
|
+
s = s[(i + 6)..].to_string();
|
|
43
|
+
if let Some(i) = s.find('/') {
|
|
44
|
+
s = s[(i + 1)..].to_string();
|
|
35
45
|
}
|
|
36
|
-
None => match s.find("/gems/") {
|
|
37
|
-
Some(i) => {
|
|
38
|
-
s = s[(i + 1)..].to_string();
|
|
39
|
-
}
|
|
40
|
-
None => match s.find("/ruby/") {
|
|
41
|
-
Some(i) => {
|
|
42
|
-
s = s[(i + 6)..].to_string();
|
|
43
|
-
match s.find("/") {
|
|
44
|
-
Some(i) => {
|
|
45
|
-
s = s[(i + 1)..].to_string();
|
|
46
|
-
}
|
|
47
|
-
None => {}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
None => {}
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
46
|
}
|
|
54
47
|
|
|
55
48
|
// something
|
|
@@ -72,9 +65,7 @@ pub fn transform_report(report: Report) -> Report {
|
|
|
72
65
|
})
|
|
73
66
|
.collect();
|
|
74
67
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
new_report
|
|
68
|
+
Report::new(data).metadata(report.metadata.clone())
|
|
78
69
|
}
|
|
79
70
|
|
|
80
71
|
#[no_mangle]
|
|
@@ -108,7 +99,9 @@ pub extern "C" fn initialize_logging(logging_level: u32) -> bool {
|
|
|
108
99
|
}
|
|
109
100
|
|
|
110
101
|
#[no_mangle]
|
|
111
|
-
|
|
102
|
+
/// # Safety
|
|
103
|
+
/// All pointer arguments must be valid, non-null, null-terminated C strings.
|
|
104
|
+
pub unsafe extern "C" fn initialize_agent(
|
|
112
105
|
application_name: *const c_char,
|
|
113
106
|
server_address: *const c_char,
|
|
114
107
|
basic_auth_user: *const c_char,
|
|
@@ -178,14 +171,14 @@ pub extern "C" fn initialize_agent(
|
|
|
178
171
|
RBSPY_VERSION,
|
|
179
172
|
rbspy,
|
|
180
173
|
)
|
|
181
|
-
.func(
|
|
174
|
+
.func(transform_report_with_current_dir)
|
|
182
175
|
.tags(tags);
|
|
183
176
|
|
|
184
|
-
if basic_auth_user
|
|
177
|
+
if !basic_auth_user.is_empty() && !basic_auth_password.is_empty() {
|
|
185
178
|
agent_builder = agent_builder.basic_auth(basic_auth_user, basic_auth_password);
|
|
186
179
|
}
|
|
187
180
|
|
|
188
|
-
if tenant_id
|
|
181
|
+
if !tenant_id.is_empty() {
|
|
189
182
|
agent_builder = agent_builder.tenant_id(tenant_id);
|
|
190
183
|
}
|
|
191
184
|
|
|
@@ -214,7 +207,9 @@ pub extern "C" fn drop_agent() -> bool {
|
|
|
214
207
|
}
|
|
215
208
|
|
|
216
209
|
#[no_mangle]
|
|
217
|
-
|
|
210
|
+
/// # Safety
|
|
211
|
+
/// `key` and `value` must be valid, non-null, null-terminated C strings.
|
|
212
|
+
pub unsafe extern "C" fn add_thread_tag(key: *const c_char, value: *const c_char) -> bool {
|
|
218
213
|
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
|
|
219
214
|
let value = unsafe { CStr::from_ptr(value) }
|
|
220
215
|
.to_str()
|
|
@@ -229,7 +224,9 @@ pub extern "C" fn add_thread_tag(key: *const c_char, value: *const c_char) -> bo
|
|
|
229
224
|
}
|
|
230
225
|
|
|
231
226
|
#[no_mangle]
|
|
232
|
-
|
|
227
|
+
/// # Safety
|
|
228
|
+
/// `key` and `value` must be valid, non-null, null-terminated C strings.
|
|
229
|
+
pub unsafe extern "C" fn remove_thread_tag(key: *const c_char, value: *const c_char) -> bool {
|
|
233
230
|
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
|
|
234
231
|
let value = unsafe { CStr::from_ptr(value) }
|
|
235
232
|
.to_str()
|
|
@@ -243,7 +240,7 @@ pub extern "C" fn remove_thread_tag(key: *const c_char, value: *const c_char) ->
|
|
|
243
240
|
.is_ok()
|
|
244
241
|
}
|
|
245
242
|
|
|
246
|
-
fn string_to_tags
|
|
243
|
+
fn string_to_tags(tags: &str) -> Vec<(&str, &str)> {
|
|
247
244
|
let mut tags_vec = Vec::new();
|
|
248
245
|
// check if string is empty
|
|
249
246
|
if tags.is_empty() {
|
|
@@ -259,3 +256,93 @@ fn string_to_tags<'a>(tags: &'a str) -> Vec<(&'a str, &'a str)> {
|
|
|
259
256
|
|
|
260
257
|
tags_vec
|
|
261
258
|
}
|
|
259
|
+
|
|
260
|
+
#[cfg(test)]
|
|
261
|
+
mod tests {
|
|
262
|
+
use super::*;
|
|
263
|
+
use pyroscope::backend::{Report, StackFrame, StackTrace};
|
|
264
|
+
use std::collections::HashMap;
|
|
265
|
+
|
|
266
|
+
fn report_with_filename(filename: &str) -> Report {
|
|
267
|
+
let stacktrace = StackTrace {
|
|
268
|
+
frames: vec![StackFrame {
|
|
269
|
+
filename: Some(filename.to_string()),
|
|
270
|
+
..Default::default()
|
|
271
|
+
}],
|
|
272
|
+
..Default::default()
|
|
273
|
+
};
|
|
274
|
+
Report::new(HashMap::from([(stacktrace, 1)]))
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
fn transformed_filename(report: Report) -> String {
|
|
278
|
+
let (stacktrace, _) = report.data.iter().next().unwrap();
|
|
279
|
+
stacktrace.frames[0].filename.clone().unwrap()
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
#[test]
|
|
283
|
+
fn transform_report_does_not_panic_when_cwd_is_a_suffix_of_filename() {
|
|
284
|
+
let report = report_with_filename("bin/rails");
|
|
285
|
+
let out = transform_report(report, Some("/rails"));
|
|
286
|
+
assert_eq!(transformed_filename(out), "bin/rails");
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
#[test]
|
|
290
|
+
fn transform_report_strips_cwd_prefix() {
|
|
291
|
+
let report = report_with_filename("/rails/app/models/user.rb");
|
|
292
|
+
let out = transform_report(report, Some("/rails"));
|
|
293
|
+
assert_eq!(transformed_filename(out), "app/models/user.rb");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
#[test]
|
|
297
|
+
fn transform_report_rewrites_gems_path() {
|
|
298
|
+
let report =
|
|
299
|
+
report_with_filename("/usr/local/bundle/gems/activerecord-7.0.0/lib/active_record.rb");
|
|
300
|
+
let out = transform_report(report, None);
|
|
301
|
+
assert_eq!(
|
|
302
|
+
transformed_filename(out),
|
|
303
|
+
"gems/activerecord-7.0.0/lib/active_record.rb",
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
#[test]
|
|
308
|
+
fn transform_report_rewrites_ruby_stdlib_path() {
|
|
309
|
+
let report = report_with_filename("/usr/local/lib/ruby/3.3.0/json/common.rb");
|
|
310
|
+
let out = transform_report(report, None);
|
|
311
|
+
assert_eq!(transformed_filename(out), "json/common.rb");
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
#[test]
|
|
315
|
+
fn transform_report_leaves_unrelated_filename_unchanged() {
|
|
316
|
+
let report = report_with_filename("/tmp/unrelated.rb");
|
|
317
|
+
let out = transform_report(report, Some("/app"));
|
|
318
|
+
assert_eq!(transformed_filename(out), "/tmp/unrelated.rb");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
#[test]
|
|
322
|
+
fn test_cargo_version_matches_ruby_version() {
|
|
323
|
+
let cargo_version = env!("CARGO_PKG_VERSION");
|
|
324
|
+
let version_rb = include_str!("../../../lib/pyroscope/version.rb");
|
|
325
|
+
let ruby_version = version_rb
|
|
326
|
+
.lines()
|
|
327
|
+
.find_map(|line| {
|
|
328
|
+
let line = line.trim();
|
|
329
|
+
if line.starts_with("VERSION") {
|
|
330
|
+
let start = line.find('\'')?;
|
|
331
|
+
let end = line.rfind('\'')?;
|
|
332
|
+
if start < end {
|
|
333
|
+
Some(&line[start + 1..end])
|
|
334
|
+
} else {
|
|
335
|
+
None
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
None
|
|
339
|
+
}
|
|
340
|
+
})
|
|
341
|
+
.expect("could not find VERSION in lib/pyroscope/version.rb");
|
|
342
|
+
|
|
343
|
+
assert_eq!(
|
|
344
|
+
cargo_version, ruby_version,
|
|
345
|
+
"Cargo.toml version ({cargo_version}) does not match lib/pyroscope/version.rb ({ruby_version})"
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
}
|
data/lib/pyroscope/version.rb
CHANGED
data/pyroscope.gemspec
CHANGED
|
@@ -14,42 +14,31 @@ Gem::Specification.new do |s|
|
|
|
14
14
|
s.description = 'Pyroscope FFI Integration for Ruby'
|
|
15
15
|
s.authors = ['Pyroscope Team']
|
|
16
16
|
s.email = ['contact@pyroscope.io']
|
|
17
|
-
s.homepage = 'https://pyroscope
|
|
17
|
+
s.homepage = 'https://grafana.com/oss/pyroscope/'
|
|
18
18
|
s.license = 'Apache-2.0'
|
|
19
19
|
s.metadata = {
|
|
20
|
-
"homepage_uri" => "https://pyroscope
|
|
21
|
-
"bug_tracker_uri" => "https://github.com/
|
|
22
|
-
"documentation_uri" => "https://
|
|
23
|
-
"
|
|
24
|
-
"source_code_uri" => "https://github.com/pyroscope-io/pyroscope-rs/tree/main/pyroscope_ffi/ruby",
|
|
20
|
+
"homepage_uri" => "https://grafana.com/oss/pyroscope/",
|
|
21
|
+
"bug_tracker_uri" => "https://github.com/grafana/pyroscope-ruby/issues",
|
|
22
|
+
"documentation_uri" => "https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/ruby/",
|
|
23
|
+
"source_code_uri" => "https://github.com/grafana/pyroscope-ruby",
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
# Specify which files should be added to the gem when it is released.
|
|
28
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
29
|
-
#s.files = Dir.chdir(__dir__) do
|
|
30
|
-
#`git ls-files -z`.split("\x0").reject do |f|
|
|
31
|
-
#(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
32
|
-
#end
|
|
33
|
-
#end
|
|
34
|
-
# s.files = `git ls-files -z`.split("\0").reject { |f| f =~ /^(\.|G|spec|Rakefile)/ }
|
|
35
26
|
s.files = [
|
|
36
27
|
"Gemfile",
|
|
37
28
|
"Gemfile.lock",
|
|
38
29
|
"LICENSE",
|
|
39
|
-
# "Makefile",
|
|
40
30
|
"README.md",
|
|
41
|
-
|
|
31
|
+
"ext/rbspy/Cargo.lock",
|
|
42
32
|
"ext/rbspy/Cargo.toml",
|
|
43
33
|
"ext/rbspy/Rakefile",
|
|
44
|
-
"ext/rbspy/build.rs",
|
|
45
34
|
"ext/rbspy/cbindgen.toml",
|
|
46
35
|
"ext/rbspy/extconf.rb",
|
|
47
36
|
"ext/rbspy/include/rbspy.h",
|
|
37
|
+
"ext/rbspy/src/backend.rs",
|
|
48
38
|
"ext/rbspy/src/lib.rs",
|
|
49
39
|
"lib/pyroscope.rb",
|
|
50
40
|
"lib/pyroscope/version.rb",
|
|
51
41
|
"pyroscope.gemspec",
|
|
52
|
-
# "scripts/tests/test.rb",
|
|
53
42
|
]
|
|
54
43
|
s.platform = Gem::Platform::RUBY
|
|
55
44
|
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pyroscope
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pyroscope Team
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: ffi
|
|
@@ -24,7 +23,6 @@ dependencies:
|
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: '0'
|
|
27
|
-
force_ruby_platform: false
|
|
28
26
|
- !ruby/object:Gem::Dependency
|
|
29
27
|
name: bundler
|
|
30
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -65,26 +63,25 @@ files:
|
|
|
65
63
|
- Gemfile.lock
|
|
66
64
|
- LICENSE
|
|
67
65
|
- README.md
|
|
66
|
+
- ext/rbspy/Cargo.lock
|
|
68
67
|
- ext/rbspy/Cargo.toml
|
|
69
68
|
- ext/rbspy/Rakefile
|
|
70
|
-
- ext/rbspy/build.rs
|
|
71
69
|
- ext/rbspy/cbindgen.toml
|
|
72
70
|
- ext/rbspy/extconf.rb
|
|
73
71
|
- ext/rbspy/include/rbspy.h
|
|
72
|
+
- ext/rbspy/src/backend.rs
|
|
74
73
|
- ext/rbspy/src/lib.rs
|
|
75
74
|
- lib/pyroscope.rb
|
|
76
75
|
- lib/pyroscope/version.rb
|
|
77
76
|
- pyroscope.gemspec
|
|
78
|
-
homepage: https://pyroscope
|
|
77
|
+
homepage: https://grafana.com/oss/pyroscope/
|
|
79
78
|
licenses:
|
|
80
79
|
- Apache-2.0
|
|
81
80
|
metadata:
|
|
82
|
-
homepage_uri: https://pyroscope
|
|
83
|
-
bug_tracker_uri: https://github.com/
|
|
84
|
-
documentation_uri: https://
|
|
85
|
-
|
|
86
|
-
source_code_uri: https://github.com/pyroscope-io/pyroscope-rs/tree/main/pyroscope_ffi/ruby
|
|
87
|
-
post_install_message:
|
|
81
|
+
homepage_uri: https://grafana.com/oss/pyroscope/
|
|
82
|
+
bug_tracker_uri: https://github.com/grafana/pyroscope-ruby/issues
|
|
83
|
+
documentation_uri: https://grafana.com/docs/pyroscope/latest/configure-client/language-sdks/ruby/
|
|
84
|
+
source_code_uri: https://github.com/grafana/pyroscope-ruby
|
|
88
85
|
rdoc_options: []
|
|
89
86
|
require_paths:
|
|
90
87
|
- lib
|
|
@@ -99,8 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
99
96
|
- !ruby/object:Gem::Version
|
|
100
97
|
version: '0'
|
|
101
98
|
requirements: []
|
|
102
|
-
rubygems_version:
|
|
103
|
-
signing_key:
|
|
99
|
+
rubygems_version: 4.0.6
|
|
104
100
|
specification_version: 4
|
|
105
101
|
summary: Pyroscope
|
|
106
102
|
test_files: []
|
data/ext/rbspy/build.rs
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
extern crate cbindgen;
|
|
2
|
-
|
|
3
|
-
use cbindgen::Config;
|
|
4
|
-
|
|
5
|
-
fn main() {
|
|
6
|
-
let bindings = {
|
|
7
|
-
let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
|
8
|
-
let config = Config::from_file("cbindgen.toml").unwrap();
|
|
9
|
-
cbindgen::generate_with_config(&crate_dir, config).unwrap()
|
|
10
|
-
};
|
|
11
|
-
bindings.write_to_file("include/rbspy.h");
|
|
12
|
-
}
|