solarwinds_apm 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
  4. data/.github/workflows/build_and_release_gem.yml +112 -0
  5. data/.github/workflows/build_for_packagecloud.yml +70 -0
  6. data/.github/workflows/docker-images.yml +47 -0
  7. data/.github/workflows/run_cpluplus_tests.yml +73 -0
  8. data/.github/workflows/run_tests.yml +155 -0
  9. data/.github/workflows/scripts/test_install.rb +23 -0
  10. data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
  11. data/.github/workflows/test_on_4_linux.yml +161 -0
  12. data/.gitignore +39 -0
  13. data/.rubocop.yml +29 -0
  14. data/.yardopts +7 -0
  15. data/CHANGELOG.md +769 -0
  16. data/CONFIG.md +31 -0
  17. data/Gemfile +14 -0
  18. data/LICENSE +202 -0
  19. data/README.md +383 -0
  20. data/bin/solarwinds_apm_config +15 -0
  21. data/examples/prepend.rb +13 -0
  22. data/examples/sdk_examples.rb +158 -0
  23. data/ext/oboe_metal/README.md +69 -0
  24. data/ext/oboe_metal/extconf.rb +141 -0
  25. data/ext/oboe_metal/extconf_local.rb +75 -0
  26. data/ext/oboe_metal/lib/.keep +0 -0
  27. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
  28. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
  29. data/ext/oboe_metal/noop/noop.c +8 -0
  30. data/ext/oboe_metal/src/README.md +6 -0
  31. data/ext/oboe_metal/src/VERSION +2 -0
  32. data/ext/oboe_metal/src/bson/bson.h +220 -0
  33. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  34. data/ext/oboe_metal/src/frames.cc +247 -0
  35. data/ext/oboe_metal/src/frames.h +40 -0
  36. data/ext/oboe_metal/src/init_solarwinds_apm.cc +21 -0
  37. data/ext/oboe_metal/src/logging.cc +95 -0
  38. data/ext/oboe_metal/src/logging.h +35 -0
  39. data/ext/oboe_metal/src/oboe.h +1169 -0
  40. data/ext/oboe_metal/src/oboe_api.cpp +658 -0
  41. data/ext/oboe_metal/src/oboe_api.hpp +433 -0
  42. data/ext/oboe_metal/src/oboe_debug.h +59 -0
  43. data/ext/oboe_metal/src/oboe_swig_wrap.cc +7562 -0
  44. data/ext/oboe_metal/src/profiling.cc +435 -0
  45. data/ext/oboe_metal/src/profiling.h +78 -0
  46. data/ext/oboe_metal/test/CMakeLists.txt +53 -0
  47. data/ext/oboe_metal/test/FindGMock.cmake +43 -0
  48. data/ext/oboe_metal/test/README.md +56 -0
  49. data/ext/oboe_metal/test/frames_test.cc +164 -0
  50. data/ext/oboe_metal/test/profiling_test.cc +93 -0
  51. data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
  52. data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
  53. data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
  54. data/ext/oboe_metal/test/test.h +11 -0
  55. data/ext/oboe_metal/test/test_main.cc +32 -0
  56. data/init.rb +4 -0
  57. data/lib/oboe.rb +7 -0
  58. data/lib/oboe_metal.rb +172 -0
  59. data/lib/rails/generators/solarwinds_apm/install_generator.rb +47 -0
  60. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +424 -0
  61. data/lib/solarwinds_apm/api/layerinit.rb +41 -0
  62. data/lib/solarwinds_apm/api/logging.rb +356 -0
  63. data/lib/solarwinds_apm/api/memcache.rb +37 -0
  64. data/lib/solarwinds_apm/api/metrics.rb +63 -0
  65. data/lib/solarwinds_apm/api/util.rb +98 -0
  66. data/lib/solarwinds_apm/api.rb +21 -0
  67. data/lib/solarwinds_apm/base.rb +160 -0
  68. data/lib/solarwinds_apm/config.rb +301 -0
  69. data/lib/solarwinds_apm/frameworks/grape.rb +96 -0
  70. data/lib/solarwinds_apm/frameworks/padrino.rb +78 -0
  71. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +100 -0
  72. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  73. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  74. data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +88 -0
  75. data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +26 -0
  76. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  77. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +22 -0
  78. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +103 -0
  79. data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +14 -0
  80. data/lib/solarwinds_apm/frameworks/rails.rb +100 -0
  81. data/lib/solarwinds_apm/frameworks/sinatra.rb +96 -0
  82. data/lib/solarwinds_apm/inst/bunny-client.rb +157 -0
  83. data/lib/solarwinds_apm/inst/bunny-consumer.rb +102 -0
  84. data/lib/solarwinds_apm/inst/curb.rb +288 -0
  85. data/lib/solarwinds_apm/inst/dalli.rb +89 -0
  86. data/lib/solarwinds_apm/inst/delayed_job.rb +100 -0
  87. data/lib/solarwinds_apm/inst/excon.rb +113 -0
  88. data/lib/solarwinds_apm/inst/faraday.rb +96 -0
  89. data/lib/solarwinds_apm/inst/graphql.rb +206 -0
  90. data/lib/solarwinds_apm/inst/grpc_client.rb +147 -0
  91. data/lib/solarwinds_apm/inst/grpc_server.rb +119 -0
  92. data/lib/solarwinds_apm/inst/httpclient.rb +181 -0
  93. data/lib/solarwinds_apm/inst/logger_formatter.rb +46 -0
  94. data/lib/solarwinds_apm/inst/logging_log_event.rb +24 -0
  95. data/lib/solarwinds_apm/inst/lumberjack_formatter.rb +9 -0
  96. data/lib/solarwinds_apm/inst/memcached.rb +86 -0
  97. data/lib/solarwinds_apm/inst/mongo.rb +246 -0
  98. data/lib/solarwinds_apm/inst/mongo2.rb +225 -0
  99. data/lib/solarwinds_apm/inst/moped.rb +466 -0
  100. data/lib/solarwinds_apm/inst/net_http.rb +60 -0
  101. data/lib/solarwinds_apm/inst/rack.rb +217 -0
  102. data/lib/solarwinds_apm/inst/rack_cache.rb +35 -0
  103. data/lib/solarwinds_apm/inst/redis.rb +273 -0
  104. data/lib/solarwinds_apm/inst/resque.rb +129 -0
  105. data/lib/solarwinds_apm/inst/rest-client.rb +43 -0
  106. data/lib/solarwinds_apm/inst/sequel.rb +241 -0
  107. data/lib/solarwinds_apm/inst/sidekiq-client.rb +63 -0
  108. data/lib/solarwinds_apm/inst/sidekiq-worker.rb +64 -0
  109. data/lib/solarwinds_apm/inst/typhoeus.rb +90 -0
  110. data/lib/solarwinds_apm/instrumentation.rb +22 -0
  111. data/lib/solarwinds_apm/loading.rb +65 -0
  112. data/lib/solarwinds_apm/logger.rb +14 -0
  113. data/lib/solarwinds_apm/noop/README.md +9 -0
  114. data/lib/solarwinds_apm/noop/context.rb +26 -0
  115. data/lib/solarwinds_apm/noop/metadata.rb +25 -0
  116. data/lib/solarwinds_apm/noop/profiling.rb +21 -0
  117. data/lib/solarwinds_apm/oboe_init_options.rb +191 -0
  118. data/lib/solarwinds_apm/ruby.rb +35 -0
  119. data/lib/solarwinds_apm/sdk/current_trace_info.rb +123 -0
  120. data/lib/solarwinds_apm/sdk/custom_metrics.rb +94 -0
  121. data/lib/solarwinds_apm/sdk/logging.rb +37 -0
  122. data/lib/solarwinds_apm/sdk/trace_context_headers.rb +69 -0
  123. data/lib/solarwinds_apm/sdk/tracing.rb +432 -0
  124. data/lib/solarwinds_apm/support/profiling.rb +22 -0
  125. data/lib/solarwinds_apm/support/trace_context.rb +53 -0
  126. data/lib/solarwinds_apm/support/trace_state.rb +69 -0
  127. data/lib/solarwinds_apm/support/trace_string.rb +89 -0
  128. data/lib/solarwinds_apm/support/transaction_metrics.rb +67 -0
  129. data/lib/solarwinds_apm/support/transaction_settings.rb +233 -0
  130. data/lib/solarwinds_apm/support/x_trace_options.rb +113 -0
  131. data/lib/solarwinds_apm/support.rb +12 -0
  132. data/lib/solarwinds_apm/support_report.rb +113 -0
  133. data/lib/solarwinds_apm/test.rb +165 -0
  134. data/lib/solarwinds_apm/thread_local.rb +26 -0
  135. data/lib/solarwinds_apm/util.rb +334 -0
  136. data/lib/solarwinds_apm/version.rb +17 -0
  137. data/lib/solarwinds_apm.rb +72 -0
  138. data/log/.keep +0 -0
  139. data/log/postgresql/.keep +0 -0
  140. data/solarwinds_apm.gemspec +52 -0
  141. data/yardoc_frontpage.md +24 -0
  142. metadata +228 -0
@@ -0,0 +1,220 @@
1
+ /* bson.h */
2
+
3
+ /* Copyright 2009, 2010 10gen Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #ifndef _BSON_H_
19
+ #define _BSON_H_
20
+
21
+ #define MONGO_HAVE_STDINT
22
+ #include "platform_hacks.h"
23
+ #include <time.h>
24
+
25
+ MONGO_EXTERN_C_START
26
+
27
+ typedef enum {
28
+ oboe_bson_error=-1,
29
+ oboe_bson_eoo=0,
30
+ oboe_bson_double=1,
31
+ oboe_bson_string=2,
32
+ oboe_bson_object=3,
33
+ oboe_bson_array=4,
34
+ oboe_bson_bindata=5,
35
+ oboe_bson_undefined=6,
36
+ oboe_bson_oid=7,
37
+ oboe_bson_bool=8,
38
+ oboe_bson_date=9,
39
+ oboe_bson_null=10,
40
+ oboe_bson_regex=11,
41
+ oboe_bson_dbref=12, /* deprecated */
42
+ oboe_bson_code=13,
43
+ oboe_bson_symbol=14,
44
+ oboe_bson_codewscope=15,
45
+ oboe_bson_int = 16,
46
+ oboe_bson_timestamp = 17,
47
+ oboe_bson_long = 18
48
+ } oboe_bson_type;
49
+
50
+ typedef int oboe_bson_bool_t;
51
+
52
+ typedef struct {
53
+ char * data;
54
+ oboe_bson_bool_t owned;
55
+ } oboe_bson;
56
+
57
+ typedef struct {
58
+ const char * cur;
59
+ oboe_bson_bool_t first;
60
+ } oboe_bson_iterator;
61
+
62
+ typedef struct {
63
+ char * buf;
64
+ char * cur;
65
+ int bufSize;
66
+ oboe_bson_bool_t finished;
67
+ int stack[32];
68
+ int stackPos;
69
+ } oboe_bson_buffer;
70
+
71
+ #pragma pack(1)
72
+ typedef union{
73
+ char bytes[12]; // Flawfinder: ignore
74
+ int ints[3];
75
+ } oboe_bson_oid_t;
76
+ #pragma pack()
77
+
78
+ typedef int64_t oboe_bson_date_t; /* milliseconds since epoch UTC */
79
+
80
+ /* ----------------------------
81
+ READING
82
+ ------------------------------ */
83
+
84
+
85
+ oboe_bson * oboe_bson_empty(oboe_bson * obj); /* returns pointer to static empty bson object */
86
+ int oboe_bson_copy(oboe_bson* out, const oboe_bson* in); /* puts data in new buffer. NOOP if out==NULL */
87
+ oboe_bson * oboe_bson_from_buffer(oboe_bson * b, oboe_bson_buffer * buf);
88
+ oboe_bson * oboe_bson_init( oboe_bson * b , char * data , oboe_bson_bool_t mine );
89
+ oboe_bson * oboe_bson_init_safe( oboe_bson * b , char * data , oboe_bson_bool_t mine , size_t buflen);
90
+ int oboe_bson_size(const oboe_bson * b );
91
+ void oboe_bson_destroy( oboe_bson * b );
92
+
93
+ void oboe_bson_print( oboe_bson * b );
94
+ void oboe_bson_print_raw( const char * bson , int depth );
95
+
96
+ /* advances iterator to named field */
97
+ /* returns bson_eoo (which is false) if field not found */
98
+ oboe_bson_type oboe_bson_find(oboe_bson_iterator* it, const oboe_bson* obj, const char* name);
99
+
100
+ void oboe_bson_iterator_init( oboe_bson_iterator * i , const char * bson );
101
+
102
+ /* more returns true for eoo. best to loop with bson_iterator_next(&it) */
103
+ oboe_bson_bool_t oboe_bson_iterator_more( const oboe_bson_iterator * i );
104
+ oboe_bson_type oboe_bson_iterator_next( oboe_bson_iterator * i );
105
+
106
+ oboe_bson_type oboe_bson_iterator_type( const oboe_bson_iterator * i );
107
+ const char * oboe_bson_iterator_key( const oboe_bson_iterator * i );
108
+ const char * oboe_bson_iterator_value( const oboe_bson_iterator * i );
109
+
110
+ /* these convert to the right type (return 0 if non-numeric) */
111
+ double oboe_bson_iterator_double( const oboe_bson_iterator * i );
112
+ int oboe_bson_iterator_int( const oboe_bson_iterator * i );
113
+ int64_t oboe_bson_iterator_long( const oboe_bson_iterator * i );
114
+
115
+ /* false: boolean false, 0 in any type, or null */
116
+ /* true: anything else (even empty strings and objects) */
117
+ oboe_bson_bool_t oboe_bson_iterator_bool( const oboe_bson_iterator * i );
118
+
119
+ /* these assume you are using the right type */
120
+ double oboe_bson_iterator_double_raw( const oboe_bson_iterator * i );
121
+ int oboe_bson_iterator_int_raw( const oboe_bson_iterator * i );
122
+ int64_t oboe_bson_iterator_long_raw( const oboe_bson_iterator * i );
123
+ oboe_bson_bool_t oboe_bson_iterator_bool_raw( const oboe_bson_iterator * i );
124
+ oboe_bson_oid_t* oboe_bson_iterator_oid( const oboe_bson_iterator * i );
125
+
126
+ /* these can also be used with bson_code and bson_symbol*/
127
+ const char * oboe_bson_iterator_string( const oboe_bson_iterator * i );
128
+ int oboe_bson_iterator_string_len( const oboe_bson_iterator * i );
129
+
130
+ /* works with bson_code, bson_codewscope, and bson_string */
131
+ /* returns NULL for everything else */
132
+ const char * oboe_bson_iterator_code(const oboe_bson_iterator * i);
133
+
134
+ /* calls bson_empty on scope if not a bson_codewscope */
135
+ void oboe_bson_iterator_code_scope(const oboe_bson_iterator * i, oboe_bson * scope);
136
+
137
+ /* both of these only work with bson_date */
138
+ oboe_bson_date_t oboe_bson_iterator_date(const oboe_bson_iterator * i);
139
+ time_t oboe_bson_iterator_time_t(const oboe_bson_iterator * i);
140
+
141
+ int oboe_bson_iterator_bin_len( const oboe_bson_iterator * i );
142
+ char oboe_bson_iterator_bin_type( const oboe_bson_iterator * i );
143
+ const char * oboe_bson_iterator_bin_data( const oboe_bson_iterator * i );
144
+
145
+ const char * oboe_bson_iterator_regex( const oboe_bson_iterator * i );
146
+ const char * oboe_bson_iterator_regex_opts( const oboe_bson_iterator * i );
147
+
148
+ /* these work with bson_object and bson_array */
149
+ void oboe_bson_iterator_subobject(const oboe_bson_iterator * i, oboe_bson * sub);
150
+ void oboe_bson_iterator_subiterator(const oboe_bson_iterator * i, oboe_bson_iterator * sub);
151
+
152
+ /* str must be at least 24 hex chars + null byte */
153
+ void oboe_bson_oid_from_string(oboe_bson_oid_t* oid, const char* str);
154
+ void oboe_bson_oid_to_string(const oboe_bson_oid_t* oid, char* str);
155
+ void oboe_bson_oid_gen(oboe_bson_oid_t* oid);
156
+
157
+ time_t oboe_bson_oid_generated_time(oboe_bson_oid_t* oid); /* Gives the time the OID was created */
158
+
159
+ /* ----------------------------
160
+ BUILDING
161
+ ------------------------------ */
162
+
163
+ oboe_bson_buffer * oboe_bson_buffer_init( oboe_bson_buffer * b );
164
+ oboe_bson_buffer * oboe_bson_ensure_space( oboe_bson_buffer * b , const int bytesNeeded );
165
+
166
+ /**
167
+ * @return the raw data. you either should free this OR call bson_destroy not both
168
+ */
169
+ char * oboe_bson_buffer_finish( oboe_bson_buffer * b );
170
+ void oboe_bson_buffer_destroy( oboe_bson_buffer * b );
171
+
172
+ oboe_bson_buffer * oboe_bson_append_oid( oboe_bson_buffer * b , const char * name , const oboe_bson_oid_t* oid );
173
+ oboe_bson_buffer * oboe_bson_append_int( oboe_bson_buffer * b , const char * name , const int i );
174
+ oboe_bson_buffer * oboe_bson_append_long( oboe_bson_buffer * b , const char * name , const int64_t i );
175
+ oboe_bson_buffer * oboe_bson_append_double( oboe_bson_buffer * b , const char * name , const double d );
176
+ oboe_bson_buffer * oboe_bson_append_string( oboe_bson_buffer * b , const char * name , const char * str );
177
+ oboe_bson_buffer * oboe_bson_append_symbol( oboe_bson_buffer * b , const char * name , const char * str );
178
+ oboe_bson_buffer * oboe_bson_append_code( oboe_bson_buffer * b , const char * name , const char * str );
179
+ oboe_bson_buffer * oboe_bson_append_code_w_scope( oboe_bson_buffer * b , const char * name , const char * code , const oboe_bson * scope);
180
+ oboe_bson_buffer * oboe_bson_append_binary( oboe_bson_buffer * b, const char * name, char type, const char * str, int len );
181
+ oboe_bson_buffer * oboe_bson_append_bool( oboe_bson_buffer * b , const char * name , const oboe_bson_bool_t v );
182
+ oboe_bson_buffer * oboe_bson_append_null( oboe_bson_buffer * b , const char * name );
183
+ oboe_bson_buffer * oboe_bson_append_undefined( oboe_bson_buffer * b , const char * name );
184
+ oboe_bson_buffer * oboe_bson_append_regex( oboe_bson_buffer * b , const char * name , const char * pattern, const char * opts );
185
+ oboe_bson_buffer * oboe_bson_append_bson( oboe_bson_buffer * b , const char * name , const oboe_bson* bson);
186
+ oboe_bson_buffer * oboe_bson_append_element( oboe_bson_buffer * b, const char * name_or_null, const oboe_bson_iterator* elem);
187
+
188
+ /* these both append a bson_date */
189
+ oboe_bson_buffer * oboe_bson_append_date(oboe_bson_buffer * b, const char * name, oboe_bson_date_t millis);
190
+ oboe_bson_buffer * oboe_bson_append_time_t(oboe_bson_buffer * b, const char * name, time_t secs);
191
+
192
+ oboe_bson_buffer * oboe_bson_append_start_object( oboe_bson_buffer * b , const char * name );
193
+ oboe_bson_buffer * oboe_bson_append_start_array( oboe_bson_buffer * b , const char * name );
194
+ oboe_bson_buffer * oboe_bson_append_finish_object( oboe_bson_buffer * b );
195
+
196
+ void oboe_bson_numstr(char* str, int i);
197
+ void oboe_bson_incnumstr(char* str);
198
+
199
+
200
+ /* ------------------------------
201
+ ERROR HANDLING - also used in mongo code
202
+ ------------------------------ */
203
+
204
+ void * oboe_bson_malloc(int size); /* checks return value */
205
+
206
+ /* bson_err_handlers shouldn't return!!! */
207
+ typedef void(*ob_bson_err_handler)(const char* errmsg);
208
+
209
+ /* returns old handler or NULL */
210
+ /* default handler prints error then exits with failure*/
211
+ ob_bson_err_handler oboe_set_bson_err_handler(ob_bson_err_handler func);
212
+
213
+
214
+
215
+ /* does nothing is ok != 0 */
216
+ void oboe_bson_fatal( int ok );
217
+ int oboe_bson_fatal_msg( int ok, const char* msg );
218
+
219
+ MONGO_EXTERN_C_END
220
+ #endif
@@ -0,0 +1,91 @@
1
+ /* platform_hacks.h */
2
+ /* Copyright 2009, 2010 10gen Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+
18
+ /* all platform-specific ifdefs should go here */
19
+
20
+ #ifndef _PLATFORM_HACKS_H_
21
+ #define _PLATFORM_HACKS_H_
22
+
23
+ #ifdef __GNUC__
24
+ #define MONGO_INLINE static __inline__
25
+ #else
26
+ #define MONGO_INLINE static
27
+ #endif
28
+
29
+ #ifdef __cplusplus
30
+ #define MONGO_EXTERN_C_START extern "C" {
31
+ #define MONGO_EXTERN_C_END }
32
+ #else
33
+ #define MONGO_EXTERN_C_START
34
+ #define MONGO_EXTERN_C_END
35
+ #endif
36
+
37
+
38
+ #if defined(MONGO_HAVE_STDINT) || __STDC_VERSION__ >= 199901L
39
+ #include <stdint.h>
40
+ #elif defined(MONGO_HAVE_UNISTD)
41
+ #include <unistd.h>
42
+ #elif defined(MONGO_USE__INT64)
43
+ typedef __int64 int64_t;
44
+ #elif defined(MONGO_USE_LONG_LONG_INT)
45
+ typedef long long int int64_t;
46
+ #else
47
+ #error must have a 64bit int type
48
+ #endif
49
+
50
+ /* big endian is only used for OID generation. little is used everywhere else */
51
+ #ifdef MONGO_BIG_ENDIAN
52
+ #define oboe_bson_little_endian64(out, in) ( oboe_bson_swap_endian64(out, in) )
53
+ #define oboe_bson_little_endian32(out, in) ( oboe_bson_swap_endian32(out, in) )
54
+ #define oboe_bson_big_endian64(out, in) ( memmove(out, in, 8) )
55
+ #define oboe_bson_big_endian32(out, in) ( memmove(out, in, 4) )
56
+ #else
57
+ #define oboe_bson_little_endian64(out, in) ( memmove(out, in, 8) )
58
+ #define oboe_bson_little_endian32(out, in) ( memmove(out, in, 4) )
59
+ #define oboe_bson_big_endian64(out, in) ( oboe_bson_swap_endian64(out, in) )
60
+ #define oboe_bson_big_endian32(out, in) ( oboe_bson_swap_endian32(out, in) )
61
+ #endif
62
+
63
+ MONGO_EXTERN_C_START
64
+
65
+ MONGO_INLINE void oboe_bson_swap_endian64(void* outp, const void* inp){
66
+ const char *in = (const char*)inp;
67
+ char *out = (char*)outp;
68
+
69
+ out[0] = in[7];
70
+ out[1] = in[6];
71
+ out[2] = in[5];
72
+ out[3] = in[4];
73
+ out[4] = in[3];
74
+ out[5] = in[2];
75
+ out[6] = in[1];
76
+ out[7] = in[0];
77
+
78
+ }
79
+ MONGO_INLINE void oboe_bson_swap_endian32(void* outp, const void* inp){
80
+ const char *in = (const char*)inp;
81
+ char *out = (char*)outp;
82
+
83
+ out[0] = in[3];
84
+ out[1] = in[2];
85
+ out[2] = in[1];
86
+ out[3] = in[0];
87
+ }
88
+
89
+ MONGO_EXTERN_C_END
90
+
91
+ #endif
@@ -0,0 +1,247 @@
1
+ // Copyright (c) 2021 SolarWinds, LLC.
2
+ // All rights reserved.
3
+
4
+ #include "frames.h"
5
+
6
+ using namespace std;
7
+
8
+ unordered_map<VALUE, FrameData> cached_frames;
9
+
10
+ // in theory the mutex is not needed, because Ruby does not context switch
11
+ // while executing a foreign function, but will this always hold true?
12
+ mutex cached_frames_mutex;
13
+
14
+ void Frames::reserve_cached_frames() {
15
+ lock_guard<mutex> guard(cached_frames_mutex);
16
+ // unordered_maps grow automatically, but it starts at 1 and then
17
+ // doubles when it is full, so lets avoid the warmup
18
+ cached_frames.reserve(500); // it will round to a prime number: 503
19
+ }
20
+
21
+ void Frames::clear_cached_frames() {
22
+ lock_guard<mutex> guard(cached_frames_mutex);
23
+ // unordered_maps grow automatically, but it starts at 1 and then
24
+ // doubles when it is full, so lets avoid the warmup
25
+ cached_frames.clear();
26
+ }
27
+
28
+ // this is a private function
29
+ int Frames::cache_frame(VALUE frame) {
30
+ VALUE val;
31
+ FrameData data;
32
+
33
+ // only cache it if it does not exist
34
+ if (cached_frames.count(frame) == 0) {
35
+ val = rb_profile_frame_label(frame); // returns method or block
36
+ if (RB_TYPE_P(val, T_STRING))
37
+ data.method = RSTRING_PTR(val);
38
+
39
+ if (data.method.rfind("block ", 0) == 0) {
40
+ // we don't need more info if it is a block
41
+ // we ignore block level info because they make things messy
42
+ lock_guard<mutex> guard(cached_frames_mutex);
43
+ cached_frames.insert({frame, data});
44
+ return 0;
45
+ }
46
+
47
+ val = rb_profile_frame_classpath(frame); // returns class or nil
48
+ if (RB_TYPE_P(val, T_STRING)) data.klass = RSTRING_PTR(val);
49
+
50
+ val = rb_profile_frame_absolute_path(frame); // returns file, use rb_profile_frame_path() if nil
51
+ if (!RB_TYPE_P(val, T_STRING)) val = rb_profile_frame_path(frame);
52
+ if (RB_TYPE_P(val, T_STRING)) data.file = RSTRING_PTR(val);
53
+
54
+ // Ruby 3 reports <cfunc>, but the linenumbers are bogus
55
+ // the default line number is 0
56
+ if (!data.file.compare("<cfunc>") == 0) {
57
+ val = rb_profile_frame_first_lineno(frame); // returns line number
58
+ if (RB_TYPE_P(val, T_FIXNUM)) {
59
+ data.lineno = NUM2INT(val);
60
+ }
61
+ }
62
+ lock_guard<mutex> guard(cached_frames_mutex);
63
+ cached_frames.insert({frame, data});
64
+ }
65
+ return 0;
66
+ }
67
+
68
+ // all frames in frames_buffer must be in cached_frames
69
+ // before calling this function
70
+ // we are saving the check for better performance
71
+ int Frames::collect_frame_data(VALUE *frames_buffer, int num, vector<FrameData> &frame_data) {
72
+ if (num == 1) {
73
+ if (frames_buffer[0] == PR_IN_GC) {
74
+ FrameData data;
75
+ data.method = "GARBAGE COLLECTION";
76
+ frame_data.push_back(data);
77
+ return 0;
78
+ } else if (frames_buffer[0] == PR_OTHER_THREAD) {
79
+ FrameData data;
80
+ data.method = "OTHER THREADS";
81
+ frame_data.push_back(data);
82
+ return 0;
83
+ }
84
+ }
85
+
86
+ for (int i = 0; i < num; i++) {
87
+ VALUE frame = frames_buffer[i];
88
+ frame_data.push_back(cached_frames[frame]);
89
+ }
90
+ return 0;
91
+ }
92
+
93
+ /////
94
+ // For the sake of efficiency this function filters uninteresting frames and
95
+ // does the caching of frames at the same time
96
+ //
97
+ // in-place removal of
98
+ // - frames with line number == 0
99
+ // - all but last of repeated frames
100
+ // - "block" frames (they are confusing) <- revisit
101
+ // and cache uncached frames
102
+ int Frames::remove_garbage(VALUE *frames_buffer, int num) {
103
+ if (num == 1 && (frames_buffer[0] == PR_OTHER_THREAD || frames_buffer[0] == PR_IN_GC))
104
+ return 1;
105
+
106
+ // TODO decide what to do with <cfunc> frames in Ruby 3
107
+ // ____ AO-20269
108
+
109
+ // 1) ignore top frames where the line number is 0
110
+ // does that mean there is no line number???
111
+ bool found = true;
112
+
113
+ while (found && num > 0) {
114
+ if (cached_frames.count(frames_buffer[num - 1]) == 1) {
115
+ found = (cached_frames[frames_buffer[num - 1]].lineno == 0);
116
+ if (found) num--;
117
+ } else {
118
+ VALUE val = rb_profile_frame_first_lineno(frames_buffer[num - 1]);
119
+ found = (!RB_TYPE_P(val, T_FIXNUM) || !NUM2INT(val));
120
+ if (found) {
121
+ lock_guard<mutex> guard(cached_frames_mutex);
122
+ cached_frames[frames_buffer[num - 1]].lineno = 0;
123
+ num--;
124
+ }
125
+ }
126
+ }
127
+
128
+ // 2) remove all repeated frames, keep the last one
129
+ int count = 0;
130
+ int k = 0;
131
+ found = false;
132
+ while (count < num - k) {
133
+ // is this frame repeated ahead?
134
+ // if so we will replace it with the next one in line
135
+ for (int j = count + k + 1; j < num; j++) {
136
+ if (frames_buffer[count] == frames_buffer[j]) {
137
+ found = true;
138
+ break;
139
+ }
140
+ }
141
+
142
+ if (found) {
143
+ // if we found this frame again later in the snapshot
144
+ // we are going to override this one
145
+ // but not if this is going beyond the boundary
146
+ k++;
147
+ if (count + k < num - 1) frames_buffer[count] = frames_buffer[count + k];
148
+ } else {
149
+ count++;
150
+ frames_buffer[count] = frames_buffer[count + k];
151
+ }
152
+ found = false;
153
+ }
154
+
155
+ // 3) remove "block" frames, they are reported inconsistently and mess up
156
+ // the profile in the dashboard
157
+ // 4) while we are at it we also cache all the frames
158
+ // these 2 are combined so we don't have to run this loop twice
159
+ num = count;
160
+ count = 0, k = 0;
161
+ string method;
162
+
163
+ while (count < num - k) {
164
+ frames_buffer[count] = frames_buffer[count + k];
165
+ cache_frame(frames_buffer[count]);
166
+ method = cached_frames[frames_buffer[count]].method;
167
+
168
+ // TODO revisit need to remove block frames, they only appear when the Ruby
169
+ // ____ script is not started with a method and has blocks outside of the
170
+ // ____ methods called and sometimes inside of rack
171
+ if (method.rfind("block ", 0) == 0) {
172
+ k++;
173
+ } else {
174
+ count++;
175
+ }
176
+ }
177
+ return count;
178
+ }
179
+
180
+ // returns the number of the matching frames
181
+ int Frames::num_matching(VALUE *frames_buffer, int num,
182
+ VALUE *prev_frames_buffer, int prev_num) {
183
+ int i;
184
+ int min = std::min(num, prev_num);
185
+
186
+ for (i = 0; i < min; i++) {
187
+ // we have to start from the "top"
188
+ if (frames_buffer[num - 1 - i] != prev_frames_buffer[prev_num - 1 - i]) {
189
+ return i;
190
+ }
191
+ }
192
+ return i;
193
+ }
194
+
195
+ /////////////////////// DEBUGGING HELPER FUNCTIONS /////////////////////////////
196
+ // helper function to print frame from ruby pointers to frame
197
+ void Frames::print_raw_frame_info(VALUE frame) {
198
+ if (frame == PR_IN_GC || frame == PR_OTHER_THREAD) {
199
+ return;
200
+ }
201
+
202
+ VALUE val;
203
+ int lineno;
204
+ string file, klass, method;
205
+
206
+ val = rb_profile_frame_first_lineno(frame); // returns line number
207
+ if (RB_TYPE_P(val, T_FIXNUM)) lineno = NUM2INT(val);
208
+
209
+ val = rb_profile_frame_classpath(frame); // returns class or nil
210
+ if (RB_TYPE_P(val, T_STRING)) klass = RSTRING_PTR(val);
211
+
212
+ val = rb_profile_frame_absolute_path(frame); // returns file, use rb_profile_frame_path() if nil
213
+ if (!RB_TYPE_P(val, T_STRING)) val = rb_profile_frame_path(frame);
214
+ if (RB_TYPE_P(val, T_STRING)) file = RSTRING_PTR(val);
215
+
216
+ val = rb_profile_frame_label(frame); // returns method or block
217
+ if (RB_TYPE_P(val, T_STRING)) method = RSTRING_PTR(val);
218
+
219
+ cout << " " << frame << " "
220
+ << "L: " << lineno << " "
221
+ << "F: " << file << " "
222
+ << "C: " << klass << " "
223
+ << "M: " << method << endl;
224
+ }
225
+
226
+ void Frames::print_all_raw_frames(VALUE *frames_buffer, int num) {
227
+ for (int i = 0; i < num; i++) {
228
+ print_raw_frame_info(frames_buffer[i]);
229
+ }
230
+ }
231
+
232
+ // helper function to print frame info
233
+ void Frames::print_frame_info(VALUE frame) {
234
+ if (cached_frames.find(frame) != cached_frames.end())
235
+ std::cout << cached_frames[frame].lineno << " "
236
+ << cached_frames[frame].file << " "
237
+ << cached_frames[frame].klass << " "
238
+ << cached_frames[frame].method << std::endl;
239
+ }
240
+
241
+ // helper function for printing the cached frames
242
+ void Frames::print_cached_frames() {
243
+ std::cout << "cached_frames contains:" << endl;
244
+ for (auto it = cached_frames.cbegin(); it != cached_frames.cend(); ++it)
245
+ std::cout << " " << it->first << " - " << it->second.method << ":" << it->second.lineno << endl; // cannot modify *it
246
+ std::cout << std::endl;
247
+ }
@@ -0,0 +1,40 @@
1
+ // Copyright (c) 2021 SolarWinds, LLC.
2
+ // All rights reserved.
3
+
4
+ #ifndef FRAMES_H
5
+ #define FRAMES_H
6
+
7
+ #include <vector>
8
+
9
+ #include <mutex>
10
+ #include <unordered_map>
11
+
12
+ #include <ruby/ruby.h>
13
+ #include <ruby/debug.h>
14
+
15
+ #include "profiling.h"
16
+ #include "oboe_api.hpp"
17
+
18
+ using namespace std;
19
+
20
+ class Frames {
21
+ public:
22
+ static void clear_cached_frames();
23
+ static void reserve_cached_frames();
24
+ static int collect_frame_data(VALUE *frames_buffer, int num, vector<FrameData> &frame_data);
25
+ static int remove_garbage(VALUE *frames_buffer, int num);
26
+ static int num_matching(VALUE *frames_buffer, int num,
27
+ VALUE *prev_frames_buffer, int prev_num);
28
+
29
+ private:
30
+ static int cache_frame(VALUE frame);
31
+
32
+ // Debugging helper functions
33
+ public:
34
+ static void print_raw_frame_info(VALUE frame);
35
+ static void print_all_raw_frames(VALUE *frames_buffer, int num);
36
+ static void print_frame_info(VALUE frame);
37
+ static void print_cached_frames();
38
+ };
39
+
40
+ #endif //FRAMES_H
@@ -0,0 +1,21 @@
1
+ // Copyright (c) 2019 SolarWinds, LLC.
2
+ // All rights reserved.
3
+
4
+ #include <iostream>
5
+
6
+ #ifdef __cplusplus
7
+ extern "C" {
8
+ #endif
9
+
10
+ void Init_oboe_metal(void);
11
+
12
+ void Init_profiling(void);
13
+
14
+ void Init_libsolarwinds_apm() {
15
+ Init_oboe_metal();
16
+ Init_profiling();
17
+ }
18
+
19
+ #ifdef __cplusplus
20
+ }
21
+ #endif