appoptics_apm 4.11.2 → 4.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build_and_release_gem.yml +103 -0
  3. data/.github/workflows/build_for_packagecloud.yml +70 -0
  4. data/.github/workflows/docker-images.yml +47 -0
  5. data/.github/workflows/run_cpluplus_tests.yml +73 -0
  6. data/.github/workflows/run_tests.yml +168 -0
  7. data/.github/workflows/scripts/test_install.rb +23 -0
  8. data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
  9. data/.github/workflows/test_on_4_linux.yml +159 -0
  10. data/.gitignore +26 -25
  11. data/.travis.yml +30 -23
  12. data/Gemfile +2 -26
  13. data/LICENSE +202 -193
  14. data/README.md +6 -6
  15. data/appoptics_apm.gemspec +15 -8
  16. data/examples/prepend.rb +13 -0
  17. data/examples/sdk_examples.rb +16 -0
  18. data/ext/oboe_metal/README.md +2 -2
  19. data/ext/oboe_metal/extconf.rb +45 -22
  20. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
  21. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
  22. data/ext/oboe_metal/src/README.md +6 -0
  23. data/ext/oboe_metal/src/VERSION +2 -1
  24. data/ext/oboe_metal/src/frames.cc +246 -0
  25. data/ext/oboe_metal/src/frames.h +40 -0
  26. data/ext/oboe_metal/src/init_appoptics_apm.cc +21 -0
  27. data/ext/oboe_metal/src/logging.cc +95 -0
  28. data/ext/oboe_metal/src/logging.h +35 -0
  29. data/ext/oboe_metal/src/oboe.h +46 -23
  30. data/ext/oboe_metal/src/oboe_api.cpp +652 -0
  31. data/ext/oboe_metal/src/oboe_api.hpp +431 -0
  32. data/ext/oboe_metal/src/oboe_debug.h +2 -0
  33. data/ext/oboe_metal/src/{oboe_wrap.cxx → oboe_swig_wrap.cc} +1523 -1327
  34. data/ext/oboe_metal/src/profiling.cc +435 -0
  35. data/ext/oboe_metal/src/profiling.h +78 -0
  36. data/ext/oboe_metal/test/CMakeLists.txt +53 -0
  37. data/ext/oboe_metal/test/FindGMock.cmake +43 -0
  38. data/ext/oboe_metal/test/README.md +56 -0
  39. data/ext/oboe_metal/test/frames_test.cc +164 -0
  40. data/ext/oboe_metal/test/profiling_test.cc +93 -0
  41. data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
  42. data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
  43. data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
  44. data/ext/oboe_metal/test/test.h +11 -0
  45. data/ext/oboe_metal/test/test_main.cc +32 -0
  46. data/lib/appoptics_apm/api/metrics.rb +7 -1
  47. data/lib/appoptics_apm/base.rb +1 -1
  48. data/lib/appoptics_apm/config.rb +20 -10
  49. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +64 -21
  50. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +7 -1
  51. data/lib/appoptics_apm/frameworks/rails.rb +7 -1
  52. data/lib/appoptics_apm/inst/http.rb +67 -59
  53. data/lib/appoptics_apm/inst/rack.rb +13 -6
  54. data/lib/appoptics_apm/inst/rack_cache.rb +35 -0
  55. data/lib/appoptics_apm/inst/redis.rb +1 -2
  56. data/lib/appoptics_apm/noop/context.rb +4 -3
  57. data/lib/appoptics_apm/noop/metadata.rb +4 -1
  58. data/lib/appoptics_apm/noop/profiling.rb +21 -0
  59. data/lib/appoptics_apm/oboe_init_options.rb +41 -23
  60. data/lib/appoptics_apm/sdk/current_trace.rb +5 -9
  61. data/lib/appoptics_apm/support/profiling.rb +18 -0
  62. data/lib/appoptics_apm/support/transaction_metrics.rb +1 -1
  63. data/lib/appoptics_apm/support/transaction_settings.rb +3 -3
  64. data/lib/appoptics_apm/support/x_trace_options.rb +2 -2
  65. data/lib/appoptics_apm/support_report.rb +2 -2
  66. data/lib/appoptics_apm/test.rb +5 -4
  67. data/lib/appoptics_apm/util.rb +4 -3
  68. data/lib/appoptics_apm/version.rb +4 -3
  69. data/lib/appoptics_apm/xtrace.rb +1 -1
  70. data/lib/appoptics_apm.rb +4 -2
  71. data/lib/oboe_metal.rb +2 -2
  72. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +80 -20
  73. data/log/.keep +0 -0
  74. metadata +47 -14
  75. data/.travis/bundle.sh +0 -9
  76. data/ext/oboe_metal/src/oboe.hpp +0 -874
@@ -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_libappoptics_apm() {
15
+ Init_oboe_metal();
16
+ Init_profiling();
17
+ }
18
+
19
+ #ifdef __cplusplus
20
+ }
21
+ #endif
@@ -0,0 +1,95 @@
1
+ // Copyright (c) 2021 SolarWinds, LLC.
2
+ // All rights reserved.
3
+
4
+ #include "logging.h"
5
+
6
+ using namespace std;
7
+
8
+ const string Logging::profiling = "profiling";
9
+ const string Logging::ruby = "ruby";
10
+ const string Logging::entry = "entry";
11
+ const string Logging::info = "info";
12
+ const string Logging::exit = "exit";
13
+
14
+ Event *Logging::createEvent(Metadata &md, string &prof_op_id, bool entry_event) {
15
+ // startTrace does not add "Edge", for profiling we need to keep track of edges
16
+ // separately from the main trace metadata
17
+
18
+ oboe_metadata_t *md_t = md.metadata();
19
+ Event *event = Event::startTrace(md_t);
20
+
21
+ if (entry_event) {
22
+ event->addSpanRef(md_t);
23
+ } else {
24
+ event->addProfileEdge(prof_op_id);
25
+ event->addContextOpId(md_t);
26
+ }
27
+ prof_op_id.assign(event->opIdString());
28
+
29
+ return event;
30
+ }
31
+
32
+ bool Logging::log_profile_entry(Metadata &md, string &prof_op_id, pid_t tid, long interval) {
33
+ Event *event = Logging::createEvent(md, prof_op_id, true);
34
+ event->addInfo((char *)"Label", Logging::entry);
35
+ event->addInfo((char *)"Language", Logging::ruby);
36
+ event->addInfo((char *)"TID", (long)tid);
37
+ event->addInfo((char *)"Interval", interval);
38
+
39
+ struct timeval tv;
40
+ oboe_gettimeofday(&tv);
41
+ event->addInfo((char *)"Timestamp_u", (long)tv.tv_sec * 1000000 + (long)tv.tv_usec);
42
+
43
+ return Logging::log_profile_event(event);
44
+ }
45
+
46
+ bool Logging::log_profile_exit(Metadata &md, string &prof_op_id, pid_t tid,
47
+ long *omitted, int num_omitted) {
48
+ Event *event = Logging::createEvent(md, prof_op_id);
49
+ event->addInfo((char *)"Label", Logging::exit);
50
+ event->addInfo((char *)"TID", (long)tid);
51
+ event->addInfo((char *)"SnapshotsOmitted", omitted, num_omitted);
52
+
53
+ struct timeval tv;
54
+ oboe_gettimeofday(&tv);
55
+ event->addInfo((char *)"Timestamp_u", (long)tv.tv_sec * 1000000 + (long)tv.tv_usec);
56
+
57
+ return Logging::log_profile_event(event);
58
+ }
59
+
60
+ bool Logging::log_profile_snapshot(Metadata &md,
61
+ string &prof_op_id,
62
+ long timestamp,
63
+ std::vector<FrameData> const &new_frames,
64
+ long exited_frames,
65
+ long total_frames,
66
+ long *omitted,
67
+ int num_omitted,
68
+ pid_t tid) {
69
+
70
+ Event *event = Logging::createEvent(md, prof_op_id);
71
+ event->addInfo((char *)"Timestamp_u", timestamp);
72
+ event->addInfo((char *)"Label", Logging::info);
73
+
74
+ event->addInfo((char *)"SnapshotsOmitted", omitted, num_omitted);
75
+ event->addInfo((char *)"NewFrames", new_frames);
76
+ event->addInfo((char *)"FramesExited", exited_frames);
77
+ event->addInfo((char *)"FramesCount", total_frames);
78
+ event->addInfo((char *)"TID", (long)tid);
79
+
80
+ return Logging::log_profile_event(event);
81
+ }
82
+
83
+ bool Logging::log_profile_event(Event *event) {
84
+ event->addInfo((char *)"Spec", Logging::profiling);
85
+ event->addHostname();
86
+ event->addInfo((char *)"PID", (long)AO_GETPID());
87
+ event->addInfo((char *)"X-Trace", event->metadataString());
88
+ event->sendProfiling();
89
+
90
+ // see comment in oboe_api.cpp:
91
+ // "event needs to be deleted, it is managed by swig %newobject"
92
+ // !!! It needs to be deleted, I tested it !!!
93
+ delete event;
94
+ return true;
95
+ }
@@ -0,0 +1,35 @@
1
+ // Copyright (c) 2021 SolarWinds, LLC.
2
+ // All rights reserved.
3
+
4
+ #ifndef LOGGING_H
5
+ #define LOGGING_H
6
+
7
+ #include "oboe_api.hpp"
8
+
9
+ using namespace std;
10
+
11
+ extern "C" int oboe_gettimeofday(struct timeval *tv);
12
+
13
+
14
+ class Logging {
15
+ public:
16
+ static const string profiling, ruby, entry, info, exit;
17
+ static bool log_profile_entry(Metadata &md, string &prof_op_id, pid_t tid, long interval);
18
+ static bool log_profile_exit(Metadata &md, string &prof_op_id, pid_t tid,
19
+ long *omitted, int num_omitted);
20
+ static bool log_profile_snapshot(Metadata &md,
21
+ string &prof_op_id,
22
+ long timestamp,
23
+ std::vector<FrameData> const &new_frames,
24
+ long exited_frames,
25
+ long total_frames,
26
+ long *omitted,
27
+ int num_omitted,
28
+ pid_t tid);
29
+
30
+ private:
31
+ static Event *createEvent(Metadata &md, string &prof_op_id, bool entry_event = false);
32
+ static bool log_profile_event(Event *event);
33
+ };
34
+
35
+ #endif //LOGGING_H
@@ -103,6 +103,7 @@ extern "C" {
103
103
  #define OBOE_REPORTER_PROTOCOL_UDP "udp"
104
104
  #define OBOE_REPORTER_PROTOCOL_SSL "ssl"
105
105
  #define OBOE_REPORTER_PROTOCOL_NULL "null"
106
+ #define OBOE_REPORTER_PROTOCOL_LAMBDA "lambda"
106
107
 
107
108
  /** Maximum reasonable length of an arguments string for configuring a reporter. */
108
109
  #define OBOE_REPORTER_ARGS_SIZE 4000
@@ -160,7 +161,7 @@ typedef struct oboe_metric_tag {
160
161
  } oboe_metric_tag_t;
161
162
 
162
163
  typedef struct oboe_init_options {
163
- int version; // the version of this structure
164
+ int version; // the version of this structure (currently on version 12)
164
165
  const char *hostname_alias; // optional hostname alias
165
166
  int log_level; // level at which log messages will be written to log file (0-6)
166
167
  // use LOGLEVEL_DEFAULT for default log level
@@ -170,19 +171,22 @@ typedef struct oboe_init_options {
170
171
  int events_flush_interval; // events flush timeout in seconds (threshold for batching messages before sending off)
171
172
  int max_request_size_bytes; // limit max RPC request size
172
173
 
173
- const char *reporter; // the reporter to be used (ssl, upd, file, null)
174
+ const char *reporter; // the reporter to be used (ssl, upd, file, null, lambda)
174
175
  const char *host; // collector endpoint (reporter=ssl), udp address (reporter=udp), or file path (reporter=file)
175
176
  const char *service_key; // the service key
176
177
  const char *trusted_path; // path to the SSL certificate (only for ssl)
177
178
  int buffer_size; // size of the message buffer
178
179
  int trace_metrics; // flag indicating if trace metrics reporting should be enabled (default) or disabled
179
180
  int histogram_precision; // the histogram precision (only for ssl)
180
- int token_bucket_capacity; // custom token bucket capacity
181
- int token_bucket_rate; // custom token bucket rate
181
+ double token_bucket_capacity; // custom token bucket capacity
182
+ double token_bucket_rate; // custom token bucket rate
182
183
  int file_single; // use single files in file reporter for each event
183
184
 
184
185
  int ec2_metadata_timeout; // EC2 metadata timeout in milliseconds
185
186
  const char *proxy; // HTTP proxy address and port to be used for the gRPC connection
187
+ int stdout_clear_nonblocking; // flag indicating if the O_NONBLOCK flag on stdout should be cleared,
188
+ // only used in lambda reporter (off=0, on=1, default off)
189
+ int is_grpc_clean_hack_enabled; // flag indicating if custom grpc clean hack enabled (default 0)
186
190
  } oboe_init_options_t;
187
191
 
188
192
  typedef struct oboe_span_params {
@@ -229,6 +233,10 @@ typedef struct oboe_tracing_decisions_out {
229
233
  int auth_status;
230
234
  const char *auth_message;
231
235
  const char *status_message;
236
+
237
+ // v3
238
+ double token_bucket_rate;
239
+ double token_bucket_capacity;
232
240
  } oboe_tracing_decisions_out_t;
233
241
 
234
242
  typedef struct oboe_internal_stats {
@@ -260,9 +268,9 @@ int oboe_metadata_destroy (oboe_metadata_t *);
260
268
 
261
269
  int oboe_metadata_is_valid (const oboe_metadata_t *);
262
270
 
263
- void oboe_metadata_copy (oboe_metadata_t *, const oboe_metadata_t *);
271
+ int oboe_metadata_copy (oboe_metadata_t *, const oboe_metadata_t *);
264
272
 
265
- void oboe_metadata_random (oboe_metadata_t *);
273
+ int oboe_metadata_random (oboe_metadata_t *);
266
274
 
267
275
  int oboe_metadata_set_lengths (oboe_metadata_t *, size_t, size_t);
268
276
  int oboe_metadata_create_event (const oboe_metadata_t *, oboe_event_t *);
@@ -306,10 +314,10 @@ int oboe_event_send(int channel, oboe_event_t *evt, oboe_metadata_t *md);
306
314
  // oboe_context
307
315
 
308
316
  oboe_metadata_t *oboe_context_get();
309
- void oboe_context_set(oboe_metadata_t *);
317
+ int oboe_context_set(oboe_metadata_t *);
310
318
  int oboe_context_set_fromstr(const char *, size_t);
311
319
 
312
- void oboe_context_clear();
320
+ int oboe_context_clear();
313
321
 
314
322
  int oboe_context_is_valid();
315
323
 
@@ -323,13 +331,14 @@ struct oboe_reporter;
323
331
  typedef int (*reporter_ready)(void *);
324
332
  typedef int (*reporter_is_within_limit)(void *, const char *, const char *);
325
333
  typedef ssize_t (*reporter_send)(void *, int, const char *, size_t);
326
- typedef int (*reporter_send_span)(void *, const char *, const char *, const int64_t);
334
+ typedef int (*reporter_send_span)(void *, const char *, const char *, const int64_t, const int);
327
335
  typedef int (*reporter_send_http_span)(void *, const char *, const char *, const int64_t, const int, const char *, const int);
328
336
  typedef int (*reporter_add_custom_metric)(void *, const char *, const double, const int, const int, const char *, const int, const oboe_metric_tag_t*, const size_t);
329
337
  typedef int (*reporter_destroy)(void *);
330
338
  typedef int (*reporter_server_response)(void *);
331
339
  typedef const char* (*reporter_server_warning)(void *);
332
340
  typedef int (*reporter_profiling_interval)(void *);
341
+ typedef int (*reporter_flush)(void *);
333
342
  typedef struct oboe_reporter {
334
343
  void * descriptor; /*!< Reporter's context. */
335
344
  reporter_ready eventReady; /*!< Check if the reporter is ready for another trace. */
@@ -346,6 +355,7 @@ typedef struct oboe_reporter {
346
355
  reporter_server_response getServerResponse;
347
356
  reporter_profiling_interval profilingInterval;
348
357
  reporter_server_warning getServerWarning;
358
+ reporter_flush flush;
349
359
  } oboe_reporter_t;
350
360
 
351
361
  /**
@@ -419,6 +429,21 @@ void oboe_reporter_disconnect(); /* TODO: Need implementation. */
419
429
  */
420
430
  void oboe_reporter_reconnect(); /* TODO: Need implementation. */
421
431
 
432
+ /**
433
+ * tell reporter to flush all messages that are currently buffered
434
+ */
435
+ int oboe_reporter_flush();
436
+
437
+ /**
438
+ * get the reporter type used
439
+ */
440
+ const char* oboe_get_reporter_type();
441
+
442
+ /**
443
+ * Check if system is AWS Lambda
444
+ */
445
+ int oboe_is_lambda();
446
+
422
447
  /**
423
448
  * Check if oboe is ready
424
449
  *
@@ -474,6 +499,7 @@ void oboe_shutdown();
474
499
 
475
500
  // Value for "SampleSource" info key
476
501
  // where was the sample rate specified? (oboe settings, config file, hard-coded default, etc)
502
+ #define OBOE_SAMPLE_RATE_SOURCE_CONTINUED -1
477
503
  #define OBOE_SAMPLE_RATE_SOURCE_FILE 1
478
504
  #define OBOE_SAMPLE_RATE_SOURCE_DEFAULT 2
479
505
  #define OBOE_SAMPLE_RATE_SOURCE_OBOE 3
@@ -490,10 +516,6 @@ void oboe_shutdown();
490
516
  #define OBOE_TRACE_DISABLED 0
491
517
  #define OBOE_TRACE_ENABLED 1
492
518
 
493
- #if defined _WIN32
494
- #pragma pack(push, 1)
495
- #endif
496
-
497
519
  #define OBOE_SEND_EVENT 0
498
520
  #define OBOE_SEND_STATUS 1
499
521
  #define OBOE_SEND_PROFILING 2
@@ -569,6 +591,7 @@ const char* oboe_get_tracing_decisions_auth_message (int code);
569
591
  #define OBOE_INIT_SSL_CONFIG_AUTH 8
570
592
  #define OBOE_INIT_SSL_LOAD_CERT 9
571
593
  #define OBOE_INIT_SSL_REPORTER_CREATE 10
594
+ #define OBOE_INIT_SSL_MISSING_KEY 11
572
595
 
573
596
  //
574
597
  // these codes are returned by oboe_notifier_status()
@@ -609,6 +632,15 @@ const char* oboe_get_tracing_decisions_auth_message (int code);
609
632
  #define OBOE_CUSTOM_METRICS_STOPPING 4
610
633
  #define OBOE_CUSTOM_METRICS_QUEUE_LIMIT_EXCEEDED 5
611
634
 
635
+ //
636
+ // these codes are returned by oboe_reporter_flush()
637
+ //
638
+ #define OBOE_REPORTER_FLUSH_OK 0
639
+ #define OBOE_REPORTER_FLUSH_METRIC_ERROR 1
640
+ #define OBOE_REPORTER_FLUSH_BAD_UTF8 2
641
+ #define OBOE_REPORTER_FLUSH_NO_REPORTER 3
642
+ #define OBOE_REPORTER_FLUSH_REPORTER_NOT_READY 4
643
+
612
644
  // token buckets
613
645
  enum TOKEN_BUCKETS {
614
646
  TOKEN_BUCKET_SAMPLING, // for normal requests
@@ -1020,16 +1052,6 @@ extern int oboe_config_get_revision();
1020
1052
  */
1021
1053
  const char* oboe_config_get_version_string();
1022
1054
 
1023
- /*
1024
- * Generate UUID for RUM
1025
- *
1026
- * @param access_key User Access Key
1027
- * @param uuid_length Size of the UUID to generate
1028
- * @param digest Pointer to array where the digest value gets stored
1029
- * @param dlen Number of bytes of data stored
1030
- */
1031
- void oboe_rum_create_digest(const char* access_key, unsigned int uuid_length, unsigned char* digest, unsigned int *dlen);
1032
-
1033
1055
  // Span reporting
1034
1056
 
1035
1057
  /*
@@ -1126,6 +1148,7 @@ int oboe_notifier_stop(int blocking);
1126
1148
  int oboe_notifier_status();
1127
1149
  int oboe_notifier_test(int test_case, const char *test_str);
1128
1150
 
1151
+
1129
1152
  #ifdef __cplusplus
1130
1153
  } // extern "C"
1131
1154
  #endif
@@ -0,0 +1,652 @@
1
+ /**
2
+ * @file oboe_api.cpp - C++ liboboe wrapper primarily used via swig interfaces
3
+ * by the python and ruby agents
4
+ *
5
+ * TODO: This doc is outdated
6
+ * This API should follow https://github.com/tracelytics/tracelons/wiki/Instrumentation-API
7
+ **/
8
+
9
+ #include "oboe_api.hpp"
10
+
11
+ /////// Metatdata ///////
12
+
13
+ Metadata::Metadata(const oboe_metadata_t *md) {
14
+ oboe_metadata_copy(this, md);
15
+ }
16
+
17
+ Metadata::~Metadata() {
18
+ oboe_metadata_destroy(this);
19
+ }
20
+
21
+ Metadata *Metadata::makeRandom(bool sampled) {
22
+ oboe_metadata_t md;
23
+ oboe_metadata_init(&md);
24
+ oboe_metadata_random(&md);
25
+
26
+ if (sampled) md.flags |= XTR_FLAGS_SAMPLED;
27
+
28
+ return new Metadata(&md); // copies md
29
+ }
30
+
31
+ Metadata *Metadata::copy() {
32
+ return new Metadata(this);
33
+ }
34
+
35
+ bool Metadata::isValid() {
36
+ return oboe_metadata_is_valid(this);
37
+ }
38
+
39
+ bool Metadata::isSampled() {
40
+ return oboe_metadata_is_sampled(this);
41
+ }
42
+
43
+ Metadata *Metadata::fromString(std::string s) {
44
+ oboe_metadata_t md;
45
+ oboe_metadata_fromstr(&md, s.data(), s.size());
46
+ return new Metadata(&md); // copies md
47
+ }
48
+
49
+ oboe_metadata_t *Metadata::metadata() {
50
+ return this;
51
+ }
52
+
53
+ Event *Metadata::createEvent() {
54
+ return new Event(this);
55
+ }
56
+
57
+ #ifdef SWIGJAVA
58
+ std::string Metadata::toStr() {
59
+ #else
60
+ std::string Metadata::toString() {
61
+ #endif
62
+ char buf[OBOE_MAX_METADATA_PACK_LEN]; // Flawfinder: ignore
63
+
64
+ int rc = oboe_metadata_tostr(this, buf, sizeof(buf) - 1);
65
+ if (rc == 0) {
66
+ return std::string(buf);
67
+ } else {
68
+ return std::string(); // throw exception?
69
+ }
70
+ }
71
+
72
+ /////// Context ///////
73
+
74
+ void Context::setTracingMode(int newMode) {
75
+ oboe_settings_mode_set(newMode);
76
+ }
77
+
78
+ void Context::setDefaultSampleRate(int newRate) {
79
+ oboe_settings_rate_set(newRate);
80
+ }
81
+
82
+ void Context::getDecisions(
83
+ // this paramter list is too long, but other forms of sending info
84
+ // between python/ruby and c++ would require extra roudn trips
85
+ // and may be less efficient.
86
+ // TODO: benchmark this assumption
87
+
88
+ // output
89
+ int *do_metrics,
90
+ int *do_sample,
91
+ int *sample_rate,
92
+ int *sample_source,
93
+ double *bucket_rate,
94
+ double *bucket_cap,
95
+ int *type,
96
+ int *auth,
97
+ std::string *status_msg,
98
+ std::string *auth_msg,
99
+ int *status,
100
+
101
+ // input
102
+ const char *in_xtrace,
103
+ int custom_tracing_mode,
104
+ int custom_sample_rate,
105
+ int request_type,
106
+ int custom_trigger_mode,
107
+ const char *header_options,
108
+ const char *header_signature,
109
+ long header_timestamp
110
+ ) {
111
+ oboe_tracing_decisions_in_t tdi;
112
+ memset(&tdi, 0, sizeof(tdi));
113
+ tdi.custom_tracing_mode = custom_tracing_mode;
114
+ tdi.custom_sample_rate = custom_sample_rate;
115
+ tdi.custom_trigger_mode = custom_trigger_mode;
116
+ tdi.request_type = request_type;
117
+ tdi.version = 2;
118
+ tdi.in_xtrace = in_xtrace;
119
+ tdi.header_options = header_options;
120
+ tdi.header_signature = header_signature;
121
+ tdi.header_timestamp = header_timestamp;
122
+
123
+ oboe_tracing_decisions_out_t tdo;
124
+ memset(&tdo, 0, sizeof(tdo));
125
+ tdo.version = 3;
126
+
127
+ *status = oboe_tracing_decisions(&tdi, &tdo);
128
+
129
+ *do_sample = tdo.do_sample;
130
+ *do_metrics = tdo.do_metrics;
131
+ *sample_rate = tdo.sample_rate;
132
+ *sample_source = tdo.sample_source;
133
+ *bucket_rate = tdo.token_bucket_rate;
134
+ *bucket_cap = tdo.token_bucket_capacity;
135
+ *type = tdo.request_provisioned;
136
+ if (tdo.status_message && tdo.status_message[0] != '\0') {
137
+ *status_msg = tdo.status_message;
138
+ }
139
+ *auth = tdo.auth_status;
140
+ if (tdo.auth_message && tdo.auth_message[0] != '\0') {
141
+ *auth_msg = tdo.auth_message;
142
+ }
143
+ }
144
+
145
+ oboe_metadata_t *Context::get() {
146
+ return oboe_context_get();
147
+ }
148
+
149
+ #ifdef SWIGJAVA
150
+ std::string Context::toStr() {
151
+ #else
152
+ std::string Context::toString() {
153
+ #endif
154
+ char buf[OBOE_MAX_METADATA_PACK_LEN]; // Flawfinder: ignore
155
+
156
+ oboe_metadata_t *md = Context::get();
157
+ int rc = oboe_metadata_tostr(md, buf, sizeof(buf) - 1);
158
+ if (rc == 0) {
159
+ return std::string(buf);
160
+ } else {
161
+ return std::string(); // throw exception?
162
+ }
163
+ }
164
+
165
+ void Context::set(oboe_metadata_t *md) {
166
+ oboe_context_set(md);
167
+ }
168
+
169
+ void Context::fromString(std::string s) {
170
+ oboe_context_set_fromstr(s.data(), s.size());
171
+ }
172
+
173
+ // this new object is managed by SWIG %newobject
174
+ Metadata *Context::copy() {
175
+ return new Metadata(Context::get());
176
+ }
177
+
178
+ void Context::setSampledFlag() {
179
+ oboe_metadata_t *md = Context::get();
180
+ md->flags |= XTR_FLAGS_SAMPLED;
181
+ }
182
+
183
+ void Context::clear() {
184
+ oboe_context_clear();
185
+ }
186
+
187
+ bool Context::isValid() {
188
+ return oboe_context_is_valid();
189
+ }
190
+
191
+ bool Context::isSampled() {
192
+ return oboe_context_is_sampled();
193
+ }
194
+
195
+ std::string Context::validateTransformServiceName(std::string service_key) {
196
+ char service_key_cpy[71 + 1 + 256]; // Flawfinder: ignore, key=71, colon=1, name<=255
197
+ memset(service_key_cpy, 0, sizeof(service_key_cpy));
198
+ strncpy(service_key_cpy, service_key.c_str(), sizeof(service_key_cpy) - 1); // Flawfinder: ignore
199
+ int len = strlen(service_key_cpy); // Flawfinder: ignore
200
+ int ret = oboe_validate_transform_service_name(service_key_cpy, &len);
201
+
202
+ if (ret == -1) {
203
+ return "";
204
+ }
205
+
206
+ return std::string(service_key_cpy);
207
+ }
208
+
209
+ void Context::shutdown() {
210
+ oboe_shutdown();
211
+ }
212
+
213
+ int Context::isReady(unsigned int timeout) {
214
+ return oboe_is_ready(timeout);
215
+ }
216
+
217
+ bool Context::isLambda() {
218
+ return (bool) oboe_is_lambda();
219
+ }
220
+
221
+ /**
222
+ * Create a new event object that continues the trace context.
223
+ *
224
+ * NOTE: The returned object must be "delete"d.
225
+ */
226
+ Event *Context::createEvent() {
227
+ return new Event(Context::get());
228
+ }
229
+
230
+ /**
231
+ * Create a new event object with a new trace context.
232
+ *
233
+ * NOTE: The returned object must be "delete"d.
234
+ */
235
+ Event *Context::startTrace() {
236
+ oboe_metadata_t *md = Context::get();
237
+ oboe_metadata_random(md);
238
+ return new Event();
239
+ }
240
+
241
+ /////// Event ///////
242
+
243
+ Event::Event() {
244
+ oboe_event_init(this, Context::get(), NULL);
245
+ }
246
+
247
+ Event::Event(const oboe_metadata_t *md, bool addEdge) {
248
+ // both methods copy metadata from md -> this
249
+ if (addEdge) {
250
+ // create_event automatically adds edge in event to md
251
+ oboe_metadata_create_event(md, this);
252
+ } else {
253
+ // initializes new Event with this md's task_id & new random op_id; no edges set
254
+ oboe_event_init(this, md, NULL);
255
+ }
256
+ }
257
+
258
+ Event::~Event() {
259
+ oboe_event_destroy(this);
260
+ }
261
+
262
+ Event *Event::startTrace(const oboe_metadata_t *md) {
263
+ return new Event(md, false);
264
+ }
265
+
266
+ // called e.g. from Python e.addInfo("Key", None) & Ruby e.addInfo("Key", nil)
267
+ bool Event::addInfo(char *key, void *val) {
268
+ // oboe_event_add_info(evt, key, NULL) does nothing
269
+ (void)key;
270
+ (void)val;
271
+ return true;
272
+ }
273
+
274
+ bool Event::addInfo(char *key, const std::string &val) {
275
+ if (memchr(val.data(), '\0', val.size())) {
276
+ return oboe_event_add_info_binary(this, key, val.data(), val.size()) == 0;
277
+ } else {
278
+ return oboe_event_add_info(this, key, val.data()) == 0;
279
+ }
280
+ }
281
+
282
+ bool Event::addInfo(char *key, long val) {
283
+ int64_t val_ = val;
284
+ return oboe_event_add_info_int64(this, key, val_) == 0;
285
+ }
286
+
287
+ bool Event::addInfo(char *key, double val) {
288
+ return oboe_event_add_info_double(this, key, val) == 0;
289
+ }
290
+
291
+ bool Event::addInfo(char *key, bool val) {
292
+ return oboe_event_add_info_bool(this, key, val) == 0;
293
+ }
294
+
295
+ /*
296
+ * this function was added for profiling
297
+ * to report the timestamps of omitted snapshots
298
+ */
299
+ bool Event::addInfo(char *key, const long *vals, int num) {
300
+ oboe_bson_append_start_array(&(this->bbuf), key);
301
+ for (int i = 0; i < num; i++) {
302
+ // 5 is chosen so that indices upto 9999 can be stored
303
+ char index[5]; // Flawfinder: ignore
304
+ sprintf(index, "%d", i); // Flawfinder: ignore
305
+ oboe_bson_append_long(&(this->bbuf), index, (int64_t)vals[i]);
306
+ }
307
+ oboe_bson_append_finish_object(&(this->bbuf));
308
+ return true;
309
+ }
310
+
311
+ /*
312
+ * A profiling specific addInfo function
313
+ * to add the frames that make up a snapshot
314
+ */
315
+ bool Event::addInfo(char *key, const std::vector<FrameData> &vals) {
316
+ oboe_bson_append_start_array(&(this->bbuf), key);
317
+ int i = 0;
318
+ for (FrameData val : vals) {
319
+ // 5 is chosen so that indices upto 9999 can be stored
320
+ char index[5]; // Flawfinder: ignore
321
+ sprintf(index, "%d", i); // Flawfinder: ignore
322
+ i++;
323
+ oboe_bson_append_start_object(&(this->bbuf), index);
324
+
325
+ if (val.method != "")
326
+ oboe_bson_append_string(&(this->bbuf), "M", (val.method).c_str());
327
+ if (val.klass != "")
328
+ oboe_bson_append_string(&(this->bbuf), "C", (val.klass).c_str());
329
+ if (val.file != "")
330
+ oboe_bson_append_string(&(this->bbuf), "F", (val.file).c_str());
331
+ if (val.lineno > 0)
332
+ oboe_bson_append_long(&(this->bbuf), "L", (int64_t)val.lineno);
333
+
334
+ oboe_bson_append_finish_object(&(this->bbuf));
335
+ }
336
+ oboe_bson_append_finish_object(&(this->bbuf));
337
+ return true;
338
+ }
339
+
340
+ bool Event::addEdge(oboe_metadata_t *md) {
341
+ return oboe_event_add_edge(this, md) == 0;
342
+ }
343
+
344
+ bool Event::addEdgeStr(const std::string &val) {
345
+ return oboe_event_add_edge_fromstr(this, val.c_str(), val.size()) == 0;
346
+ }
347
+
348
+ bool Event::addHostname() {
349
+ static char oboe_hostname[HOST_NAME_MAX + 1] = {'\0'}; // Flawfinder: ignore
350
+
351
+ if (oboe_hostname[0] == '\0') {
352
+ (void)gethostname(oboe_hostname, sizeof(oboe_hostname) - 1);
353
+ if (oboe_hostname[0] == '\0') {
354
+ // Something is wrong but we don't want to to report this more than
355
+ // once so we'll set it to a minimal non-empty string.
356
+ OBOE_DEBUG_LOG_WARNING(OBOE_MODULE_LIBOBOE, "Failed to get hostname, setting it to '?'");
357
+ oboe_hostname[0] = '?';
358
+ oboe_hostname[1] = '\0';
359
+ }
360
+ }
361
+ return oboe_event_add_info(this, "Hostname", oboe_hostname) == 0;
362
+ }
363
+
364
+ bool Event::addContextOpId(const oboe_metadata_t *md) {
365
+ char buf[OBOE_MAX_METADATA_PACK_LEN]; // Flawfinder: ignore
366
+ oboe_metadata_tostr(md, buf, OBOE_MAX_METADATA_PACK_LEN);
367
+ buf[58] = '\0';
368
+
369
+ return oboe_event_add_info(this, "ContextOpId", &buf[42]);
370
+ }
371
+
372
+ bool Event::addSpanRef(const oboe_metadata_t *md) {
373
+ char buf[OBOE_MAX_METADATA_PACK_LEN]; // Flawfinder: ignore
374
+ oboe_metadata_tostr(md, buf, OBOE_MAX_METADATA_PACK_LEN);
375
+ buf[58] = '\0';
376
+
377
+ return oboe_event_add_info(this, "SpanRef", &buf[42]);
378
+ }
379
+
380
+ bool Event::addProfileEdge(std::string id) {
381
+ return oboe_event_add_info(this, "Edge", id.c_str());
382
+ }
383
+
384
+ /**
385
+ * Get a new copy of this metadata.
386
+ *
387
+ * NOTE: The returned object must be "delete"d.
388
+ */
389
+ Metadata *Event::getMetadata() {
390
+ return new Metadata(&this->metadata);
391
+ }
392
+
393
+ std::string Event::opIdString() {
394
+ char buf[OBOE_MAX_METADATA_PACK_LEN]; // Flawfinder: ignore
395
+ oboe_metadata_tostr(&this->metadata, buf, OBOE_MAX_METADATA_PACK_LEN);
396
+ buf[58] = '\0';
397
+ return std::string(&buf[42]);
398
+ }
399
+
400
+ std::string Event::metadataString() {
401
+ char buf[OBOE_MAX_METADATA_PACK_LEN]; // Flawfinder: ignore
402
+
403
+ int rc = oboe_metadata_tostr(&this->metadata, buf, sizeof(buf) - 1);
404
+ if (rc == 0) {
405
+ return std::string(buf);
406
+ } else {
407
+ return std::string(); // throw exception?
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Report this event.
413
+ *
414
+ * This sends the event using the default reporter.
415
+ *
416
+ * @return True on success; otherwise an error message is logged.
417
+ */
418
+ bool Event::send() {
419
+ return (oboe_event_send(OBOE_SEND_EVENT, this, Context::get()) >= 0);
420
+ }
421
+
422
+ /**
423
+ * Report a Profiling Event
424
+ * needs to be sent raw, so that the timestamp doesn't get altered
425
+ */
426
+ bool Event::sendProfiling() {
427
+ int retval = -1;
428
+
429
+ this->bb_str = oboe_bson_buffer_finish(&this->bbuf);
430
+ if (!this->bb_str)
431
+ return -1;
432
+
433
+ size_t len = (size_t)(this->bbuf.cur - this->bbuf.buf);
434
+ retval = oboe_raw_send(OBOE_SEND_PROFILING, this->bb_str, len);
435
+
436
+ if (retval < 0)
437
+ OBOE_DEBUG_LOG_ERROR(OBOE_MODULE_LIBOBOE, "Raw send failed - reporter returned %d", retval);
438
+
439
+ return (retval >= 0);
440
+ }
441
+
442
+ /////// Span ///////
443
+
444
+ std::string Span::createSpan(const char *transaction, const char *domain, const int64_t duration, const int has_error, const char *service_name) {
445
+ oboe_span_params_t params;
446
+ memset(&params, 0, sizeof(oboe_span_params_t));
447
+ params.version = 1;
448
+ params.transaction = transaction;
449
+ params.domain = domain;
450
+ params.duration = duration;
451
+ params.has_error = has_error;
452
+ params.service = service_name;
453
+
454
+ char buffer[OBOE_TRANSACTION_NAME_MAX_LENGTH + 1]; // Flawfinder: ignore
455
+ int len = oboe_span(buffer, sizeof(buffer), &params);
456
+ if (len > 0) {
457
+ return std::string(buffer);
458
+ } else {
459
+ return "";
460
+ }
461
+ }
462
+
463
+ std::string Span::createHttpSpan(const char *transaction, const char *url, const char *domain, const int64_t duration,
464
+ const int status, const char *method, const int has_error, const char *service_name) {
465
+ oboe_span_params_t params;
466
+ memset(&params, 0, sizeof(oboe_span_params_t));
467
+ params.version = 1;
468
+ params.transaction = transaction;
469
+ params.url = url;
470
+ params.domain = domain;
471
+ params.duration = duration;
472
+ params.status = status;
473
+ params.method = method;
474
+ params.has_error = has_error;
475
+ params.service = service_name;
476
+
477
+ char buffer[OBOE_TRANSACTION_NAME_MAX_LENGTH + 1]; // Flawfinder: ignore
478
+ int len = oboe_http_span(buffer, sizeof(buffer), &params);
479
+ if (len > 0) {
480
+ return std::string(buffer);
481
+ } else {
482
+ return "";
483
+ }
484
+ }
485
+
486
+ /////// MetricTags ///////
487
+
488
+ MetricTags::MetricTags(size_t count) {
489
+ tags = new oboe_metric_tag_t[count];
490
+ for (size_t i = 0; i < count; i++) {
491
+ tags[i].key = nullptr;
492
+ tags[i].value = nullptr;
493
+ }
494
+ size = count;
495
+ }
496
+
497
+ MetricTags::~MetricTags() {
498
+ for (size_t i = 0; i < size; i++) {
499
+ delete tags[i].key; tags[i].key = nullptr;
500
+ delete tags[i].value; tags[i].value = nullptr;
501
+ }
502
+ delete[] tags;
503
+ }
504
+
505
+ bool MetricTags::add(size_t index, const char *k, const char *v) {
506
+ if (index < size) {
507
+ tags[index].key = strdup(k);
508
+ tags[index].value = strdup(v);
509
+ return (tags[index].key != nullptr && tags[index].value != nullptr);
510
+ }
511
+ return false;
512
+ }
513
+ oboe_metric_tag_t *MetricTags::get() const {
514
+ return tags;
515
+ }
516
+
517
+ /////// CustomMetrics ///////
518
+
519
+ int CustomMetrics::summary(const char *name, const double value, const int count, const int host_tag,
520
+ const char *service_name, const MetricTags *tags, size_t tags_count) {
521
+ if (tags->size < tags_count) {
522
+ tags_count = tags->size;
523
+ }
524
+ return oboe_custom_metric_summary(name, value, count, host_tag, service_name, tags->get(), tags_count);
525
+ }
526
+
527
+ int CustomMetrics::increment(const char *name, const int count, const int host_tag,
528
+ const char *service_name, const MetricTags *tags, size_t tags_count) {
529
+ if (tags->size < tags_count) {
530
+ tags_count = tags->size;
531
+ }
532
+ return oboe_custom_metric_increment(name, count, host_tag, service_name, tags->get(), tags_count);
533
+ }
534
+
535
+ /////// Profiling ///////
536
+
537
+ // adding this to have a proper interface, even though it just
538
+ // returns the return value of the oboe function
539
+ // 0 indicates not to profile, returns -1 if the collector hasn't sent anything
540
+ int OboeProfiling::get_interval() {
541
+ return oboe_get_profiling_interval();
542
+ }
543
+
544
+ /////// Reporter ///////
545
+
546
+ Reporter::Reporter(
547
+ std::string hostname_alias, // optional hostname alias
548
+ int log_level, // level at which log messages will be written to log file (0-6)
549
+ std::string log_file_path, // file name including path for log file
550
+
551
+ int max_transactions, // maximum number of transaction names to track
552
+ int max_flush_wait_time, // maximum wait time for flushing data before terminating in milli seconds
553
+ int events_flush_interval, // events flush timeout in seconds (threshold for batching messages before sending off)
554
+ int max_request_size_bytes, // events flush batch size in KB (threshold for batching messages before sending off)
555
+
556
+ std::string reporter, // the reporter to be used ("ssl", "upd", "file", "null")
557
+ std::string host, // collector endpoint (reporter=ssl), udp address (reporter=udp), or file path (reporter=file)
558
+ std::string service_key, // the service key (also known as access_key)
559
+ std::string trusted_path, // path to the SSL certificate (only for ssl)
560
+
561
+ int buffer_size, // size of the message buffer
562
+ int trace_metrics, // flag indicating if trace metrics reporting should be enabled (default) or disabled
563
+ int histogram_precision, // the histogram precision (only for ssl)
564
+ double token_bucket_capacity, // custom token bucket capacity
565
+ double token_bucket_rate, // custom token bucket rate
566
+ int file_single, // use single files in file reporter for each event
567
+
568
+ int ec2_metadata_timeout, // the timeout (milli seconds) for retrieving EC2 metadata
569
+ std::string grpc_proxy, // HTTP proxy address and port to be used for the gRPC connection
570
+ int stdout_clear_nonblocking, // flag indicating if the O_NONBLOCK flag on stdout should be cleared,
571
+ // only used in lambda reporter (off=0, on=1, default off)
572
+ int is_grpc_clean_hack_enabled // flag indicating if custom grpc clean hack enabled (default 0)
573
+ ) {
574
+ oboe_init_options_t options;
575
+ memset(&options, 0, sizeof(options));
576
+ options.version = 12;
577
+ oboe_init_options_set_defaults(&options);
578
+
579
+ if (hostname_alias != "") {
580
+ options.hostname_alias = hostname_alias.c_str();
581
+ }
582
+ options.log_level = log_level;
583
+ options.log_file_path = log_file_path.c_str();
584
+ options.max_transactions = max_transactions;
585
+ options.max_flush_wait_time = max_flush_wait_time;
586
+ options.events_flush_interval = events_flush_interval;
587
+ options.max_request_size_bytes = max_request_size_bytes;
588
+ if (reporter != "") {
589
+ options.reporter = reporter.c_str();
590
+ }
591
+ if (host != "") {
592
+ options.host = host.c_str();
593
+ }
594
+ if (service_key != "") {
595
+ options.service_key = service_key.c_str();
596
+ }
597
+ if (trusted_path != "") {
598
+ options.trusted_path = trusted_path.c_str();
599
+ }
600
+ options.buffer_size = buffer_size;
601
+ options.trace_metrics = trace_metrics;
602
+ options.histogram_precision = histogram_precision;
603
+ options.token_bucket_capacity = token_bucket_capacity;
604
+ options.token_bucket_rate = token_bucket_rate;
605
+ options.file_single = file_single;
606
+ options.ec2_metadata_timeout = ec2_metadata_timeout;
607
+ if (grpc_proxy != "") {
608
+ options.proxy = grpc_proxy.c_str();
609
+ }
610
+ options.stdout_clear_nonblocking = stdout_clear_nonblocking;
611
+ options.is_grpc_clean_hack_enabled = is_grpc_clean_hack_enabled;
612
+ init_status = oboe_init(&options);
613
+ }
614
+
615
+ Reporter::~Reporter() {
616
+ oboe_reporter_destroy(this);
617
+ }
618
+
619
+ bool Reporter::sendReport(Event *evt) {
620
+ return oboe_event_send(OBOE_SEND_EVENT, evt, Context::get()) >= 0;
621
+ }
622
+
623
+ bool Reporter::sendReport(Event *evt, oboe_metadata_t *md) {
624
+ return oboe_event_send(OBOE_SEND_EVENT, evt, md) >= 0;
625
+ }
626
+
627
+ bool Reporter::sendStatus(Event *evt) {
628
+ return oboe_event_send(OBOE_SEND_STATUS, evt, Context::get()) >= 0;
629
+ }
630
+
631
+ bool Reporter::sendStatus(Event *evt, oboe_metadata_t *md) {
632
+ return oboe_event_send(OBOE_SEND_STATUS, evt, md) >= 0;
633
+ }
634
+
635
+ void Reporter::flush() {
636
+ oboe_reporter_flush();
637
+ }
638
+
639
+ std::string Reporter::getType() {
640
+ const char* type = oboe_get_reporter_type();
641
+ return type ? std::string(type) : "";
642
+ }
643
+
644
+ /////// Config ///////
645
+
646
+ bool Config::checkVersion(int version, int revision) {
647
+ return (oboe_config_check_version(version, revision) != 0);
648
+ }
649
+
650
+ std::string Config::getVersionString() {
651
+ return oboe_config_get_version_string();
652
+ }