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.
data/ext/rbspy/Cargo.toml CHANGED
@@ -1,21 +1,18 @@
1
1
  [package]
2
2
  name = "ffiruby"
3
- version = "0.1.0"
3
+ version = "1.0.9" # x-release-please-version
4
4
  edition = "2021"
5
- rust-version = "1.64"
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 = { path = "../../../../" }
13
- pyroscope_rbspy = { path = "../../../../pyroscope_backends/pyroscope_rbspy" }
14
- ffikit = { path = "../../../ffikit" }
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
- [build-dependencies]
20
- cbindgen = "0.28"
21
-
17
+ libc = "0.2"
18
+ anyhow = "1.0"
data/ext/rbspy/Rakefile CHANGED
@@ -5,7 +5,7 @@ require "shellwords"
5
5
  class RbspyRakeCargoHelper
6
6
  attr_reader :gemname
7
7
 
8
- def initialize(gemname=File.basename(__dir__))
8
+ def initialize(gemname="rbspy")
9
9
  @gemname = gemname
10
10
  end
11
11
 
@@ -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
- # include a comment with the version of cbindgen used to generate the file
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
@@ -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
- bool add_thread_tag(uint64_t thread_id, const char *key, const char *value);
36
-
37
- bool remove_thread_tag(uint64_t thread_id, const char *key, const char *value);
38
-
39
- bool add_global_tag(const char *key, const char *value);
40
-
41
- bool remove_global_tag(const char *key, const char *value);
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
+ }