solarwinds_apm 5.1.8 → 6.0.0.preV1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +0 -1
  3. data/ext/oboe_metal/extconf.rb +19 -23
  4. data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +1 -1
  5. data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +1 -1
  6. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +1 -1
  7. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +1 -1
  8. data/ext/oboe_metal/src/VERSION +1 -1
  9. data/ext/oboe_metal/src/oboe_api.cpp +9 -7
  10. data/ext/oboe_metal/src/oboe_api.h +7 -7
  11. data/ext/oboe_metal/src/oboe_debug.h +2 -0
  12. data/ext/oboe_metal/src/oboe_swig_wrap.cc +19 -18
  13. data/lib/oboe_metal.rb +116 -80
  14. data/lib/rails/generators/solarwinds_apm/install_generator.rb +1 -2
  15. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +44 -260
  16. data/lib/solarwinds_apm/api/current_trace_info.rb +148 -0
  17. data/lib/solarwinds_apm/api/tracing.rb +30 -0
  18. data/lib/solarwinds_apm/api/transaction_name.rb +57 -0
  19. data/lib/solarwinds_apm/api.rb +8 -15
  20. data/lib/solarwinds_apm/base.rb +4 -131
  21. data/lib/solarwinds_apm/config.rb +128 -175
  22. data/lib/solarwinds_apm/constants.rb +32 -0
  23. data/lib/solarwinds_apm/logger.rb +1 -1
  24. data/lib/solarwinds_apm/noop/context.rb +2 -5
  25. data/lib/solarwinds_apm/noop/metadata.rb +1 -2
  26. data/lib/solarwinds_apm/noop/profiling.rb +3 -7
  27. data/lib/solarwinds_apm/oboe_init_options.rb +71 -33
  28. data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +204 -0
  29. data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +163 -0
  30. data/lib/solarwinds_apm/opentelemetry/solarwinds_propagator.rb +92 -0
  31. data/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +72 -0
  32. data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +330 -0
  33. data/lib/solarwinds_apm/opentelemetry.rb +8 -0
  34. data/lib/solarwinds_apm/otel_config.rb +161 -0
  35. data/lib/solarwinds_apm/{inst → support}/logger_formatter.rb +5 -6
  36. data/lib/solarwinds_apm/{inst → support}/logging_log_event.rb +3 -6
  37. data/lib/solarwinds_apm/{inst → support}/lumberjack_formatter.rb +1 -4
  38. data/lib/solarwinds_apm/support/oboe_tracing_mode.rb +27 -0
  39. data/lib/solarwinds_apm/support/swomarginalia/LICENSE +20 -0
  40. data/lib/solarwinds_apm/support/swomarginalia/README.md +41 -0
  41. data/lib/solarwinds_apm/support/swomarginalia/comment.rb +205 -0
  42. data/lib/solarwinds_apm/support/swomarginalia/load_swomarginalia.rb +48 -0
  43. data/lib/solarwinds_apm/support/swomarginalia/railtie.rb +22 -0
  44. data/lib/solarwinds_apm/support/swomarginalia/swomarginalia.rb +86 -0
  45. data/lib/solarwinds_apm/support/transaction_cache.rb +24 -0
  46. data/lib/solarwinds_apm/support/transaction_settings.rb +26 -209
  47. data/lib/solarwinds_apm/support/transformer.rb +56 -0
  48. data/lib/solarwinds_apm/support/txn_name_manager.rb +25 -0
  49. data/lib/solarwinds_apm/support/x_trace_options.rb +42 -26
  50. data/lib/solarwinds_apm/support.rb +33 -10
  51. data/lib/solarwinds_apm/support_report.rb +10 -32
  52. data/lib/solarwinds_apm/thread_local.rb +1 -1
  53. data/lib/solarwinds_apm/version.rb +4 -4
  54. data/lib/solarwinds_apm.rb +31 -26
  55. metadata +76 -121
  56. data/.dockerignore +0 -5
  57. data/.gitignore +0 -58
  58. data/.rubocop.yml +0 -29
  59. data/.whitesource +0 -22
  60. data/.yardopts +0 -7
  61. data/CHANGELOG-appoptics.md +0 -766
  62. data/CHANGELOG.md +0 -72
  63. data/CONFIG.md +0 -31
  64. data/Gemfile +0 -15
  65. data/README.md +0 -385
  66. data/bin/solarwinds_apm_config +0 -15
  67. data/examples/prepend.rb +0 -13
  68. data/examples/sdk_examples.rb +0 -158
  69. data/ext/oboe_metal/README.md +0 -69
  70. data/ext/oboe_metal/extconf_local.rb +0 -75
  71. data/ext/oboe_metal/lib/.keep +0 -0
  72. data/ext/oboe_metal/noop/noop.c +0 -8
  73. data/ext/oboe_metal/src/README.md +0 -6
  74. data/ext/oboe_metal/src/frames.cc +0 -247
  75. data/ext/oboe_metal/src/frames.h +0 -40
  76. data/ext/oboe_metal/src/logging.cc +0 -97
  77. data/ext/oboe_metal/src/logging.h +0 -34
  78. data/ext/oboe_metal/src/profiling.cc +0 -435
  79. data/ext/oboe_metal/src/profiling.h +0 -78
  80. data/ext/oboe_metal/test/CMakeLists.txt +0 -53
  81. data/ext/oboe_metal/test/FindGMock.cmake +0 -43
  82. data/ext/oboe_metal/test/README.md +0 -56
  83. data/ext/oboe_metal/test/frames_test.cc +0 -164
  84. data/ext/oboe_metal/test/profiling_test.cc +0 -93
  85. data/ext/oboe_metal/test/ruby_inc_dir.rb +0 -8
  86. data/ext/oboe_metal/test/ruby_prefix.rb +0 -8
  87. data/ext/oboe_metal/test/ruby_test_helper.rb +0 -67
  88. data/ext/oboe_metal/test/test.h +0 -11
  89. data/ext/oboe_metal/test/test_main.cc +0 -32
  90. data/init.rb +0 -4
  91. data/lib/solarwinds_apm/api/layerinit.rb +0 -41
  92. data/lib/solarwinds_apm/api/logging.rb +0 -356
  93. data/lib/solarwinds_apm/api/memcache.rb +0 -37
  94. data/lib/solarwinds_apm/api/metrics.rb +0 -63
  95. data/lib/solarwinds_apm/api/util.rb +0 -98
  96. data/lib/solarwinds_apm/frameworks/grape.rb +0 -96
  97. data/lib/solarwinds_apm/frameworks/padrino.rb +0 -78
  98. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +0 -100
  99. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +0 -50
  100. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +0 -50
  101. data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +0 -88
  102. data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +0 -26
  103. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +0 -29
  104. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +0 -22
  105. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +0 -103
  106. data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +0 -14
  107. data/lib/solarwinds_apm/frameworks/rails.rb +0 -100
  108. data/lib/solarwinds_apm/frameworks/sinatra.rb +0 -96
  109. data/lib/solarwinds_apm/inst/bunny-client.rb +0 -157
  110. data/lib/solarwinds_apm/inst/bunny-consumer.rb +0 -102
  111. data/lib/solarwinds_apm/inst/curb.rb +0 -289
  112. data/lib/solarwinds_apm/inst/dalli.rb +0 -89
  113. data/lib/solarwinds_apm/inst/delayed_job.rb +0 -100
  114. data/lib/solarwinds_apm/inst/excon.rb +0 -113
  115. data/lib/solarwinds_apm/inst/faraday.rb +0 -96
  116. data/lib/solarwinds_apm/inst/graphql.rb +0 -206
  117. data/lib/solarwinds_apm/inst/grpc_client.rb +0 -147
  118. data/lib/solarwinds_apm/inst/grpc_server.rb +0 -119
  119. data/lib/solarwinds_apm/inst/httpclient.rb +0 -182
  120. data/lib/solarwinds_apm/inst/memcached.rb +0 -86
  121. data/lib/solarwinds_apm/inst/mongo.rb +0 -246
  122. data/lib/solarwinds_apm/inst/mongo2.rb +0 -225
  123. data/lib/solarwinds_apm/inst/moped.rb +0 -466
  124. data/lib/solarwinds_apm/inst/net_http.rb +0 -60
  125. data/lib/solarwinds_apm/inst/rack.rb +0 -223
  126. data/lib/solarwinds_apm/inst/rack_cache.rb +0 -35
  127. data/lib/solarwinds_apm/inst/redis.rb +0 -280
  128. data/lib/solarwinds_apm/inst/redis_v4.rb +0 -273
  129. data/lib/solarwinds_apm/inst/resque.rb +0 -129
  130. data/lib/solarwinds_apm/inst/rest-client.rb +0 -43
  131. data/lib/solarwinds_apm/inst/sequel.rb +0 -241
  132. data/lib/solarwinds_apm/inst/sidekiq-client.rb +0 -63
  133. data/lib/solarwinds_apm/inst/sidekiq-worker.rb +0 -64
  134. data/lib/solarwinds_apm/inst/typhoeus.rb +0 -90
  135. data/lib/solarwinds_apm/instrumentation.rb +0 -22
  136. data/lib/solarwinds_apm/loading.rb +0 -65
  137. data/lib/solarwinds_apm/ruby.rb +0 -35
  138. data/lib/solarwinds_apm/sdk/current_trace_info.rb +0 -123
  139. data/lib/solarwinds_apm/sdk/custom_metrics.rb +0 -94
  140. data/lib/solarwinds_apm/sdk/logging.rb +0 -37
  141. data/lib/solarwinds_apm/sdk/trace_context_headers.rb +0 -69
  142. data/lib/solarwinds_apm/sdk/tracing.rb +0 -432
  143. data/lib/solarwinds_apm/support/profiling.rb +0 -25
  144. data/lib/solarwinds_apm/support/trace_context.rb +0 -53
  145. data/lib/solarwinds_apm/support/trace_state.rb +0 -69
  146. data/lib/solarwinds_apm/support/trace_string.rb +0 -89
  147. data/lib/solarwinds_apm/support/transaction_metrics.rb +0 -67
  148. data/lib/solarwinds_apm/test.rb +0 -165
  149. data/lib/solarwinds_apm/util.rb +0 -426
  150. data/log/.keep +0 -0
  151. data/log/postgresql/.keep +0 -0
  152. data/solarwinds_apm.gemspec +0 -55
  153. data/yardoc_frontpage.md +0 -24
@@ -1,435 +0,0 @@
1
- // Copyright (c) 2021 SolarWinds, LLC.
2
- // All rights reserved.
3
-
4
- #include "profiling.h"
5
-
6
- #include <ruby/debug.h>
7
- #include <signal.h>
8
- #include <time.h>
9
-
10
- #include <atomic>
11
- #include <unordered_map>
12
- #include <vector>
13
-
14
- #include "frames.h"
15
- #include "logging.h"
16
- #include "oboe_api.h"
17
-
18
-
19
- #define TIMER_SIG SIGRTMAX // the timer notification signal
20
-
21
- using namespace std;
22
-
23
- static atomic_bool running;
24
- atomic_bool profiling_shut_down; // !! can't be static because of tests
25
-
26
- // need to initialize here, hangs if it is done inside the signal handler
27
- // these are reused for every snapshot
28
- static VALUE frames_buffer[BUF_SIZE];
29
- static int lines_buffer[BUF_SIZE];
30
-
31
-
32
- static long configured_interval = 10; // in milliseconds, initializing in case Ruby forgets to
33
- static long current_interval = 10;
34
- timer_t timerid;
35
-
36
- typedef struct prof_data {
37
- bool running_p = false;
38
- Metadata md = Metadata(Context::get());
39
- string prof_op_id;
40
-
41
- VALUE prev_frames_buffer[BUF_SIZE];
42
- int prev_num = 0;
43
- long omitted[BUF_SIZE];
44
- int omitted_num = 0;
45
- } prof_data_t;
46
-
47
- unordered_map<pid_t, prof_data_t> prof_data_map;
48
-
49
- const string Profiling::string_job_handler = "Profiling::profiler_job_handler()";
50
- const string Profiling::string_gc_handler = "Profiling::profiler_gc_handler()";
51
- const string Profiling::string_signal_handler = "Profiling::profiler_signal_handler()";
52
- const string Profiling::string_stop = "Profiling::profiling_stop()";
53
-
54
- // for debugging only
55
- void print_prof_data_map() {
56
- pid_t tid = AO_GETTID;
57
- Metadata md_str(prof_data_map[tid].md);
58
- cout << tid << ", " << prof_data_map[tid].running_p << ", " << prof_data_map[tid].prof_op_id << ", ";
59
- cout << md_str.toString() << ", " << prof_data_map[tid].prev_num << ", " << prof_data_map[tid].omitted_num << endl;
60
- }
61
-
62
- long ts_now() {
63
- struct timeval tv;
64
- struct timezone *tz = NULL;
65
- gettimeofday(&tv, tz);
66
- return (long)tv.tv_sec * 1000000 + (long)tv.tv_usec;
67
- }
68
-
69
- // try catch block to be used inside functions that return an int
70
- // shuts down profiling and returns -1 on error
71
- int Profiling::try_catch_shutdown(std::function<int()> f, const string& fun_name) {
72
- try {
73
- return f();
74
- } catch (const std::exception &e) {
75
- string msg = "Exception in " + fun_name + ", can't recover, profiling shutting down";
76
- OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_RUBY, e.what());
77
- OBOE_DEBUG_LOG_HIGH(OBOE_MODULE_RUBY, msg.c_str());
78
- Profiling::shut_down();
79
- return -1;
80
- } catch (...) {
81
- string msg = "Exception in " + fun_name + ", can't recover, profiling shutting down";
82
- OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_RUBY, msg.c_str());
83
- Profiling::shut_down();
84
- return -1;
85
- }
86
- }
87
-
88
- void Profiling::profiler_record_frames() {
89
- pid_t tid = AO_GETTID;
90
- long ts = ts_now();
91
-
92
- // check if this thread is being profiled
93
- if (prof_data_map[tid].running_p) {
94
- // executes in the same thread as rb_postponed_job was called from
95
-
96
- // get the frames
97
- // won't overrun frames buffer, because size is set in arg 2
98
- int num = rb_profile_frames(0, sizeof(frames_buffer) / sizeof(VALUE), frames_buffer, lines_buffer);
99
-
100
- Profiling::process_snapshot(frames_buffer, num, tid, ts);
101
- }
102
-
103
- // add this timestamp as omitted to other running threads that are profiled
104
- for (pair<const pid_t, prof_data_t> &ele : prof_data_map) {
105
- if (ele.second.running_p && ele.first != tid) {
106
- frames_buffer[0] = PR_OTHER_THREAD;
107
- Profiling::process_snapshot(frames_buffer, 1, ele.first, ts);
108
- }
109
- }
110
- }
111
-
112
- void Profiling::profiler_record_gc() {
113
- pid_t tid = AO_GETTID;
114
- long ts = ts_now();
115
-
116
- // check if this thread is being profiled
117
- if (prof_data_map[tid].running_p) {
118
- frames_buffer[0] = PR_IN_GC;
119
- Profiling::process_snapshot(frames_buffer, 1, tid, ts);
120
- }
121
-
122
- // add this timestamp as omitted to other running threads that are profiled
123
- for (pair<const pid_t, prof_data_t> &ele : prof_data_map) {
124
- if (ele.second.running_p && ele.first != tid) {
125
- frames_buffer[0] = PR_OTHER_THREAD;
126
- Profiling::process_snapshot(frames_buffer, 1, ele.first, ts);
127
- }
128
- }
129
- }
130
-
131
- void Profiling::send_omitted(pid_t tid, long ts) {
132
- static vector<FrameData> empty;
133
- Logging::log_profile_snapshot(prof_data_map[tid].md,
134
- prof_data_map[tid].prof_op_id,
135
- ts, // timestamp
136
- empty, // <vector> new frames
137
- 0, // number of exited frames
138
- prof_data_map[tid].prev_num, // total number of frames
139
- prof_data_map[tid].omitted, // array of timestamps of omitted snapshots
140
- prof_data_map[tid].omitted_num, // number of omitted snapshots
141
- tid); // thread id
142
-
143
- prof_data_map[tid].omitted_num = 0;
144
- }
145
-
146
- void Profiling::process_snapshot(VALUE *frames_buffer, int num, pid_t tid, long ts) {
147
- int num_new = 0;
148
- int num_exited = 0;
149
- vector<FrameData> new_frames;
150
-
151
- num = Frames::remove_garbage(frames_buffer, num);
152
-
153
- // find the number of matching frames from the top
154
- int num_match = Frames::num_matching(frames_buffer,
155
- num,
156
- prof_data_map[tid].prev_frames_buffer,
157
- prof_data_map[tid].prev_num);
158
- num_new = num - num_match;
159
- num_exited = prof_data_map[tid].prev_num - num_match;
160
-
161
- if (num_new == 0 && num_exited == 0) {
162
- prof_data_map[tid].omitted[prof_data_map[tid].omitted_num] = ts;
163
- prof_data_map[tid].omitted_num++;
164
-
165
- // the omitted buffer can fill up if the interval is small
166
- // and the stack doesn't change
167
- // We need to send a profiling event with the timestamps when it is full
168
- if (prof_data_map[tid].omitted_num >= BUF_SIZE) {
169
- Profiling::send_omitted(tid, ts);
170
- }
171
- return;
172
- }
173
-
174
- Frames::collect_frame_data(frames_buffer, num_new, new_frames);
175
-
176
- Logging::log_profile_snapshot(prof_data_map[tid].md,
177
- prof_data_map[tid].prof_op_id,
178
- ts, // timestamp
179
- new_frames, // <vector> new frames
180
- num_exited, // number of exited frames
181
- num, // total number of frames
182
- prof_data_map[tid].omitted, // array of timestamps of omitted snapshots
183
- prof_data_map[tid].omitted_num, // number of omitted snapshots
184
- tid); // thread id
185
-
186
- prof_data_map[tid].omitted_num = 0;
187
- prof_data_map[tid].prev_num = num;
188
- for (int i = 0; i < num; ++i)
189
- prof_data_map[tid].prev_frames_buffer[i] = frames_buffer[i];
190
- }
191
-
192
- void Profiling::profiler_job_handler(void *data) {
193
- static atomic_bool in_job_handler{false};
194
-
195
- // atomically replaces the value of the object, returns the value held previously
196
- if (in_job_handler.exchange(true)) return;
197
-
198
- try_catch_shutdown([&]() {
199
- Profiling::profiler_record_frames();
200
- return 0; // block needs an int returned
201
- }, Profiling::string_job_handler);
202
-
203
- in_job_handler = false;
204
- }
205
-
206
- void Profiling::profiler_gc_handler(void *data) {
207
- static atomic_bool in_gc_handler{false};
208
-
209
- // atomically replaces the value of the object, returns the value held previously
210
- if (in_gc_handler.exchange(true)) return;
211
-
212
- try_catch_shutdown([]() {
213
- Profiling::profiler_record_gc();
214
- return 0; // block needs an int returned
215
- }, Profiling::string_gc_handler);
216
-
217
- in_gc_handler = false;
218
- }
219
-
220
- ////////////////////////////////////////////////////////////////////////////////
221
- // THIS IS THE SIGNAL HANDLER FUNCTION
222
- // ONLY ASYNC-SAFE FUNCTIONS ALLOWED IN HERE (no exception handling !!!)
223
- ////////////////////////////////////////////////////////////////////////////////
224
- extern "C" void profiler_signal_handler(int sigint, siginfo_t *siginfo, void *ucontext) {
225
- if (!ruby_native_thread_p()) return;
226
- static std::atomic_bool in_signal_handler{false};
227
-
228
- // atomically replaces the value of the object, returns the value held previously
229
- // also keeps in_signal_handler lock_free -> async-safe
230
- if (in_signal_handler.exchange(true)) return;
231
-
232
- // the following two ruby c-functions are async safe
233
- if (rb_during_gc())
234
- {
235
- rb_postponed_job_register(0, Profiling::profiler_gc_handler, (void *)0);
236
- } else {
237
- rb_postponed_job_register(0, Profiling::profiler_job_handler, (void *)0);
238
- }
239
-
240
- in_signal_handler = false;
241
- }
242
-
243
- void Profiling::profiling_start(pid_t tid) {
244
- prof_data_map[tid].md = Metadata(Context::get());
245
- prof_data_map[tid].prev_num = 0;
246
- prof_data_map[tid].omitted_num = 0;
247
- prof_data_map[tid].running_p = true;
248
-
249
- Logging::log_profile_entry(prof_data_map[tid].md,
250
- prof_data_map[tid].prof_op_id,
251
- tid,
252
- current_interval);
253
-
254
- if (!running.exchange(true)) {
255
- // start timer with interval timer spec
256
- struct itimerspec ts;
257
- ts.it_interval.tv_sec = 0;
258
- ts.it_interval.tv_nsec = current_interval * 1000000;
259
- ts.it_value.tv_sec = 0;
260
- ts.it_value.tv_nsec = ts.it_interval.tv_nsec;
261
-
262
- // global timer_t timerid points to timer created in Init_profiling
263
- if (timer_settime(timerid, 0, &ts, NULL) == -1) {
264
- OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_RUBY, "timer_settime() failed");
265
- shut_down();
266
- }
267
- }
268
- }
269
-
270
- VALUE Profiling::profiling_stop(pid_t tid) {
271
- if (!running.exchange(false)) return Qfalse;
272
-
273
- int result = try_catch_shutdown([&]() {
274
- // stop the timer, needs both (value and interval) set to 0
275
- struct itimerspec ts;
276
- ts.it_value.tv_sec = 0;
277
- ts.it_value.tv_nsec = 0;
278
- ts.it_interval.tv_sec = 0;
279
- ts.it_interval.tv_nsec = 0;
280
-
281
- if (timer_settime(timerid, 0, &ts, NULL) == -1) {
282
- OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_RUBY, "timer_settime() failed");
283
- shut_down();
284
- }
285
-
286
- Logging::log_profile_exit(prof_data_map[tid].md,
287
- prof_data_map[tid].prof_op_id,
288
- tid,
289
- prof_data_map[tid].omitted,
290
- prof_data_map[tid].omitted_num);
291
-
292
- prof_data_map[tid].running_p = false;
293
- return 0; // block needs an int returned
294
- }, Profiling::string_stop);
295
-
296
- return (result == 0) ? Qtrue : Qfalse;
297
- }
298
-
299
- VALUE Profiling::set_interval(VALUE self, VALUE val) {
300
- if (!FIXNUM_P(val)) return Qfalse;
301
-
302
- configured_interval = FIX2INT(val);
303
-
304
- return INT2FIX(configured_interval);
305
- }
306
-
307
- VALUE Profiling::get_interval() {
308
- return INT2FIX(current_interval);
309
- }
310
-
311
- VALUE Profiling::profiling_run(VALUE self, VALUE rb_thread_val, VALUE interval) {
312
- rb_need_block(); // checks if function is called with a block in Ruby
313
- if (profiling_shut_down || OboeProfiling::get_interval() == 0) {
314
- return rb_yield(Qundef);
315
- }
316
-
317
- if (FIXNUM_P(interval)) configured_interval = FIX2INT(interval);
318
- current_interval = max(configured_interval, (long)OboeProfiling::get_interval());
319
-
320
- // !!!!! Can't use try_catch_shutdown() here, MAKES rb_ensure cause a memory leak !!!!!
321
- try {
322
- pid_t tid = AO_GETTID;
323
- profiling_start(tid);
324
- rb_ensure(reinterpret_cast<VALUE (*)(...)>(rb_yield), Qundef,
325
- reinterpret_cast<VALUE (*)(...)>(profiling_stop), tid);
326
- return Qtrue;
327
- } catch (const std::exception &e) {
328
- string msg = "Exception in Profiling::profiling_run(), can't recover, profiling shutting down";
329
- OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_RUBY, e.what());
330
- OBOE_DEBUG_LOG_HIGH(OBOE_MODULE_RUBY, msg.c_str());
331
- shut_down();
332
- return Qfalse;
333
- } catch (...) {
334
- string msg = "Exception in Profiling::profiling_run(), can't recover, profiling shutting down";
335
- OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_RUBY, msg.c_str());
336
- shut_down();
337
- return Qfalse;
338
- }
339
-
340
- return Qfalse;
341
- }
342
-
343
- // in case C++ misbehaves we will stop profiling
344
- // to be used when catching exceptions
345
- void Profiling::shut_down() {
346
- static atomic_bool ending{false};
347
-
348
- if (ending.exchange(true)) return;
349
-
350
- // avoid running any more profiling
351
- profiling_shut_down = true;
352
-
353
- // stop all profiling, the last one also stops the timer/signals
354
- for (pair<const pid_t, prof_data_t> &ele : prof_data_map) {
355
- profiling_stop(ele.first);
356
- }
357
- }
358
-
359
- VALUE Profiling::getTid() {
360
- pid_t tid = AO_GETTID;
361
-
362
- return INT2NUM(tid);
363
- }
364
-
365
- static void
366
- prof_atfork_prepare(void) {
367
- // cout << "Parent getting ready" << endl;
368
- }
369
-
370
- static void
371
- prof_atfork_parent(void) {
372
- // cout << "Parent let child loose" << endl;
373
- }
374
-
375
- // make sure new processes have a clean slate for profiling
376
- static void
377
- prof_atfork_child(void) {
378
- // cout << "A child is born" << endl;
379
- Frames::clear_cached_frames();
380
- prof_data_map.clear();
381
- running = false;
382
-
383
- // make sure it has a timer ready, it is a per-process-timer
384
- Profiling::create_timer();
385
- }
386
-
387
- void Profiling::create_sigaction() {
388
- struct sigaction sa;
389
- // what happens if there is another action for the same signal?
390
- // => last one defined wins!
391
- sa.sa_sigaction = profiler_signal_handler;
392
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
393
- sigemptyset(&sa.sa_mask);
394
- if (sigaction(TIMER_SIG, &sa, NULL) == -1) {
395
- OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_RUBY, "sigaction() failed");
396
- profiling_shut_down = true; // no profiling without sigaction
397
- }
398
- }
399
-
400
- void Profiling::create_timer() {
401
- struct sigevent sev;
402
-
403
- sev.sigev_value.sival_ptr = &timerid;
404
- sev.sigev_notify = SIGEV_SIGNAL; /* Notify via signal */
405
- sev.sigev_signo = TIMER_SIG; /* Notify using this signal */
406
-
407
- if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {
408
- OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_RUBY, "timer_create() failed");
409
- profiling_shut_down = true; // no profiling without clock
410
- }
411
- }
412
-
413
- extern "C" void Init_profiling(void) {
414
- // assign values to global atomic vars that know about state of profiling
415
- running = false;
416
- profiling_shut_down = false;
417
-
418
- // prep data structures
419
- Profiling::create_sigaction();
420
- Profiling::create_timer();
421
- Frames::reserve_cached_frames();
422
-
423
- // create Ruby Module: SolarWindsAPM::CProfiler
424
- static VALUE rb_mSolarWindsAPM = rb_define_module("SolarWindsAPM");
425
- static VALUE rb_mCProfiler = rb_define_module_under(rb_mSolarWindsAPM, "CProfiler");
426
-
427
- rb_define_singleton_method(rb_mCProfiler, "get_interval", reinterpret_cast<VALUE (*)(...)>(Profiling::get_interval), 0);
428
- rb_define_singleton_method(rb_mCProfiler, "set_interval", reinterpret_cast<VALUE (*)(...)>(Profiling::set_interval), 1);
429
- rb_define_singleton_method(rb_mCProfiler, "run", reinterpret_cast<VALUE (*)(...)>(Profiling::profiling_run), 2);
430
- rb_define_singleton_method(rb_mCProfiler, "get_tid", reinterpret_cast<VALUE (*)(...)>(Profiling::getTid), 0);
431
-
432
- pthread_atfork(prof_atfork_prepare,
433
- prof_atfork_parent,
434
- prof_atfork_child);
435
- }
@@ -1,78 +0,0 @@
1
- // Copyright (c) 2021 SolarWinds, LLC.
2
- // All rights reserved.
3
-
4
- #ifndef PROFILING_H
5
- #define PROFILING_H
6
-
7
- #include <ruby/ruby.h>
8
- #include <ruby/debug.h>
9
- #include <signal.h>
10
- #include <time.h>
11
-
12
- #include <atomic>
13
- #include <functional>
14
- #include <unordered_map>
15
- #include <vector>
16
-
17
- #include "frames.h"
18
- #include "logging.h"
19
- #include "oboe_api.h"
20
-
21
- #define BUF_SIZE 2048
22
-
23
- // these definitions are based on the assumption that there are no
24
- // frames with VALUE == 1 or VALUE == 2 in Ruby
25
- // profiling won't blow up if there are, because there is also a check to see
26
- // if the stack has size == 1 when assuming what these frames refer to
27
- #define PR_OTHER_THREAD 1
28
- #define PR_IN_GC 2
29
-
30
- #if !defined(AO_GETTID)
31
- #if defined(_WIN32)
32
- #define AO_GETTID GetCurrentThreadId
33
- #else
34
- #include <unistd.h>
35
- #include <sys/syscall.h>
36
- #ifdef SYS_gettid
37
- #define AO_GETTID syscall(SYS_gettid);
38
- #endif
39
- #endif
40
- #endif
41
-
42
- class Profiling {
43
- public:
44
- static const string string_job_handler, string_gc_handler, string_signal_handler, string_stop;
45
-
46
- static void create_sigaction();
47
- static void create_timer();
48
-
49
- static int try_catch_shutdown(std::function<int()>, const string& fun_name);
50
- static void profiler_job_handler(void* data);
51
- static void profiler_gc_handler(void* data);
52
- // This is used when catching an exception
53
- static void shut_down();
54
-
55
- // The following are made available to Ruby and have to return VALUE
56
- static VALUE profiling_run(VALUE self, VALUE rb_thread_val, VALUE interval);
57
- static VALUE get_interval();
58
- static VALUE set_interval(VALUE self, VALUE interval);
59
- static VALUE getTid();
60
-
61
- private:
62
- static void profiling_start(pid_t tid);
63
-
64
- // This is used via rb_ensure and therefore needs VALUE as a return type
65
- static VALUE profiling_stop(pid_t tid);
66
-
67
- static void process_snapshot(VALUE* frames_buffer,
68
- int num,
69
- pid_t tid,
70
- long ts);
71
- static void profiler_record_frames();
72
- static void profiler_record_gc();
73
- static void send_omitted(pid_t tid, long ts);
74
- };
75
-
76
- extern "C" void Init_profiling(void);
77
-
78
- #endif // PROFILING_H
@@ -1,53 +0,0 @@
1
- cmake_minimum_required(VERSION 3.13)
2
- project(test)
3
-
4
- # specify the C++ standard
5
- set(CMAKE_CXX_STANDARD 11)
6
- set(CMAKE_CXX_STANDARD_REQUIRED True)
7
- # set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/FindGMock.cmake)
8
-
9
- include(FetchContent)
10
- FetchContent_Declare(
11
- googletest
12
- URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
13
- # URL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip
14
- )
15
-
16
- # For Windows: Prevent overriding the parent project's compiler/linker settings
17
- set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
18
- FetchContent_MakeAvailable(googletest)
19
-
20
- include_directories(
21
- ${gtest_SOURCE_DIR}/include
22
- ../src/
23
- $ENV{RUBY_INC_DIR}
24
- $ENV{RUBY_INC_DIR}/x86_64-linux/
25
- )
26
-
27
- link_directories(
28
- # /usr/lib/
29
- $ENV{RUBY_PREFIX}/lib/
30
- ../../../lib/
31
- ../lib
32
- )
33
-
34
- enable_testing()
35
- set (sources
36
- test_main.cc
37
- frames_test.cc
38
- profiling_test.cc
39
- )
40
-
41
- ## Link runTests with what we want to test and the GTest and pthread library
42
- add_executable(runTests ${sources})
43
- target_link_libraries(runTests
44
- # ${GTEST_LIBRARIES}
45
- gtest
46
- solarwinds_apm.so
47
- liboboe.so
48
- libruby.so
49
- pthread
50
- )
51
-
52
- include(GoogleTest)
53
- gtest_discover_tests(runTests)
@@ -1,43 +0,0 @@
1
- # This content copied from
2
- # https://git.simply-life.net/simply-life.net/talltower/-/blob/639293a366da43eb94a72d2e7596242314c9809c/cmake/FindGMock.cmake
3
-
4
-
5
- # Try to find GMock
6
- find_package(GTest)
7
-
8
- # the following issues a warning, but it works nonetheless
9
- find_package(PkgConfig)
10
- pkg_check_modules(PC_GMOCK QUIET gmock)
11
- set(GMOCK_DEFINITIONS ${PC_GMOCK_CFLAGS_OTHER})
12
-
13
- find_path(GMOCK_INCLUDE_DIR gmock.h
14
- HINTS ${PC_GMOCK_INCLUDEDIR} ${PC_GMOCK_INCLUDE_DIRS}
15
- PATH_SUFFIXES gmock)
16
-
17
- find_library(GMOCK_LIBRARY NAMES gmock libgmock
18
- HINTS ${PC_GMOCK_LIBDIR} ${PC_GMOCK_LIBRARY_DIRS} )
19
-
20
- find_library(GMOCK_MAIN_LIBRARY NAMES gmock_main libgmock_main
21
- HINTS ${PC_GMOCK_LIBDIR} ${PC_GMOCK_LIBRARY_DIRS} )
22
-
23
- include(FindPackageHandleStandardArgs)
24
- # handle the QUIETLY and REQUIRED arguments and set GMOCK_FOUND to TRUE
25
- # if all listed variables are TRUE
26
- find_package_handle_standard_args(GMock DEFAULT_MSG
27
- GMOCK_LIBRARY GMOCK_INCLUDE_DIR GTEST_FOUND)
28
-
29
- mark_as_advanced(GMOCK_INCLUDE_DIR GMOCK_LIBRARY GMOCK_MAIN_LIBRARY)
30
-
31
- set(GMOCK_LIBRARIES ${GMOCK_LIBRARY} )
32
- set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR} )
33
- set(GMOCK_MAIN_LIBRARIES ${GMOCK_MAIN_LIBRARY} )
34
-
35
- if (NOT TARGET GMock)
36
- add_library(GMock IMPORTED SHARED)
37
- set_property(TARGET GMock PROPERTY IMPORTED_LOCATION ${GMOCK_LIBRARY})
38
- set_property(TARGET GMock PROPERTY INTERFACE_INCLUDE_DIRECTORY ${GMOCK_INCLUDE_DIR})
39
-
40
- add_library(GMockMain IMPORTED SHARED)
41
- set_property(TARGET GMockMain PROPERTY IMPORTED_LOCATION ${GMOCK_MAIN_LIBRARY})
42
- set_property(TARGET GMockMain PROPERTY INTERFACE_LINK_LIBRARIES GMock GTest)
43
- endif()
@@ -1,56 +0,0 @@
1
- C-code tests:
2
-
3
- CMakeLists.txt includes downloading and compiling googletest if necessary
4
-
5
- In the ext/oboe_metal/test directory:
6
-
7
- Set an environment variable for the current path:
8
- ```
9
- export TEST_DIR=`pwd`
10
- ```
11
-
12
- Every time the ruby version changes the solarwinds_apm gem needs to be
13
- re-installed or its c++-code recompiled and relinked
14
-
15
- These environment variables need to be set every time the ruby version is set:
16
- ```
17
- export RUBY_INC_DIR=$(ruby ruby_inc_dir.rb)
18
- export RUBY_PREFIX=$(ruby ruby_prefix.rb)
19
- ```
20
-
21
- create the Makefile (needs to be remade when the ruby version changes)
22
- ```
23
- cmake -S . -B build
24
- ```
25
- build
26
- ```
27
- cmake --build build
28
- ```
29
- run
30
- ```
31
- cd build && ctest && cd -
32
- ```
33
-
34
- Most testing of profiling is done via Ruby integration tests
35
-
36
- For example logging is tested in Ruby tests that verify the different
37
- KVs and values in the resulting traces, using the same approach as
38
- for traces without profiling.
39
-
40
- Gotchas:
41
-
42
- - In alpine the `ruby/config.h` file is in an architecture specific folder and needs
43
- to be symlinked to the location set via RUBY_INC_DIR (see: Dockerfile_alpine)
44
-
45
- TODO:
46
-
47
- - write a script for this
48
-
49
- ```
50
- export TEST_DIR=`pwd`
51
- export RUBY_INC_DIR=$(ruby ruby_inc_dir.rb)
52
- export RUBY_PREFIX=$(ruby ruby_prefix.rb)
53
- cmake -S . -B build
54
- cmake --build build
55
- cd build && ctest && cd -
56
- ```