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/Cargo.toml
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "ffiruby"
|
|
3
|
-
version = "
|
|
3
|
+
version = "1.0.9" # 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
|
-
|
|
14
|
-
|
|
15
|
-
# 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"
|
|
16
15
|
pretty_env_logger = "0.5"
|
|
17
16
|
log = "0.4"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
cbindgen = "0.28"
|
|
21
|
-
|
|
17
|
+
libc = "0.2"
|
|
18
|
+
anyhow = "1.0"
|
data/ext/rbspy/Rakefile
CHANGED
data/ext/rbspy/cbindgen.toml
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
# The language to output bindings in
|
|
2
1
|
language = "C"
|
|
3
2
|
documentation_style = "C"
|
|
4
3
|
|
|
5
4
|
style = "type"
|
|
6
5
|
|
|
7
|
-
# An optional name to use as an include guard
|
|
8
6
|
include_guard = "RBSPY_H_"
|
|
9
|
-
|
|
10
|
-
include_version = true
|
|
7
|
+
include_version = false
|
|
11
8
|
|
|
12
|
-
# An optional string of text to output at the beginning of the generated file
|
|
13
9
|
header = "/* Licensed under Apache-2.0 */"
|
|
14
10
|
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
|
|
15
11
|
|
|
@@ -18,5 +14,4 @@ tab_width = 2
|
|
|
18
14
|
line_length = 80
|
|
19
15
|
|
|
20
16
|
[parse]
|
|
21
|
-
# Do not parse dependent crates
|
|
22
17
|
parse_deps = false
|
data/ext/rbspy/include/rbspy.h
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
#ifndef RBSPY_H_
|
|
4
4
|
#define RBSPY_H_
|
|
5
5
|
|
|
6
|
-
/* Generated with cbindgen:0.28.0 */
|
|
7
|
-
|
|
8
6
|
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
|
|
9
7
|
|
|
10
8
|
#include <stdarg.h>
|
|
@@ -14,30 +12,34 @@
|
|
|
14
12
|
|
|
15
13
|
bool initialize_logging(uint32_t logging_level);
|
|
16
14
|
|
|
15
|
+
/*
|
|
16
|
+
# Safety
|
|
17
|
+
All pointer arguments must be valid, non-null, null-terminated C strings.
|
|
18
|
+
*/
|
|
17
19
|
bool initialize_agent(const char *application_name,
|
|
18
20
|
const char *server_address,
|
|
19
|
-
const char *auth_token,
|
|
20
21
|
const char *basic_auth_user,
|
|
21
22
|
const char *basic_auth_password,
|
|
22
23
|
uint32_t sample_rate,
|
|
23
|
-
bool detect_subprocesses,
|
|
24
24
|
bool oncpu,
|
|
25
25
|
bool report_pid,
|
|
26
26
|
bool report_thread_id,
|
|
27
27
|
const char *tags,
|
|
28
|
-
const char *compression,
|
|
29
|
-
const char *_report_encoding,
|
|
30
28
|
const char *tenant_id,
|
|
31
29
|
const char *http_headers_json);
|
|
32
30
|
|
|
33
31
|
bool drop_agent(void);
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
bool
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
/*
|
|
34
|
+
# Safety
|
|
35
|
+
`key` and `value` must be valid, non-null, null-terminated C strings.
|
|
36
|
+
*/
|
|
37
|
+
bool add_thread_tag(const char *key, const char *value);
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
# Safety
|
|
41
|
+
`key` and `value` must be valid, non-null, null-terminated C strings.
|
|
42
|
+
*/
|
|
43
|
+
bool remove_thread_tag(const char *key, const char *value);
|
|
42
44
|
|
|
43
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
|
+
}
|