solarwinds_apm 5.1.9 → 6.0.0.preV2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +28 -55
  3. data/ext/oboe_metal/extconf.rb +37 -41
  4. data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +1 -1
  5. data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +1 -1
  6. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +1 -1
  7. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +1 -1
  8. data/ext/oboe_metal/src/VERSION +1 -1
  9. data/ext/oboe_metal/src/init_solarwinds_apm.cc +0 -6
  10. data/ext/oboe_metal/src/oboe_debug.h +1 -0
  11. data/lib/oboe_metal.rb +116 -80
  12. data/lib/rails/generators/solarwinds_apm/install_generator.rb +1 -5
  13. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +42 -267
  14. data/lib/solarwinds_apm/api/current_trace_info.rb +148 -0
  15. data/lib/solarwinds_apm/api/tracing.rb +30 -0
  16. data/lib/solarwinds_apm/api/transaction_name.rb +58 -0
  17. data/lib/solarwinds_apm/api.rb +8 -15
  18. data/lib/solarwinds_apm/base.rb +4 -131
  19. data/lib/solarwinds_apm/config.rb +101 -174
  20. data/lib/solarwinds_apm/constants.rb +32 -0
  21. data/lib/solarwinds_apm/logger.rb +1 -1
  22. data/lib/solarwinds_apm/noop/context.rb +2 -5
  23. data/lib/solarwinds_apm/noop/metadata.rb +1 -2
  24. data/lib/solarwinds_apm/oboe_init_options.rb +74 -38
  25. data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +204 -0
  26. data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +166 -0
  27. data/lib/solarwinds_apm/opentelemetry/solarwinds_propagator.rb +92 -0
  28. data/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +72 -0
  29. data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +335 -0
  30. data/lib/solarwinds_apm/opentelemetry.rb +8 -0
  31. data/lib/solarwinds_apm/otel_config.rb +161 -0
  32. data/lib/solarwinds_apm/{inst → support}/logger_formatter.rb +5 -6
  33. data/lib/solarwinds_apm/{inst → support}/logging_log_event.rb +3 -6
  34. data/lib/solarwinds_apm/{inst → support}/lumberjack_formatter.rb +1 -4
  35. data/lib/solarwinds_apm/support/oboe_tracing_mode.rb +27 -0
  36. data/lib/solarwinds_apm/support/swomarginalia/LICENSE +20 -0
  37. data/lib/solarwinds_apm/support/swomarginalia/README.md +41 -0
  38. data/lib/solarwinds_apm/support/swomarginalia/comment.rb +205 -0
  39. data/lib/solarwinds_apm/support/swomarginalia/load_swomarginalia.rb +48 -0
  40. data/lib/solarwinds_apm/support/swomarginalia/railtie.rb +22 -0
  41. data/lib/solarwinds_apm/support/swomarginalia/swomarginalia.rb +86 -0
  42. data/lib/solarwinds_apm/support/transaction_cache.rb +24 -0
  43. data/lib/solarwinds_apm/support/transaction_settings.rb +26 -209
  44. data/lib/solarwinds_apm/support/transformer.rb +56 -0
  45. data/lib/solarwinds_apm/support/txn_name_manager.rb +25 -0
  46. data/lib/solarwinds_apm/support/x_trace_options.rb +42 -26
  47. data/lib/solarwinds_apm/support.rb +37 -10
  48. data/lib/solarwinds_apm/support_report.rb +10 -32
  49. data/lib/solarwinds_apm/thread_local.rb +1 -1
  50. data/lib/solarwinds_apm/version.rb +4 -4
  51. data/lib/solarwinds_apm.rb +29 -25
  52. metadata +63 -123
  53. data/.dockerignore +0 -5
  54. data/.gitignore +0 -58
  55. data/.rubocop.yml +0 -29
  56. data/.whitesource +0 -22
  57. data/.yardopts +0 -7
  58. data/CHANGELOG-appoptics.md +0 -766
  59. data/CHANGELOG.md +0 -82
  60. data/CONFIG.md +0 -31
  61. data/Gemfile +0 -15
  62. data/README.md +0 -385
  63. data/bin/solarwinds_apm_config +0 -15
  64. data/examples/prepend.rb +0 -13
  65. data/examples/sdk_examples.rb +0 -158
  66. data/ext/oboe_metal/README.md +0 -69
  67. data/ext/oboe_metal/extconf_local.rb +0 -75
  68. data/ext/oboe_metal/lib/.keep +0 -0
  69. data/ext/oboe_metal/noop/noop.c +0 -8
  70. data/ext/oboe_metal/src/README.md +0 -6
  71. data/ext/oboe_metal/src/frames.cc +0 -247
  72. data/ext/oboe_metal/src/frames.h +0 -40
  73. data/ext/oboe_metal/src/logging.cc +0 -97
  74. data/ext/oboe_metal/src/logging.h +0 -34
  75. data/ext/oboe_metal/src/profiling.cc +0 -435
  76. data/ext/oboe_metal/src/profiling.h +0 -78
  77. data/ext/oboe_metal/test/CMakeLists.txt +0 -53
  78. data/ext/oboe_metal/test/FindGMock.cmake +0 -43
  79. data/ext/oboe_metal/test/README.md +0 -56
  80. data/ext/oboe_metal/test/frames_test.cc +0 -164
  81. data/ext/oboe_metal/test/profiling_test.cc +0 -93
  82. data/ext/oboe_metal/test/ruby_inc_dir.rb +0 -8
  83. data/ext/oboe_metal/test/ruby_prefix.rb +0 -8
  84. data/ext/oboe_metal/test/ruby_test_helper.rb +0 -67
  85. data/ext/oboe_metal/test/test.h +0 -11
  86. data/ext/oboe_metal/test/test_main.cc +0 -32
  87. data/init.rb +0 -4
  88. data/lib/solarwinds_apm/api/layerinit.rb +0 -41
  89. data/lib/solarwinds_apm/api/logging.rb +0 -356
  90. data/lib/solarwinds_apm/api/memcache.rb +0 -37
  91. data/lib/solarwinds_apm/api/metrics.rb +0 -63
  92. data/lib/solarwinds_apm/api/util.rb +0 -98
  93. data/lib/solarwinds_apm/frameworks/grape.rb +0 -96
  94. data/lib/solarwinds_apm/frameworks/padrino.rb +0 -78
  95. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +0 -100
  96. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +0 -50
  97. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +0 -50
  98. data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +0 -88
  99. data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +0 -26
  100. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +0 -29
  101. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +0 -22
  102. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +0 -103
  103. data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +0 -14
  104. data/lib/solarwinds_apm/frameworks/rails.rb +0 -100
  105. data/lib/solarwinds_apm/frameworks/sinatra.rb +0 -96
  106. data/lib/solarwinds_apm/inst/bunny-client.rb +0 -157
  107. data/lib/solarwinds_apm/inst/bunny-consumer.rb +0 -102
  108. data/lib/solarwinds_apm/inst/curb.rb +0 -289
  109. data/lib/solarwinds_apm/inst/dalli.rb +0 -89
  110. data/lib/solarwinds_apm/inst/delayed_job.rb +0 -100
  111. data/lib/solarwinds_apm/inst/excon.rb +0 -113
  112. data/lib/solarwinds_apm/inst/faraday.rb +0 -96
  113. data/lib/solarwinds_apm/inst/graphql.rb +0 -206
  114. data/lib/solarwinds_apm/inst/grpc_client.rb +0 -147
  115. data/lib/solarwinds_apm/inst/grpc_server.rb +0 -119
  116. data/lib/solarwinds_apm/inst/httpclient.rb +0 -182
  117. data/lib/solarwinds_apm/inst/memcached.rb +0 -86
  118. data/lib/solarwinds_apm/inst/mongo.rb +0 -246
  119. data/lib/solarwinds_apm/inst/mongo2.rb +0 -225
  120. data/lib/solarwinds_apm/inst/moped.rb +0 -466
  121. data/lib/solarwinds_apm/inst/net_http.rb +0 -60
  122. data/lib/solarwinds_apm/inst/rack.rb +0 -223
  123. data/lib/solarwinds_apm/inst/rack_cache.rb +0 -35
  124. data/lib/solarwinds_apm/inst/redis.rb +0 -280
  125. data/lib/solarwinds_apm/inst/redis_v4.rb +0 -273
  126. data/lib/solarwinds_apm/inst/resque.rb +0 -129
  127. data/lib/solarwinds_apm/inst/rest-client.rb +0 -43
  128. data/lib/solarwinds_apm/inst/sequel.rb +0 -241
  129. data/lib/solarwinds_apm/inst/sidekiq-client.rb +0 -63
  130. data/lib/solarwinds_apm/inst/sidekiq-worker.rb +0 -64
  131. data/lib/solarwinds_apm/inst/typhoeus.rb +0 -90
  132. data/lib/solarwinds_apm/instrumentation.rb +0 -22
  133. data/lib/solarwinds_apm/loading.rb +0 -65
  134. data/lib/solarwinds_apm/noop/profiling.rb +0 -21
  135. data/lib/solarwinds_apm/ruby.rb +0 -35
  136. data/lib/solarwinds_apm/sdk/current_trace_info.rb +0 -123
  137. data/lib/solarwinds_apm/sdk/custom_metrics.rb +0 -94
  138. data/lib/solarwinds_apm/sdk/logging.rb +0 -37
  139. data/lib/solarwinds_apm/sdk/trace_context_headers.rb +0 -69
  140. data/lib/solarwinds_apm/sdk/tracing.rb +0 -432
  141. data/lib/solarwinds_apm/support/profiling.rb +0 -25
  142. data/lib/solarwinds_apm/support/trace_context.rb +0 -53
  143. data/lib/solarwinds_apm/support/trace_state.rb +0 -69
  144. data/lib/solarwinds_apm/support/trace_string.rb +0 -89
  145. data/lib/solarwinds_apm/support/transaction_metrics.rb +0 -67
  146. data/lib/solarwinds_apm/test.rb +0 -165
  147. data/lib/solarwinds_apm/util.rb +0 -426
  148. data/log/.keep +0 -0
  149. data/log/postgresql/.keep +0 -0
  150. data/solarwinds_apm.gemspec +0 -55
  151. data/yardoc_frontpage.md +0 -24
@@ -1,158 +0,0 @@
1
- # Copyright (c) 2020 SolarWinds, LLC.
2
- # All rights reserved.
3
-
4
- ###############################################################
5
- # SDK EXAMPLES
6
- ###############################################################
7
- # The uses cases of the SDK include:
8
- # - tracing a piece of your own code
9
- # - tracing a method call of a gem that is not auto-instrumented
10
- # by solarwinds_apm
11
- #
12
- # SDK documentation:
13
- # https://rubydoc.info/gems/solarwinds_apm/SolarWindsAPM/SDK
14
-
15
- ###############################################################
16
- # Prerequisits
17
- # export SW_APM_SERVICE_KEY=<API token>:<service_name>
18
- # `bundle exec ruby sdk_examples.rb`
19
- # 5 traced requests will show up in the backend
20
- ###############################################################
21
-
22
- require 'solarwinds_apm'
23
-
24
- unless SolarWindsAPM::SDK.solarwinds_ready?(10_000)
25
- puts "aborting!!! Agent not ready after 10 seconds"
26
- exit false
27
- end
28
-
29
- ###############################################################
30
- ### ADD A SPAN
31
- ###############################################################
32
- #
33
- # SolarWindsAPM::SDK.trace()
34
- # This method adds a span to a trace that has been started either
35
- # by the auto-instrumentation of the gem handling incoming requests
36
- # or the SDK method `start_trace`.
37
- # If this method is called outside of the context of a started
38
- # trace no spans will be created.
39
- #
40
- # The argument is the name for the span
41
-
42
- SolarWindsAPM::SDK.trace('span_name') do
43
- [9, 6, 12, 2, 7, 1, 9, 3, 4, 14, 5, 8].sort
44
- end
45
-
46
- ###############################################################
47
- # START A TRACE, ADD A SPAN, AND LOG AN INFO EVENT
48
- ###############################################################
49
- #
50
- # SolarWindsAPM::SDK.start_trace()
51
- # This method starts a trace. It is handy for background jobs,
52
- # workers, or scripts, that are not part of a rack application
53
-
54
- SolarWindsAPM::SDK.start_trace('outer_span') do
55
- SolarWindsAPM::SDK.trace('first_child_span') do
56
- [9, 6, 12, 2, 7, 1, 9, 3, 4, 14, 5, 8].sort
57
- SolarWindsAPM::SDK.log_info({ some: :fancy, hash: :to, send: 1 })
58
- end
59
- end
60
-
61
- ###############################################################
62
- # LOG AN ERROR EVENT
63
- ###############################################################
64
- #
65
- # SolarWindsAPM::SDK.log_exception()
66
- # This method adds an error event to the trace, which will be
67
- # displayed and counted as exception on the solarwinds_apm dashboard.
68
-
69
- def do_raise
70
- raise StandardError.new("oops")
71
- end
72
-
73
- SolarWindsAPM::SDK.start_trace('with_error') do
74
- begin
75
- do_raise
76
- rescue => e
77
- SolarWindsAPM::SDK.log_exception(e)
78
- end
79
- end
80
-
81
- ###############################################################
82
- # TRACE A METHOD
83
- ###############################################################
84
- #
85
- # SolarWindsAPM::SDK.trace_method()
86
- # This creates a span every time the defined method is run.
87
- # The method can be of any (accessible) type (instance,
88
- # singleton, private, protected etc.).
89
-
90
- module ExampleModule
91
- def self.do_sum(a, b)
92
- a + b
93
- end
94
- end
95
-
96
- SolarWindsAPM::SDK.trace_method(ExampleModule,
97
- :do_sum,
98
- config: { name: 'computation', backtrace: true },
99
- kvs: { CustomKey: "some_info" })
100
-
101
- SolarWindsAPM::SDK.start_trace('trace_a_method') do
102
- ExampleModule.do_sum(1, 2)
103
- ExampleModule.do_sum(3, 4)
104
- end
105
-
106
- ###############################################################
107
- # SET A CUSTOM TRANSACTION NAME
108
- ###############################################################
109
- #
110
- # SolarWindsAPM::SDK.set_transaction_name()
111
- #
112
- # this method can be called anytime after a trace has been started to add a
113
- # custom name for the whole transaction.
114
- # In case of a controller the trace is usually started in rack.
115
-
116
- class FakeController
117
- def create(params)
118
- # @fake = fake.new(params.permit(:type, :title))
119
- # @fake.save
120
- SolarWindsAPM::SDK.set_transaction_name("fake.#{params[:type]}")
121
- # redirect_to @fake
122
- end
123
- end
124
-
125
- SolarWindsAPM::SDK.start_trace('set_transaction_name') do
126
- FakeController.new.create(type: 'news')
127
- end
128
-
129
- ###############################################################
130
- # LOG INJECTION OF TRACE_ID
131
- ###############################################################
132
- #
133
- # SolarWindsAPM::SDK.current_trace_info
134
- # This method creates an object with the current trace ID and
135
- # helper methods to add the ID to logs for cross-referencing.
136
-
137
- SolarWindsAPM::Config[:log_traceId] = :always
138
-
139
- SolarWindsAPM::SDK.start_trace('log_trace_id') do
140
- trace = SolarWindsAPM::SDK.current_trace_info
141
- SolarWindsAPM.logger.warn "Some log message #{trace.for_log}"
142
- end
143
-
144
- ###############################################################
145
- # START A TRACE AND PROFILE
146
- ###############################################################
147
- #
148
- # SolarWindsAPM::Profiling.run
149
- # This method adds profiling for the code executed in the block
150
-
151
- SolarWindsAPM::SDK.start_trace("#{name}_profiling") do
152
- SolarWindsAPM::Profiling.run do
153
- 10.times do
154
- [9, 6, 12, 2, 7, 1, 9, 3, 4, 14, 5, 8].sort
155
- sleep 0.2
156
- end
157
- end
158
- end
@@ -1,69 +0,0 @@
1
- # Debug the c-code with gdb
2
-
3
- inspired by: https://dev.to/wataash/how-to-create-and-debug-ruby-gem-with-c-native-extension-3l8b
4
-
5
-
6
- ## install ruby with sources
7
-
8
- rbenv is your friend ;) -k means keep sources
9
-
10
- ```
11
- rbenv install -k 2.7.5
12
- rbenv shell 2.7.5
13
-
14
- # check that ruby is debuggable
15
- type ruby # => ruby is /home/wsh/.rbenv/shims/ruby
16
- rbenv which ruby # => /home/wsh/.rbenv/versions/2.6.3/bin/ruby
17
- ```
18
-
19
-
20
- ##
21
- ## add debug info when compiling solarwinds_apm
22
- add this line to extconf.rb to turn off optimization
23
-
24
- ```
25
- CONFIG["optflags"] = "-O0"
26
- ```
27
-
28
-
29
- ##
30
- ## start ruby app with gdb
31
-
32
- This will run ruby and load the app with a breakpoint in the Reporter::startThread
33
- c-function.
34
-
35
- `bundle exec gdb -q -ex 'set breakpoint pending on' -ex 'b Reporter::startThread' -ex run --args ruby -e 'require "./app"'`
36
-
37
- If there is a bug in the ruby code or a ruby byebug binding that halts the
38
- script, the debugger will hang without showing any output.
39
- So, make sure `bundle exec ruby app.rb` runs.
40
-
41
- use the gdb navigation commands to step through the code. If it says:
42
-
43
- ```
44
- (gdb) n
45
- Single stepping until exit from function _ZN8Reporter11startThreadEv@plt,
46
- which has no line number information.
47
- ```
48
-
49
- type `c` and it may end up stopping in the right location.
50
-
51
- ##
52
- ## make ruby .gdbinit macros available
53
-
54
- These macros are pretty elaborate. They are checked in the ruby github
55
- repo: https://github.com/ruby/ruby/blob/master/.gdbinit
56
- The code is nicely formatted and colorized in github and easiest to read there.
57
-
58
- installation in the user's home dir:
59
- ```
60
- wget https://github.com/ruby/ruby/blob/master/.gdbinit
61
- ```
62
- ##
63
- ## examples
64
-
65
- Some inspiring examples here:
66
-
67
- https://jvns.ca/blog/2016/06/12/a-weird-system-call-process-vm-readv/
68
-
69
- https://medium.com/@zanker/finding-a-ruby-bug-with-gdb-56d6b321bc86
@@ -1,75 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2016 SolarWinds, LLC.
4
- # All rights reserved.
5
-
6
- require 'mkmf'
7
- require 'rbconfig'
8
- require 'open-uri'
9
- require 'no_proxy_fix'
10
-
11
- CONFIG['warnflags'] = CONFIG['warnflags'].gsub(/-Wdeclaration-after-statement/, '')
12
- .gsub(/-Wimplicit-function-declaration/, '')
13
- .gsub(/-Wimplicit-int/, '')
14
- .gsub(/-Wno-tautological-compare/, '')
15
- .gsub(/-Wno-self-assign/, '')
16
- .gsub(/-Wno-parentheses-equality/, '')
17
- .gsub(/-Wno-constant-logical-operand/, '')
18
- .gsub(/-Wno-cast-function-type/, '')
19
- init_mkmf(CONFIG)
20
-
21
- ext_dir = File.expand_path(File.dirname(__FILE__))
22
-
23
- # Set the mkmf lib paths so we have no issues linking to
24
- # the SolarWindsAPM libs.
25
- ao_lib_dir = File.join(ext_dir, 'lib')
26
- ao_path = '../../../oboe/factory-output'
27
- ao_clib = "liboboe-1.0-x86_64.so"
28
- ao_item = File.join(ao_path, ao_clib)
29
- clib = File.join(ao_lib_dir, ao_clib)
30
-
31
- FileUtils.cp(ao_item, clib)
32
-
33
- # Create relative symlinks for the SolarWindsAPM library
34
- Dir.chdir(ao_lib_dir) do
35
- File.symlink(ao_clib, 'liboboe.so')
36
- File.symlink(ao_clib, 'liboboe-1.0.so.0')
37
- end
38
-
39
- dir_config('oboe', 'src', 'lib')
40
-
41
- if have_library('oboe', 'oboe_config_get_revision', 'oboe.h')
42
- $libs = append_library($libs, 'oboe')
43
- $libs = append_library($libs, 'stdc++')
44
-
45
- $CFLAGS << " #{ENV['CFLAGS']}"
46
- # $CPPFLAGS << " #{ENV['CPPFLAGS']} -std=c++11"
47
- # TODO for debugging: -pg -gdwarf-2, remove for production
48
- # -pg does not work on alpine https://www.openwall.com/lists/musl/2014/11/05/2
49
- $CPPFLAGS << " #{ENV['CPPFLAGS']} -std=c++11 -gdwarf-2 -I$$ORIGIN/../ext/oboe_metal/include -I$$ORIGIN/../ext/oboe_metal/src"
50
- # $CPPFLAGS << " #{ENV['CPPFLAGS']} -std=c++11 -I$$ORIGIN/../ext/oboe_metal/include"
51
- $LIBS << " #{ENV['LIBS']}"
52
-
53
- # use "z,defs" to see what happens during linking
54
- # $LDFLAGS << " #{ENV['LDFLAGS']} '-Wl,-rpath=$$ORIGIN/../ext/oboe_metal/lib,-z,defs' -lrt"
55
- $LDFLAGS << " #{ENV['LDFLAGS']} '-Wl,-rpath=$$ORIGIN/../ext/oboe_metal/lib' -lrt"
56
- $CXXFLAGS += " -std=c++11 "
57
-
58
- # ____ include debug info, comment out when not debugging
59
- # ____ -pg -> profiling info for gprof
60
- CONFIG["debugflags"] = "-ggdb3 "
61
- CONFIG["optflags"] = "-O0"
62
-
63
- create_makefile('libsolarwinds_apm', 'src')
64
- else
65
- $stderr.puts '== ERROR ========================================================='
66
- if have_library('oboe')
67
- $stderr.puts "The c-library either needs to be updated or doesn't match the OS."
68
- $stderr.puts 'No tracing will occur.'
69
- else
70
- $stderr.puts 'Could not find a matching c-library. No tracing will occur.'
71
- end
72
- $stderr.puts 'Contact technicalsupport@solarwinds.com if the problem persists.'
73
- $stderr.puts '=================================================================='
74
- create_makefile('oboe_noop', 'noop')
75
- end
File without changes
@@ -1,8 +0,0 @@
1
- #include <ruby.h>
2
-
3
- /* ruby calls this to load the extension */
4
- void Init_oboe_noop(void) {
5
- /* assume we haven't yet defined Hola */
6
- // VALUE klass = rb_define_class("OboeNoop", rb_cObject);
7
- rb_define_class("OboeNoop", rb_cObject);
8
- }
@@ -1,6 +0,0 @@
1
-
2
- oboe_api.h and oboe_api.cpp are copied here from the oboe repo during install
3
-
4
- it is best to edit these file in the oboe codebase and use the OBOE_WIP=true env
5
- var to include the local development version while the changes aren't deployed to s3.
6
-
@@ -1,247 +0,0 @@
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
- }
@@ -1,40 +0,0 @@
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.h"
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