solarwinds_apm 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.dockerignore +5 -0
- data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
- data/.github/workflows/build_and_release_gem.yml +112 -0
- data/.github/workflows/build_for_packagecloud.yml +70 -0
- data/.github/workflows/docker-images.yml +47 -0
- data/.github/workflows/run_cpluplus_tests.yml +73 -0
- data/.github/workflows/run_tests.yml +155 -0
- data/.github/workflows/scripts/test_install.rb +23 -0
- data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
- data/.github/workflows/test_on_4_linux.yml +161 -0
- data/.gitignore +39 -0
- data/.rubocop.yml +29 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +769 -0
- data/CONFIG.md +31 -0
- data/Gemfile +14 -0
- data/LICENSE +202 -0
- data/README.md +383 -0
- data/bin/solarwinds_apm_config +15 -0
- data/examples/prepend.rb +13 -0
- data/examples/sdk_examples.rb +158 -0
- data/ext/oboe_metal/README.md +69 -0
- data/ext/oboe_metal/extconf.rb +141 -0
- data/ext/oboe_metal/extconf_local.rb +75 -0
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/noop/noop.c +8 -0
- data/ext/oboe_metal/src/README.md +6 -0
- data/ext/oboe_metal/src/VERSION +2 -0
- data/ext/oboe_metal/src/bson/bson.h +220 -0
- data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
- data/ext/oboe_metal/src/frames.cc +247 -0
- data/ext/oboe_metal/src/frames.h +40 -0
- data/ext/oboe_metal/src/init_solarwinds_apm.cc +21 -0
- data/ext/oboe_metal/src/logging.cc +95 -0
- data/ext/oboe_metal/src/logging.h +35 -0
- data/ext/oboe_metal/src/oboe.h +1169 -0
- data/ext/oboe_metal/src/oboe_api.cpp +658 -0
- data/ext/oboe_metal/src/oboe_api.hpp +433 -0
- data/ext/oboe_metal/src/oboe_debug.h +59 -0
- data/ext/oboe_metal/src/oboe_swig_wrap.cc +7562 -0
- data/ext/oboe_metal/src/profiling.cc +435 -0
- data/ext/oboe_metal/src/profiling.h +78 -0
- data/ext/oboe_metal/test/CMakeLists.txt +53 -0
- data/ext/oboe_metal/test/FindGMock.cmake +43 -0
- data/ext/oboe_metal/test/README.md +56 -0
- data/ext/oboe_metal/test/frames_test.cc +164 -0
- data/ext/oboe_metal/test/profiling_test.cc +93 -0
- data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
- data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
- data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
- data/ext/oboe_metal/test/test.h +11 -0
- data/ext/oboe_metal/test/test_main.cc +32 -0
- data/init.rb +4 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe_metal.rb +172 -0
- data/lib/rails/generators/solarwinds_apm/install_generator.rb +47 -0
- data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +424 -0
- data/lib/solarwinds_apm/api/layerinit.rb +41 -0
- data/lib/solarwinds_apm/api/logging.rb +356 -0
- data/lib/solarwinds_apm/api/memcache.rb +37 -0
- data/lib/solarwinds_apm/api/metrics.rb +63 -0
- data/lib/solarwinds_apm/api/util.rb +98 -0
- data/lib/solarwinds_apm/api.rb +21 -0
- data/lib/solarwinds_apm/base.rb +160 -0
- data/lib/solarwinds_apm/config.rb +301 -0
- data/lib/solarwinds_apm/frameworks/grape.rb +96 -0
- data/lib/solarwinds_apm/frameworks/padrino.rb +78 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +100 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +50 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +88 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +26 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +22 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +103 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +14 -0
- data/lib/solarwinds_apm/frameworks/rails.rb +100 -0
- data/lib/solarwinds_apm/frameworks/sinatra.rb +96 -0
- data/lib/solarwinds_apm/inst/bunny-client.rb +157 -0
- data/lib/solarwinds_apm/inst/bunny-consumer.rb +102 -0
- data/lib/solarwinds_apm/inst/curb.rb +288 -0
- data/lib/solarwinds_apm/inst/dalli.rb +89 -0
- data/lib/solarwinds_apm/inst/delayed_job.rb +100 -0
- data/lib/solarwinds_apm/inst/excon.rb +113 -0
- data/lib/solarwinds_apm/inst/faraday.rb +96 -0
- data/lib/solarwinds_apm/inst/graphql.rb +206 -0
- data/lib/solarwinds_apm/inst/grpc_client.rb +147 -0
- data/lib/solarwinds_apm/inst/grpc_server.rb +119 -0
- data/lib/solarwinds_apm/inst/httpclient.rb +181 -0
- data/lib/solarwinds_apm/inst/logger_formatter.rb +46 -0
- data/lib/solarwinds_apm/inst/logging_log_event.rb +24 -0
- data/lib/solarwinds_apm/inst/lumberjack_formatter.rb +9 -0
- data/lib/solarwinds_apm/inst/memcached.rb +86 -0
- data/lib/solarwinds_apm/inst/mongo.rb +246 -0
- data/lib/solarwinds_apm/inst/mongo2.rb +225 -0
- data/lib/solarwinds_apm/inst/moped.rb +466 -0
- data/lib/solarwinds_apm/inst/net_http.rb +60 -0
- data/lib/solarwinds_apm/inst/rack.rb +217 -0
- data/lib/solarwinds_apm/inst/rack_cache.rb +35 -0
- data/lib/solarwinds_apm/inst/redis.rb +273 -0
- data/lib/solarwinds_apm/inst/resque.rb +129 -0
- data/lib/solarwinds_apm/inst/rest-client.rb +43 -0
- data/lib/solarwinds_apm/inst/sequel.rb +241 -0
- data/lib/solarwinds_apm/inst/sidekiq-client.rb +63 -0
- data/lib/solarwinds_apm/inst/sidekiq-worker.rb +64 -0
- data/lib/solarwinds_apm/inst/typhoeus.rb +90 -0
- data/lib/solarwinds_apm/instrumentation.rb +22 -0
- data/lib/solarwinds_apm/loading.rb +65 -0
- data/lib/solarwinds_apm/logger.rb +14 -0
- data/lib/solarwinds_apm/noop/README.md +9 -0
- data/lib/solarwinds_apm/noop/context.rb +26 -0
- data/lib/solarwinds_apm/noop/metadata.rb +25 -0
- data/lib/solarwinds_apm/noop/profiling.rb +21 -0
- data/lib/solarwinds_apm/oboe_init_options.rb +191 -0
- data/lib/solarwinds_apm/ruby.rb +35 -0
- data/lib/solarwinds_apm/sdk/current_trace_info.rb +123 -0
- data/lib/solarwinds_apm/sdk/custom_metrics.rb +94 -0
- data/lib/solarwinds_apm/sdk/logging.rb +37 -0
- data/lib/solarwinds_apm/sdk/trace_context_headers.rb +69 -0
- data/lib/solarwinds_apm/sdk/tracing.rb +432 -0
- data/lib/solarwinds_apm/support/profiling.rb +22 -0
- data/lib/solarwinds_apm/support/trace_context.rb +53 -0
- data/lib/solarwinds_apm/support/trace_state.rb +69 -0
- data/lib/solarwinds_apm/support/trace_string.rb +89 -0
- data/lib/solarwinds_apm/support/transaction_metrics.rb +67 -0
- data/lib/solarwinds_apm/support/transaction_settings.rb +233 -0
- data/lib/solarwinds_apm/support/x_trace_options.rb +113 -0
- data/lib/solarwinds_apm/support.rb +12 -0
- data/lib/solarwinds_apm/support_report.rb +113 -0
- data/lib/solarwinds_apm/test.rb +165 -0
- data/lib/solarwinds_apm/thread_local.rb +26 -0
- data/lib/solarwinds_apm/util.rb +334 -0
- data/lib/solarwinds_apm/version.rb +17 -0
- data/lib/solarwinds_apm.rb +72 -0
- data/log/.keep +0 -0
- data/log/postgresql/.keep +0 -0
- data/solarwinds_apm.gemspec +52 -0
- data/yardoc_frontpage.md +24 -0
- 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
|