pyroscope 0.6.7 → 1.0.9
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 -54
- data/ext/rbspy/Cargo.lock +2743 -0
- data/ext/rbspy/Cargo.toml +7 -10
- data/ext/rbspy/Rakefile +1 -1
- data/ext/rbspy/cbindgen.toml +1 -6
- data/ext/rbspy/include/rbspy.h +15 -13
- data/ext/rbspy/src/backend.rs +199 -0
- data/ext/rbspy/src/lib.rs +170 -180
- data/lib/pyroscope/version.rb +1 -1
- data/lib/pyroscope.rb +9 -30
- data/pyroscope.gemspec +8 -26
- metadata +10 -22
- data/ext/rbspy/build.rs +0 -12
- data/ext/thread_id/Cargo.toml +0 -15
- data/ext/thread_id/Rakefile +0 -163
- data/ext/thread_id/build.rs +0 -12
- data/ext/thread_id/cbindgen.toml +0 -22
- data/ext/thread_id/extconf.rb +0 -11
- data/ext/thread_id/include/thread_id.h +0 -17
- data/ext/thread_id/src/lib.rs +0 -4
data/ext/rbspy/src/lib.rs
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
mod backend;
|
|
2
|
+
|
|
3
|
+
use rbspy::sampler::Sampler;
|
|
4
|
+
use remoteprocess::Pid;
|
|
2
5
|
use std::env;
|
|
3
6
|
use std::ffi::CStr;
|
|
4
|
-
use std::hash::Hasher;
|
|
5
7
|
use std::os::raw::c_char;
|
|
6
|
-
use std::str::FromStr;
|
|
7
|
-
|
|
8
|
-
use ffikit::Signal;
|
|
9
|
-
use pyroscope_rbspy::{rbspy_backend, RbspyConfig};
|
|
10
8
|
|
|
11
|
-
use
|
|
12
|
-
use pyroscope::{
|
|
13
|
-
use pyroscope::
|
|
14
|
-
use pyroscope::pyroscope::ReportEncoding;
|
|
9
|
+
use crate::backend::Rbspy;
|
|
10
|
+
use pyroscope::backend::{BackendConfig, BackendImpl, Report, StackFrame, Tag};
|
|
11
|
+
use pyroscope::pyroscope::PyroscopeAgentBuilder;
|
|
15
12
|
|
|
16
13
|
const LOG_TAG: &str = "Pyroscope::rbspy::ffi";
|
|
14
|
+
const RBSPY_NAME: &str = "rbspy";
|
|
15
|
+
const RBSPY_VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
17
16
|
|
|
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
|
+
}
|
|
18
22
|
|
|
19
|
-
pub fn transform_report(report: Report) -> Report {
|
|
20
|
-
let cwd = env::current_dir().unwrap();
|
|
21
|
-
let cwd = cwd.to_str().unwrap_or("");
|
|
22
|
-
|
|
23
|
+
pub fn transform_report(report: Report, cwd: Option<&str>) -> Report {
|
|
23
24
|
let data = report
|
|
24
25
|
.data
|
|
25
26
|
.iter()
|
|
@@ -30,27 +31,18 @@ pub fn transform_report(report: Report) -> Report {
|
|
|
30
31
|
.map(|frame| {
|
|
31
32
|
let frame = frame.to_owned();
|
|
32
33
|
let mut s = frame.filename.unwrap();
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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();
|
|
36
45
|
}
|
|
37
|
-
None => match s.find("/gems/") {
|
|
38
|
-
Some(i) => {
|
|
39
|
-
s = s[(i + 1)..].to_string();
|
|
40
|
-
}
|
|
41
|
-
None => match s.find("/ruby/") {
|
|
42
|
-
Some(i) => {
|
|
43
|
-
s = s[(i + 6)..].to_string();
|
|
44
|
-
match s.find("/") {
|
|
45
|
-
Some(i) => {
|
|
46
|
-
s = s[(i + 1)..].to_string();
|
|
47
|
-
}
|
|
48
|
-
None => {}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
None => {}
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
46
|
}
|
|
55
47
|
|
|
56
48
|
// something
|
|
@@ -73,9 +65,7 @@ pub fn transform_report(report: Report) -> Report {
|
|
|
73
65
|
})
|
|
74
66
|
.collect();
|
|
75
67
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
new_report
|
|
68
|
+
Report::new(data).metadata(report.metadata.clone())
|
|
79
69
|
}
|
|
80
70
|
|
|
81
71
|
#[no_mangle]
|
|
@@ -109,42 +99,27 @@ pub extern "C" fn initialize_logging(logging_level: u32) -> bool {
|
|
|
109
99
|
}
|
|
110
100
|
|
|
111
101
|
#[no_mangle]
|
|
112
|
-
|
|
102
|
+
/// # Safety
|
|
103
|
+
/// All pointer arguments must be valid, non-null, null-terminated C strings.
|
|
104
|
+
pub unsafe extern "C" fn initialize_agent(
|
|
113
105
|
application_name: *const c_char,
|
|
114
106
|
server_address: *const c_char,
|
|
115
|
-
auth_token: *const c_char,
|
|
116
107
|
basic_auth_user: *const c_char,
|
|
117
108
|
basic_auth_password: *const c_char,
|
|
118
109
|
sample_rate: u32,
|
|
119
|
-
detect_subprocesses: bool,
|
|
120
110
|
oncpu: bool,
|
|
121
111
|
report_pid: bool,
|
|
122
112
|
report_thread_id: bool,
|
|
123
113
|
tags: *const c_char,
|
|
124
|
-
compression: *const c_char,
|
|
125
|
-
_report_encoding: *const c_char,
|
|
126
114
|
tenant_id: *const c_char,
|
|
127
115
|
http_headers_json: *const c_char,
|
|
128
116
|
) -> bool {
|
|
129
|
-
// Initialize FFIKit
|
|
130
|
-
let recv = ffikit::initialize_ffi().unwrap();
|
|
131
|
-
|
|
132
117
|
let application_name = unsafe { CStr::from_ptr(application_name) }
|
|
133
118
|
.to_str()
|
|
134
119
|
.unwrap()
|
|
135
120
|
.to_string();
|
|
136
121
|
|
|
137
|
-
let
|
|
138
|
-
.to_str()
|
|
139
|
-
.unwrap()
|
|
140
|
-
.to_string();
|
|
141
|
-
|
|
142
|
-
let adhoc_server_address = std::env::var("PYROSCOPE_ADHOC_SERVER_ADDRESS");
|
|
143
|
-
if let Ok(adhoc_server_address) = adhoc_server_address {
|
|
144
|
-
server_address = adhoc_server_address
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
let auth_token = unsafe { CStr::from_ptr(auth_token) }
|
|
122
|
+
let server_address = unsafe { CStr::from_ptr(server_address) }
|
|
148
123
|
.to_str()
|
|
149
124
|
.unwrap()
|
|
150
125
|
.to_string();
|
|
@@ -164,11 +139,6 @@ pub extern "C" fn initialize_agent(
|
|
|
164
139
|
.unwrap()
|
|
165
140
|
.to_string();
|
|
166
141
|
|
|
167
|
-
let compression_string = unsafe { CStr::from_ptr(compression) }
|
|
168
|
-
.to_str()
|
|
169
|
-
.unwrap()
|
|
170
|
-
.to_string();
|
|
171
|
-
|
|
172
142
|
let tenant_id = unsafe { CStr::from_ptr(tenant_id) }
|
|
173
143
|
.to_str()
|
|
174
144
|
.unwrap()
|
|
@@ -179,35 +149,36 @@ pub extern "C" fn initialize_agent(
|
|
|
179
149
|
.unwrap()
|
|
180
150
|
.to_string();
|
|
181
151
|
|
|
182
|
-
let compression = Compression::from_str(&compression_string);
|
|
183
|
-
|
|
184
152
|
let pid = std::process::id();
|
|
185
153
|
|
|
186
|
-
let
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
154
|
+
let backend_config = BackendConfig {
|
|
155
|
+
report_thread_id,
|
|
156
|
+
report_thread_name: false,
|
|
157
|
+
report_pid,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
let sampler = Sampler::new(pid as Pid, sample_rate, false, None, false, None, oncpu);
|
|
193
161
|
|
|
194
162
|
let tags_ref = tags_string.as_str();
|
|
195
163
|
let tags = string_to_tags(tags_ref);
|
|
196
|
-
let rbspy =
|
|
197
|
-
|
|
198
|
-
let mut agent_builder =
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
164
|
+
let rbspy = BackendImpl::new(Box::new(Rbspy::new(sampler, sample_rate, backend_config)));
|
|
165
|
+
|
|
166
|
+
let mut agent_builder = PyroscopeAgentBuilder::new(
|
|
167
|
+
server_address,
|
|
168
|
+
application_name,
|
|
169
|
+
sample_rate,
|
|
170
|
+
RBSPY_NAME,
|
|
171
|
+
RBSPY_VERSION,
|
|
172
|
+
rbspy,
|
|
173
|
+
)
|
|
174
|
+
.func(transform_report_with_current_dir)
|
|
175
|
+
.tags(tags);
|
|
176
|
+
|
|
177
|
+
if !basic_auth_user.is_empty() && !basic_auth_password.is_empty() {
|
|
207
178
|
agent_builder = agent_builder.basic_auth(basic_auth_user, basic_auth_password);
|
|
208
179
|
}
|
|
209
180
|
|
|
210
|
-
if tenant_id
|
|
181
|
+
if !tenant_id.is_empty() {
|
|
211
182
|
agent_builder = agent_builder.tenant_id(tenant_id);
|
|
212
183
|
}
|
|
213
184
|
|
|
@@ -216,131 +187,60 @@ pub extern "C" fn initialize_agent(
|
|
|
216
187
|
Ok(http_headers) => {
|
|
217
188
|
agent_builder = agent_builder.http_headers(http_headers);
|
|
218
189
|
}
|
|
219
|
-
Err(e) => {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
log::error!(target: LOG_TAG, "parse_http_headers_json error {}", e);
|
|
223
|
-
}
|
|
224
|
-
pyroscope::PyroscopeError::AdHoc(e) => {
|
|
225
|
-
log::error!(target: LOG_TAG, "parse_http_headers_json {}", e);
|
|
226
|
-
}
|
|
227
|
-
_ => {}
|
|
190
|
+
Err(e) => match e {
|
|
191
|
+
pyroscope::PyroscopeError::Json(e) => {
|
|
192
|
+
log::error!(target: LOG_TAG, "parse_http_headers_json error {}", e);
|
|
228
193
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if let Ok(compression) = compression {
|
|
233
|
-
agent_builder = agent_builder.compression(compression);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
let agent = agent_builder.build().unwrap();
|
|
237
|
-
|
|
238
|
-
let agent_running = agent.start().unwrap();
|
|
239
|
-
|
|
240
|
-
std::thread::spawn(move || {
|
|
241
|
-
while let Ok(signal) = recv.recv() {
|
|
242
|
-
match signal {
|
|
243
|
-
Signal::Kill => {
|
|
244
|
-
agent_running.stop().unwrap();
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
Signal::AddGlobalTag(name, value) => {
|
|
248
|
-
agent_running.add_global_tag(Tag::new(name, value)).unwrap();
|
|
249
|
-
}
|
|
250
|
-
Signal::RemoveGlobalTag(name, value) => {
|
|
251
|
-
agent_running
|
|
252
|
-
.remove_global_tag(Tag::new(name, value))
|
|
253
|
-
.unwrap();
|
|
254
|
-
}
|
|
255
|
-
Signal::AddThreadTag(thread_id, key, value) => {
|
|
256
|
-
let tag = Tag::new(key, value);
|
|
257
|
-
agent_running.add_thread_tag(thread_id, tag).unwrap();
|
|
258
|
-
}
|
|
259
|
-
Signal::RemoveThreadTag(thread_id, key, value) => {
|
|
260
|
-
let tag = Tag::new(key, value);
|
|
261
|
-
agent_running.remove_thread_tag(thread_id, tag).unwrap();
|
|
262
|
-
}
|
|
194
|
+
pyroscope::PyroscopeError::AdHoc(e) => {
|
|
195
|
+
log::error!(target: LOG_TAG, "parse_http_headers_json {}", e);
|
|
263
196
|
}
|
|
264
|
-
|
|
265
|
-
|
|
197
|
+
_ => {}
|
|
198
|
+
},
|
|
199
|
+
}
|
|
266
200
|
|
|
267
|
-
|
|
201
|
+
pyroscope::ffikit::run(agent_builder).is_ok()
|
|
268
202
|
}
|
|
269
203
|
|
|
270
204
|
#[no_mangle]
|
|
271
205
|
pub extern "C" fn drop_agent() -> bool {
|
|
272
|
-
|
|
273
|
-
ffikit::send(ffikit::Signal::Kill).unwrap();
|
|
274
|
-
|
|
275
|
-
true
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
#[no_mangle]
|
|
279
|
-
pub extern "C" fn add_thread_tag(thread_id: u64, key: *const c_char, value: *const c_char) -> bool {
|
|
280
|
-
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
|
|
281
|
-
let value = unsafe { CStr::from_ptr(value) }
|
|
282
|
-
.to_str()
|
|
283
|
-
.unwrap()
|
|
284
|
-
.to_owned();
|
|
285
|
-
|
|
286
|
-
let pid = std::process::id();
|
|
287
|
-
let mut hasher = DefaultHasher::new();
|
|
288
|
-
hasher.write_u64(thread_id % pid as u64);
|
|
289
|
-
let id = hasher.finish();
|
|
290
|
-
|
|
291
|
-
ffikit::send(ffikit::Signal::AddThreadTag(id, key, value)).unwrap();
|
|
292
|
-
|
|
293
|
-
true
|
|
206
|
+
pyroscope::ffikit::send(pyroscope::ffikit::Signal::Kill).is_ok()
|
|
294
207
|
}
|
|
295
208
|
|
|
296
209
|
#[no_mangle]
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
) -> bool {
|
|
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 {
|
|
300
213
|
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
|
|
301
214
|
let value = unsafe { CStr::from_ptr(value) }
|
|
302
215
|
.to_str()
|
|
303
216
|
.unwrap()
|
|
304
217
|
.to_owned();
|
|
305
218
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
ffikit::send(ffikit::Signal::RemoveThreadTag(id, key, value)).unwrap();
|
|
312
|
-
|
|
313
|
-
true
|
|
219
|
+
pyroscope::ffikit::send(pyroscope::ffikit::Signal::AddThreadTag(
|
|
220
|
+
backend::self_thread_id(),
|
|
221
|
+
Tag { key, value },
|
|
222
|
+
))
|
|
223
|
+
.is_ok()
|
|
314
224
|
}
|
|
315
225
|
|
|
316
226
|
#[no_mangle]
|
|
317
|
-
|
|
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 {
|
|
318
230
|
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
|
|
319
231
|
let value = unsafe { CStr::from_ptr(value) }
|
|
320
232
|
.to_str()
|
|
321
233
|
.unwrap()
|
|
322
234
|
.to_owned();
|
|
323
235
|
|
|
324
|
-
ffikit::send(ffikit::Signal::
|
|
325
|
-
|
|
326
|
-
|
|
236
|
+
pyroscope::ffikit::send(pyroscope::ffikit::Signal::RemoveThreadTag(
|
|
237
|
+
backend::self_thread_id(),
|
|
238
|
+
Tag { key, value },
|
|
239
|
+
))
|
|
240
|
+
.is_ok()
|
|
327
241
|
}
|
|
328
242
|
|
|
329
|
-
|
|
330
|
-
pub extern "C" fn remove_global_tag(key: *const c_char, value: *const c_char) -> bool {
|
|
331
|
-
let key = unsafe { CStr::from_ptr(key) }.to_str().unwrap().to_owned();
|
|
332
|
-
let value = unsafe { CStr::from_ptr(value) }
|
|
333
|
-
.to_str()
|
|
334
|
-
.unwrap()
|
|
335
|
-
.to_owned();
|
|
336
|
-
|
|
337
|
-
ffikit::send(ffikit::Signal::RemoveGlobalTag(key, value)).unwrap();
|
|
338
|
-
|
|
339
|
-
true
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Convert a string of tags to a Vec<(&str, &str)>
|
|
343
|
-
fn string_to_tags<'a>(tags: &'a str) -> Vec<(&'a str, &'a str)> {
|
|
243
|
+
fn string_to_tags(tags: &str) -> Vec<(&str, &str)> {
|
|
344
244
|
let mut tags_vec = Vec::new();
|
|
345
245
|
// check if string is empty
|
|
346
246
|
if tags.is_empty() {
|
|
@@ -356,3 +256,93 @@ fn string_to_tags<'a>(tags: &'a str) -> Vec<(&'a str, &'a str)> {
|
|
|
356
256
|
|
|
357
257
|
tags_vec
|
|
358
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/lib/pyroscope.rb
CHANGED
|
@@ -9,20 +9,12 @@ module Pyroscope
|
|
|
9
9
|
extend FFI::Library
|
|
10
10
|
ffi_lib File.expand_path(File.dirname(__FILE__)) + "/rbspy/rbspy.#{RbConfig::CONFIG["DLEXT"]}"
|
|
11
11
|
attach_function :initialize_logging, [:int], :bool
|
|
12
|
-
attach_function :initialize_agent, [:string, :string, :string, :string, :
|
|
13
|
-
attach_function :add_thread_tag, [:
|
|
14
|
-
attach_function :remove_thread_tag, [:
|
|
15
|
-
attach_function :add_global_tag, [:string, :string], :bool
|
|
16
|
-
attach_function :remove_global_tag, [:string, :string], :bool
|
|
12
|
+
attach_function :initialize_agent, [:string, :string, :string, :string, :int, :bool, :bool, :bool, :string, :string, :string], :bool
|
|
13
|
+
attach_function :add_thread_tag, [:string, :string], :bool
|
|
14
|
+
attach_function :remove_thread_tag, [:string, :string], :bool
|
|
17
15
|
attach_function :drop_agent, [], :bool
|
|
18
16
|
end
|
|
19
17
|
|
|
20
|
-
module Utils
|
|
21
|
-
extend FFI::Library
|
|
22
|
-
ffi_lib File.expand_path(File.dirname(__FILE__)) + "/thread_id/thread_id.#{RbConfig::CONFIG["DLEXT"]}"
|
|
23
|
-
attach_function :thread_id, [], :uint64
|
|
24
|
-
end
|
|
25
|
-
|
|
26
18
|
if defined?(::Rails::Engine)
|
|
27
19
|
class Engine < ::Rails::Engine
|
|
28
20
|
config.after_initialize do
|
|
@@ -37,12 +29,10 @@ module Pyroscope
|
|
|
37
29
|
:application_name,
|
|
38
30
|
:app_name,
|
|
39
31
|
:server_address,
|
|
40
|
-
:auth_token,
|
|
41
32
|
:basic_auth_username,
|
|
42
33
|
:basic_auth_password,
|
|
43
34
|
:log_level,
|
|
44
35
|
:sample_rate,
|
|
45
|
-
:detect_subprocesses,
|
|
46
36
|
:oncpu,
|
|
47
37
|
:report_pid,
|
|
48
38
|
:report_thread_id,
|
|
@@ -58,11 +48,9 @@ module Pyroscope
|
|
|
58
48
|
# defaults:
|
|
59
49
|
self.application_name = ''
|
|
60
50
|
self.server_address = 'http://localhost:4040'
|
|
61
|
-
self.auth_token = ''
|
|
62
51
|
self.basic_auth_username = ''
|
|
63
52
|
self.basic_auth_password = ''
|
|
64
53
|
self.sample_rate = 100
|
|
65
|
-
self.detect_subprocesses = false
|
|
66
54
|
self.oncpu = true
|
|
67
55
|
self.report_pid = false
|
|
68
56
|
self.report_thread_id = false
|
|
@@ -109,17 +97,13 @@ module Pyroscope
|
|
|
109
97
|
# these are defaults in case user-provided values are nil:
|
|
110
98
|
@config.app_name || @config.application_name || "",
|
|
111
99
|
@config.server_address || "",
|
|
112
|
-
@config.auth_token || "",
|
|
113
100
|
@config.basic_auth_username || "",
|
|
114
101
|
@config.basic_auth_password || "",
|
|
115
102
|
@config.sample_rate || 100,
|
|
116
|
-
@config.detect_subprocesses || false,
|
|
117
103
|
@config.oncpu || false,
|
|
118
104
|
@config.report_pid || false,
|
|
119
105
|
@config.report_thread_id || false,
|
|
120
106
|
tags_to_string(@config.tags || {}),
|
|
121
|
-
@config.compression || "",
|
|
122
|
-
@config.report_encoding || "pprof",
|
|
123
107
|
@config.tenant_id || "",
|
|
124
108
|
http_headers_to_json(@config.http_headers || {})
|
|
125
109
|
)
|
|
@@ -137,12 +121,11 @@ module Pyroscope
|
|
|
137
121
|
end
|
|
138
122
|
|
|
139
123
|
def tag_wrapper(tags)
|
|
140
|
-
|
|
141
|
-
_add_tags(tid, tags)
|
|
124
|
+
_add_tags(tags)
|
|
142
125
|
begin
|
|
143
126
|
yield
|
|
144
127
|
ensure
|
|
145
|
-
_remove_tags(
|
|
128
|
+
_remove_tags(tags)
|
|
146
129
|
end
|
|
147
130
|
end
|
|
148
131
|
|
|
@@ -154,19 +137,15 @@ module Pyroscope
|
|
|
154
137
|
warn("deprecated. Use `Pyroscope.tag_wrapper` instead.")
|
|
155
138
|
end
|
|
156
139
|
|
|
157
|
-
def
|
|
158
|
-
return Utils.thread_id
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def _add_tags(thread_id, tags)
|
|
140
|
+
def _add_tags(tags)
|
|
162
141
|
tags.each do |tag_name, tag_value|
|
|
163
|
-
Rust.add_thread_tag(
|
|
142
|
+
Rust.add_thread_tag(tag_name.to_s, tag_value.to_s)
|
|
164
143
|
end
|
|
165
144
|
end
|
|
166
145
|
|
|
167
|
-
def _remove_tags(
|
|
146
|
+
def _remove_tags(tags)
|
|
168
147
|
tags.each do |tag_name, tag_value|
|
|
169
|
-
Rust.remove_thread_tag(
|
|
148
|
+
Rust.remove_thread_tag(tag_name.to_s, tag_value.to_s)
|
|
170
149
|
end
|
|
171
150
|
end
|
|
172
151
|
|
data/pyroscope.gemspec
CHANGED
|
@@ -14,55 +14,37 @@ 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
|
-
"ext/thread_id/Cargo.toml",
|
|
50
|
-
"ext/thread_id/Rakefile",
|
|
51
|
-
"ext/thread_id/build.rs",
|
|
52
|
-
"ext/thread_id/cbindgen.toml",
|
|
53
|
-
"ext/thread_id/extconf.rb",
|
|
54
|
-
"ext/thread_id/include/thread_id.h",
|
|
55
|
-
"ext/thread_id/src/lib.rs",
|
|
56
39
|
"lib/pyroscope.rb",
|
|
57
40
|
"lib/pyroscope/version.rb",
|
|
58
41
|
"pyroscope.gemspec",
|
|
59
|
-
# "scripts/tests/test.rb",
|
|
60
42
|
]
|
|
61
43
|
s.platform = Gem::Platform::RUBY
|
|
62
44
|
|
|
63
45
|
s.required_ruby_version = ">= 1.9.3"
|
|
64
46
|
|
|
65
|
-
s.extensions = ['ext/rbspy/extconf.rb'
|
|
47
|
+
s.extensions = ['ext/rbspy/extconf.rb']
|
|
66
48
|
|
|
67
49
|
s.add_dependency 'ffi'
|
|
68
50
|
|