solarwinds_apm 5.1.9 → 6.0.0.preV1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +0 -1
  3. data/ext/oboe_metal/extconf.rb +19 -23
  4. data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +1 -1
  5. data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +1 -1
  6. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +1 -1
  7. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +1 -1
  8. data/ext/oboe_metal/src/VERSION +1 -1
  9. data/ext/oboe_metal/src/oboe_debug.h +1 -0
  10. data/lib/oboe_metal.rb +116 -80
  11. data/lib/rails/generators/solarwinds_apm/install_generator.rb +1 -2
  12. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +44 -260
  13. data/lib/solarwinds_apm/api/current_trace_info.rb +148 -0
  14. data/lib/solarwinds_apm/api/tracing.rb +30 -0
  15. data/lib/solarwinds_apm/api/transaction_name.rb +57 -0
  16. data/lib/solarwinds_apm/api.rb +8 -15
  17. data/lib/solarwinds_apm/base.rb +4 -131
  18. data/lib/solarwinds_apm/config.rb +128 -175
  19. data/lib/solarwinds_apm/constants.rb +32 -0
  20. data/lib/solarwinds_apm/logger.rb +1 -1
  21. data/lib/solarwinds_apm/noop/context.rb +2 -5
  22. data/lib/solarwinds_apm/noop/metadata.rb +1 -2
  23. data/lib/solarwinds_apm/noop/profiling.rb +3 -7
  24. data/lib/solarwinds_apm/oboe_init_options.rb +71 -33
  25. data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +204 -0
  26. data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +163 -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 +330 -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 +33 -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 +31 -26
  52. metadata +76 -121
  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/ruby.rb +0 -35
  135. data/lib/solarwinds_apm/sdk/current_trace_info.rb +0 -123
  136. data/lib/solarwinds_apm/sdk/custom_metrics.rb +0 -94
  137. data/lib/solarwinds_apm/sdk/logging.rb +0 -37
  138. data/lib/solarwinds_apm/sdk/trace_context_headers.rb +0 -69
  139. data/lib/solarwinds_apm/sdk/tracing.rb +0 -432
  140. data/lib/solarwinds_apm/support/profiling.rb +0 -25
  141. data/lib/solarwinds_apm/support/trace_context.rb +0 -53
  142. data/lib/solarwinds_apm/support/trace_state.rb +0 -69
  143. data/lib/solarwinds_apm/support/trace_string.rb +0 -89
  144. data/lib/solarwinds_apm/support/transaction_metrics.rb +0 -67
  145. data/lib/solarwinds_apm/test.rb +0 -165
  146. data/lib/solarwinds_apm/util.rb +0 -426
  147. data/log/.keep +0 -0
  148. data/log/postgresql/.keep +0 -0
  149. data/solarwinds_apm.gemspec +0 -55
  150. data/yardoc_frontpage.md +0 -24
@@ -1,432 +0,0 @@
1
- #--
2
- # Copyright (c) 2016 SolarWinds, LLC.
3
- # All rights reserved.
4
- #++
5
-
6
- module SolarWindsAPM
7
- module SDK
8
-
9
- ##
10
- # Traces are best created with an <tt>SolarWindsAPM::SDK.start_trace</tt> block and
11
- # <tt>SolarWindsAPM::SDK.trace</tt> blocks around calls to be traced.
12
- # These two methods guarantee proper nesting of traces, handling of the tracing context, as well as avoiding
13
- # broken traces in case of exceptions.
14
- #
15
- # Some optional keys that can be used in the +kvs+ hash:
16
- # * +:Controller+
17
- # * +:Action+
18
- # * +:HTTP-Host+
19
- # * +:URL+
20
- # * +:Method+
21
- #
22
- # as well as custom keys. The information will show up in the raw data view of a span.
23
- #
24
- # Invalid keys: +:Label+, +:Layer+, +:Edge+, +:Timestamp+, +:Timestamp_u+, +:TransactionName+ (allowed in start_trace)
25
- #
26
- # The methods are exposed as singleton methods for SolarWindsAPM::SDK.
27
- #
28
- # === Usage:
29
- # * +SolarWindsAPM::SDK.solarwinds_ready?+
30
- # * +SolarWindsAPM::SDK.get_transaction_name+
31
- # * +SolarWindsAPM::SDK.set_transaction_name+
32
- # * +SolarWindsAPM::SDK.start_trace+
33
- # * +SolarWindsAPM::SDK.start_trace_with_target+
34
- # * +SolarWindsAPM::SDK.trace+
35
- # * +SolarWindsAPM::SDK.trace_method+
36
- # * +SolarWindsAPM::SDK.tracing?+
37
- #
38
- # === Example:
39
- # class MonthlyCouponEmailJob
40
- # def perform(*args)
41
- #
42
- # # KVs to report to the dashboard
43
- # report_kvs = {}
44
- # report_kvs[:Spec] = :job
45
- # report_kvs[:Controller] = :MonthlyEmailJob
46
- # report_kvs[:Action] = :CouponEmailer
47
- #
48
- # # Start tracing this job with start_trace
49
- # SolarWindsAPM::SDK.start_trace('monthly_coupons', kvs: report_kvs) do
50
- # monthly = MonthlyEmail.new(:CouponEmailer)
51
- #
52
- # # Trace a sub-component of this trace
53
- # SolarWindsAPM::SDK.trace(self.class.name) do
54
- #
55
- # # The work to be done
56
- # users = User.all
57
- # users.each do |u|
58
- # monthly.send(u.email)
59
- # end
60
- #
61
- # end
62
- # end
63
- # end
64
- # end
65
- #
66
- module Tracing
67
-
68
- # Trace a given block of code.
69
- #
70
- # Also detects any exceptions thrown by the block and report errors.
71
- #
72
- # === Arguments:
73
- # * +name+ - Name for the span to be used as label in the trace view.
74
- # * +kvs:+ - (optional) A hash containing key/value pairs that will be reported along with the first event of this span.
75
- # * +protect_op:+ - (optional) The operation being traced. Used to avoid double tracing operations that call each other.
76
- #
77
- # === Example:
78
- #
79
- # def computation_with_sw_apm(n)
80
- # SolarWindsAPM::SDK.trace('computation', kvs: { :number => n }, protect_op: :computation) do
81
- # return n if n == 0
82
- # n + computation_with_sw_apm(n-1)
83
- # end
84
- # end
85
- #
86
- # result = computation_with_sw_apm(100)
87
- #
88
- # === Returns:
89
- # * The result of the block.
90
- #
91
- def trace(name, kvs: {}, protect_op: nil)
92
- return yield if !SolarWindsAPM.loaded || !SolarWindsAPM.tracing? || SolarWindsAPM.tracing_layer_op?(protect_op)
93
-
94
- kvs.delete(:TransactionName)
95
- kvs.delete('TransactionName')
96
-
97
- SolarWindsAPM::API.log_entry(name, kvs, protect_op)
98
- kvs[:Backtrace] && kvs.delete(:Backtrace) # to avoid sending backtrace twice (faster to check presence here)
99
- begin
100
- yield
101
- rescue Exception => e
102
- SolarWindsAPM::API.log_exception(name, e)
103
- raise
104
- ensure
105
- SolarWindsAPM::API.log_exit(name, kvs, protect_op)
106
- end
107
- end
108
-
109
- # Collect metrics and start tracing a given block of code.
110
- #
111
- # This will start a trace depending on configuration and probability, detect any exceptions
112
- # thrown by the block, and report errors.
113
- #
114
- # This method is for request entry points where no trace has been started yet
115
- # Nested calls to start_trace() will have the inner call override the outer call
116
- # The behavior may be unexpected. After a trace is started with start_trace()
117
- # trace() should be used to create spans within the started trace
118
- #
119
- # When start_trace returns control to the calling context, the trace will be
120
- # completed and the tracing context will be cleared.
121
- #
122
- # === Arguments:
123
- #
124
- # * +name+ - Name for the span to be used as label in the trace view.
125
- # * +kvs:+ - (optional) hash containing key/value pairs that will be reported with this span.
126
- # The value of :TransactionName entry will set the transaction_name.
127
- # * +headers:+ - hash containing incoming headers to extract w3c trace context
128
- #
129
- # === Example:
130
- #
131
- # def handle_request(request, response)
132
- # # ... code that processes request and response ...
133
- # end
134
- #
135
- # def handle_request_with_sw_apm(request, response)
136
- # SolarWindsAPM::SDK.start_trace('custom_trace', kvs: { :TransactionName => 'handle_request' }) do
137
- # handle_request(request, response)
138
- # end
139
- # end
140
- #
141
- # === Returns:
142
- # * The result of the block.
143
- #
144
- def start_trace(name, kvs: {}, headers: {})
145
- start_trace_with_target(name, target: {}, kvs: kvs, headers: headers) { yield }
146
- end
147
-
148
- # Collect metrics, trace a given block of code, and assign trace info to target.
149
- #
150
- # This will start a trace depending on configuration and probability, detect any exceptions
151
- # thrown by the block, report errors, and assign an X-Trace to the target.
152
- #
153
- # The motivating use case for this is HTTP streaming in rails3. We need
154
- # access to the exit event's trace id so we can set the header before any
155
- # work is done, and before any headers are sent back to the client.
156
- #
157
- # === Arguments:
158
- # * +name+ - Name for the span to be used as label in the trace view.
159
- # * +target:+ - (optional) has to respond to #[]=, The target object in which to place the trace information.
160
- # * +kvs:+ - (optional) Hash containing key/value pairs that will be reported with this span.
161
- # * +headers:+ - (optional) Hash containing incoming headers to extract w3c trace context
162
- #
163
- # === Example:
164
- #
165
- # def handle_request(request, response)
166
- # # ... code that processes request and response ...
167
- # end
168
- #
169
- # def handle_request_with_sw_apm(request, response)
170
- # SolarWindsAPM::SDK.start_trace_with_target('rails', headers: request.headers, target: response) do
171
- # handle_request(request, response)
172
- # end
173
- # end
174
- #
175
- # === Returns:
176
- # * The result of the block.
177
- #
178
- def start_trace_with_target(name, target: {}, kvs: {}, headers: {})
179
- return yield unless SolarWindsAPM.loaded
180
-
181
- SolarWindsAPM.transaction_name = kvs.delete('TransactionName') || kvs.delete(:TransactionName)
182
-
183
- SolarWindsAPM::API.log_start(name, kvs, headers)
184
- kvs[:Backtrace] && kvs.delete(:Backtrace) # to avoid sending backtrace twice (faster to check presence here)
185
-
186
- # SolarWindsAPM::Event.startTrace creates an Event without an Edge
187
- exit_evt = SolarWindsAPM::Event.startTrace(SolarWindsAPM::Context.get)
188
-
189
- result = begin
190
- SolarWindsAPM::API.send_metrics(name, kvs) do
191
- target['X-Trace'] = SolarWindsAPM::EventUtil.metadataString(exit_evt)
192
- yield
193
- end
194
- rescue Exception => e
195
- SolarWindsAPM::API.log_exception(name, e)
196
- exit_evt.addEdge(SolarWindsAPM::Context.get)
197
- trace_parent = SolarWindsAPM::API.log_end(name, kvs, exit_evt)
198
- e.instance_variable_set(:@tracestring, trace_parent)
199
- raise
200
- end
201
-
202
- exit_evt.addEdge(SolarWindsAPM::Context.get)
203
- SolarWindsAPM::API.log_end(name, kvs, exit_evt)
204
-
205
- result
206
- end
207
-
208
- ##
209
- # Add tracing to a given method
210
- #
211
- # This instruments the given method so that every time it is called it
212
- # will create a span depending on the current context.
213
- #
214
- # The method can be of any (accessible) type (instance, singleton,
215
- # private, protected etc.).
216
- #
217
- # The motivating use case for this is MetalController methods in Rails,
218
- # which can't be auto-instrumented.
219
- #
220
- # === Arguments:
221
- # * +klass+ - The module/class the method belongs to.
222
- # * +method+ - The method name as symbol
223
- # * +config:+ - (optional) possible keys are:
224
- # :name the name of the span (default: the method name)
225
- # :backtrace true/false (default: false) if true the backtrace will be added to the space
226
- # * +kvs:+ - (optional) hash containing key/value pairs that will be reported with this span.
227
- #
228
- # === Example:
229
- #
230
- # module ExampleModule
231
- # def do_sum(a, b)
232
- # a + b
233
- # end
234
- # end
235
- #
236
- # SolarWindsAPM::SDK.trace_method(ExampleModule,
237
- # :do_sum,
238
- # config: {name: 'computation', backtrace: true},
239
- # kvs: { CustomKey: "some_info"})
240
- #
241
- def trace_method(klass, method, config: {}, kvs: {})
242
- # If we're on an unsupported platform (ahem Mac), just act
243
- # like we did something to nicely play the no-op part.
244
- return true unless SolarWindsAPM.loaded
245
-
246
- if !klass.is_a?(Module)
247
- SolarWindsAPM.logger.warn "[solarwinds_apm/error] trace_method: Not sure what to do with #{klass}. Send a class or module."
248
- return false
249
- end
250
-
251
- if method.is_a?(String)
252
- method = method.to_sym
253
- elsif !method.is_a?(Symbol)
254
- SolarWindsAPM.logger.warn "[solarwinds_apm/error] trace_method: Not sure what to do with #{method}. Send a string or symbol for method."
255
- return false
256
- end
257
-
258
- instance_method = klass.instance_methods.include?(method) || klass.private_instance_methods.include?(method)
259
- class_method = klass.singleton_methods.include?(method)
260
-
261
- # Make sure the request klass::method exists
262
- if !instance_method && !class_method
263
- SolarWindsAPM.logger.warn "[solarwinds_apm/error] trace_method: Can't instrument #{klass}.#{method} as it doesn't seem to exist."
264
- SolarWindsAPM.logger.warn "[solarwinds_apm/error] #{__FILE__}:#{__LINE__}"
265
- return false
266
- end
267
-
268
- # Strip '!' or '?' from method if present
269
- safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
270
- safe_method_name ||= method
271
-
272
- without_sw_apm = "#{safe_method_name}_without_sw_apm"
273
- with_sw_apm = "#{safe_method_name}_with_sw_apm"
274
-
275
- # Check if already profiled
276
- if instance_method && klass.instance_methods.include?(with_sw_apm.to_sym) ||
277
- class_method && klass.singleton_methods.include?(with_sw_apm.to_sym)
278
- SolarWindsAPM.logger.warn "[solarwinds_apm/error] trace_method: #{klass}::#{method} already instrumented.\n#{__FILE__}:#{__LINE__}"
279
- return false
280
- end
281
-
282
- report_kvs = kvs.dup
283
- if defined?(::AbstractController::Base) && klass.ancestors.include?(::AbstractController::Base)
284
- report_kvs[:Controller] = klass.to_s
285
- report_kvs[:Action] = method.to_s
286
- else
287
- klass.is_a?(Class) ? report_kvs[:Class] = klass.to_s : report_kvs[:Module] = klass.to_s
288
- report_kvs[:MethodName] = safe_method_name
289
- end
290
- backtrace = config[:backtrace]
291
-
292
- name = config[:name] || method
293
- if instance_method
294
- klass.class_eval do
295
- define_method(with_sw_apm) do |*args, &block|
296
- # if this is a rails controller we want to set the transaction for the outbound metrics
297
- if report_kvs[:Controller] && defined?(request) && defined?(request.env)
298
- request.env['solarwinds_apm.controller'] = report_kvs[:Controller]
299
- request.env['solarwinds_apm.action'] = report_kvs[:Action]
300
- end
301
-
302
- SolarWindsAPM::SDK.trace(name, kvs: report_kvs) do
303
- report_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if backtrace
304
- send(without_sw_apm, *args, &block)
305
- end
306
- end
307
-
308
- alias_method without_sw_apm, method.to_s
309
- alias_method method.to_s, with_sw_apm
310
- end
311
- elsif class_method
312
- klass.define_singleton_method(with_sw_apm) do |*args, &block|
313
- SolarWindsAPM::SDK.trace(name, kvs: report_kvs) do
314
- report_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if backtrace
315
- send(without_sw_apm, *args, &block)
316
- end
317
- end
318
-
319
- klass.singleton_class.class_eval do
320
- alias_method without_sw_apm, method.to_s
321
- alias_method method.to_s, with_sw_apm
322
- end
323
- end
324
- true
325
- end
326
-
327
- ##
328
- # Provide a custom transaction name
329
- #
330
- # The SolarWindsAPM gem tries to create meaningful transaction names from controller+action
331
- # or something similar depending on the framework used. However, you may want to override the
332
- # transaction name to better describe your instrumented operation.
333
- #
334
- # Take note that on the dashboard the transaction name is converted to lowercase, and might be
335
- # truncated with invalid characters replaced. Method calls with an empty string or a non-string
336
- # argument won't change the current transaction name.
337
- #
338
- # The configuration +SolarWindsAPM.Config+['transaction_name']+['prepend_domain']+ can be set to
339
- # true to have the domain name prepended to the transaction name when an event or a metric are
340
- # logged. This is a global setting.
341
- #
342
- # === Argument:
343
- #
344
- # * +name+ - A non-empty string with the custom transaction name
345
- #
346
- # === Example:
347
- #
348
- # class DogfoodsController < ApplicationController
349
- #
350
- # def create
351
- # @dogfood = Dogfood.new(params.permit(:brand, :name))
352
- # @dogfood.save
353
- #
354
- # SolarWindsAPM::SDK.set_transaction_name("dogfoodscontroller.create_for_#{params[:brand]}")
355
- #
356
- # redirect_to @dogfood
357
- # end
358
- #
359
- # end
360
- #
361
- # === Returns:
362
- # * (String or nil) the current transaction name
363
- #
364
- def set_transaction_name(name)
365
- if name.is_a?(String) && name.strip != ''
366
- SolarWindsAPM.transaction_name = name
367
- else
368
- SolarWindsAPM.logger.debug "[solarwinds_apm/api] Could not set transaction name, provided name is empty or not a String."
369
- end
370
- SolarWindsAPM.transaction_name
371
- end
372
-
373
- # Get the currently set custom transaction name.
374
- #
375
- # This is provided for testing
376
- #
377
- # === Returns:
378
- # * (String or nil) the current transaction name (without domain prepended)
379
- #
380
- def get_transaction_name
381
- SolarWindsAPM.transaction_name
382
- end
383
-
384
- # Determine if this transaction is being traced.
385
- #
386
- # Tracing puts some extra load on a system, therefore not all transaction are traced.
387
- # The +tracing?+ method helps to determine this so that extra work can be avoided when not tracing.
388
- #
389
- # === Example:
390
- #
391
- # kvs = expensive_info_gathering_method if SolarWindsAPM::SDK.tracing?
392
- # SolarWindsAPM::SDK.trace('some_span', kvs: kvs) do
393
- # db_request
394
- # end
395
- #
396
- def tracing?
397
- SolarWindsAPM.tracing?
398
- end
399
-
400
- # Wait for SolarWinds to be ready to send traces.
401
- #
402
- # This may be useful in short lived background processes when it is important to capture
403
- # information during the whole time the process is running. Usually SolarWinds doesn't block an
404
- # application while it is starting up.
405
- #
406
- # === Argument:
407
- #
408
- # * +wait_milliseconds+ (int, default 3000) the maximum time to wait in milliseconds
409
- #
410
- # === Example:
411
- #
412
- # unless SolarWindsAPM::SDK.solarwinds_ready?(10_000)
413
- # Logger.info "SolarWindsAPM not ready after 10 seconds, no metrics will be sent"
414
- # end
415
- #
416
- def solarwinds_ready?(wait_milliseconds = 3000)
417
- return false unless SolarWindsAPM.loaded
418
- # These codes are returned by isReady:
419
- # OBOE_SERVER_RESPONSE_UNKNOWN 0
420
- # OBOE_SERVER_RESPONSE_OK 1
421
- # OBOE_SERVER_RESPONSE_TRY_LATER 2
422
- # OBOE_SERVER_RESPONSE_LIMIT_EXCEEDED 3
423
- # OBOE_SERVER_RESPONSE_INVALID_API_KEY 4
424
- # OBOE_SERVER_RESPONSE_CONNECT_ERROR 5
425
- SolarWindsAPM::Context.isReady(wait_milliseconds) == 1
426
- end
427
- end
428
-
429
- extend Tracing
430
-
431
- end
432
- end
@@ -1,25 +0,0 @@
1
- # Copyright (c) 2020 SolarWinds, LLC.
2
- # All rights reserved.
3
-
4
- module SolarWindsAPM
5
-
6
- # *
7
- # * This class only got defined if Init_profiling defined in init_solarwinds_apm.cc
8
- class Profiling
9
-
10
- def self.run
11
- # TODO
12
- # add back at some point but for now NH is not ready for profiling
13
- SolarWindsAPM::Config.profiling = :disabled
14
-
15
- # allow enabling and disabling and setting interval interactively
16
- return yield unless SolarWindsAPM::Config.profiling == :enabled && SolarWindsAPM.tracing?
17
-
18
- CProfiler.run(Thread.current, SolarWindsAPM::Config.profiling_interval) do
19
- # for some reason `return` is needed here
20
- # this is yielded by c-code, but why it needs `return` ... ????
21
- return yield
22
- end
23
- end
24
- end
25
- end
@@ -1,53 +0,0 @@
1
- # Copyright (c) SolarWinds, LLC.
2
- # All rights reserved.
3
-
4
- module SolarWindsAPM
5
-
6
- class TraceContext
7
-
8
- attr_reader :traceparent, :tracestate, :tracestring, :sw_member_value
9
-
10
- def initialize(headers = {})
11
- return if headers.nil? || headers.empty?
12
-
13
- # we won't propagate this context if the traceparent is invalid
14
- traceparent, tracestate = ingest(headers)
15
- return unless traceparent.is_a?(String) && SolarWindsAPM::TraceString.valid?(traceparent)
16
-
17
- @traceparent = traceparent
18
- @tracestate = tracestate
19
-
20
- if @tracestate
21
- @sw_member_value = TraceState.sw_member_value(@tracestate)
22
- @tracestring = SolarWindsAPM::TraceString.replace_span_id_flags(@traceparent, @sw_member_value)
23
- end
24
-
25
- @tracestring ||= @traceparent
26
- end
27
-
28
- # these are event kvs, not headers
29
- # called by log_start, lets reset to nil if there is no info
30
- def add_traceinfo(kvs = {})
31
- kvs['sw.tracestate_parent_id'] = @sw_member_value ? @sw_member_value[0...-3] : nil
32
- kvs['sw.w3c.tracestate'] = @tracestate ? @tracestate : nil
33
- kvs
34
- end
35
-
36
- private
37
-
38
- def ingest(headers)
39
- traceparent_key = headers.keys.find do |key|
40
- key.to_s.downcase =~ /^(http){0,1}[_-]{0,1}traceparent$/
41
- end
42
-
43
- tracestate_key = headers.keys.find do |key|
44
- key.to_s.downcase =~ /^(http){0,1}[_-]{0,1}tracestate$/
45
- end
46
-
47
- return nil, nil unless traceparent_key && tracestate_key
48
-
49
- [headers[traceparent_key], headers[tracestate_key]]
50
- end
51
-
52
- end
53
- end
@@ -1,69 +0,0 @@
1
- # Copyright (c) 2021 SolarWinds, LLC.
2
- # All rights reserved.
3
-
4
- module SolarWindsAPM
5
-
6
- # test coverage through instrumentation_mocked and inst tests
7
- module TraceState
8
- class << self
9
-
10
- # prepends our kv to tracestate string
11
- # value has to be in W3C format
12
- def add_sw_member(tracestate, value)
13
- return tracestate unless sw_value_valid?(value)
14
-
15
- result = "#{SW_APM_TRACESTATE_ID}=#{value}#{remove_sw(tracestate)}"
16
-
17
- if result.bytesize > SW_APM_MAX_TRACESTATE_BYTES
18
- return reduce_size(result)
19
- end
20
-
21
- result
22
- end
23
-
24
- # extract the 'sw' tracestate member, parent_id/edge, and flags
25
- def sw_member_value(tracestate)
26
- regex = /^.*(#{SW_APM_TRACESTATE_ID}=(?<sw_member_value>[a-f0-9]{16}-[a-f0-9]{2})).*$/.freeze
27
-
28
- matches = regex.match(tracestate)
29
-
30
- return nil unless matches
31
-
32
- matches[:sw_member_value]
33
- end
34
-
35
- private
36
-
37
- # returns tracestate with leading comma for specific use
38
- # in add_sw_member
39
- def remove_sw(tracestate)
40
- return "" unless tracestate
41
- tracestate.gsub!(/,{0,1}\s*#{SW_APM_TRACESTATE_ID}=[^,]*/, '')
42
- (tracestate.size > 0 && tracestate[0] != ',') ? ",#{tracestate}" : tracestate
43
- end
44
-
45
- # this validates the format of the value of our vendor entry
46
- def sw_value_valid?(value)
47
- value =~ /^[a-f0-9]{16}-0[01]$/.freeze
48
- end
49
-
50
- def reduce_size(tracestate)
51
- size = tracestate.bytesize
52
- members = tracestate.split(',').reverse
53
-
54
- large_members = members.select { |m| m.bytesize > SW_APM_MAX_TRACESTATE_MEMBER_BYTES }
55
- while large_members[0] && size > SW_APM_MAX_TRACESTATE_BYTES
56
- size -= large_members[0].bytesize + 1 # add 1 for comma
57
- members.delete(large_members.shift)
58
- end
59
-
60
- tracestate = members.reverse.join(',')
61
- until tracestate.bytesize <= SW_APM_MAX_TRACESTATE_BYTES do
62
- tracestate.gsub!(/,[^,]*$/, '')
63
- end
64
- tracestate
65
- end
66
-
67
- end
68
- end
69
- end
@@ -1,89 +0,0 @@
1
- # Copyright (c) SolarWinds, LLC.
2
- # All rights reserved.
3
-
4
- module SolarWindsAPM
5
- module TraceString
6
- # This module processes and queries strings of the format defined in
7
- # https://www.w3.org/TR/trace-context/#traceparent-header
8
-
9
- # Regexp copied from Ruby OT trace_string.rb
10
- REGEXP = /^(?<tracestring>(?<version>[a-f0-9]{2})-(?<trace_id>[a-f0-9]{32})-(?<span_id>[a-f0-9]{16})-(?<flags>[a-f0-9]{2}))$/.freeze
11
- private_constant :REGEXP
12
-
13
- class << self
14
-
15
- def split(tracestring)
16
- matches = REGEXP.match(tracestring)
17
-
18
- matches
19
- end
20
-
21
- # un-initialized (all 0 trace-id) tracestrings are not valid
22
- def valid?(tracestring)
23
- matches = REGEXP.match(tracestring)
24
-
25
- matches && matches[:trace_id] != ("0" * 32)
26
- end
27
-
28
- def sampled?(tracestring)
29
- matches = REGEXP.match(tracestring)
30
-
31
- matches && matches[:flags][-1].to_i & 1 == 1
32
- end
33
-
34
- def trace_id(tracestring)
35
- matches = REGEXP.match(tracestring)
36
-
37
- matches && matches[:trace_id]
38
- end
39
-
40
- def span_id(tracestring)
41
- matches = REGEXP.match(tracestring)
42
-
43
- matches && matches[:span_id]
44
- end
45
-
46
- # Extract and return the span_id and flags
47
- def span_id_flags(tracestring)
48
- matches = REGEXP.match(tracestring)
49
-
50
- matches && "#{matches[:span_id]}-#{matches[:flags]}"
51
- end
52
-
53
- def set_sampled(tracestring)
54
- return unless REGEXP.match(tracestring)
55
-
56
- last = tracestring[-2..-1].hex | 0x00000001
57
- last = last.to_s(16).rjust(2, '0')
58
-
59
- tracestring[-2..-1] = last
60
- tracestring
61
- end
62
-
63
- def unset_sampled(tracestring)
64
- return unless REGEXP.match(tracestring)
65
-
66
- # shift left and right to set last bit to zero
67
- last = tracestring[-2..-1].hex >> 1 << 1
68
- last = last.to_s(16).rjust(2, '0')
69
-
70
- tracestring[-2..-1] = last
71
- tracestring
72
- end
73
-
74
- # !!! garbage in garbage out !!!
75
- # span_id_flag are not checked for validity
76
- # method is only used in TraceContext, where span_id_flags arg
77
- # is created and is either valid or nil
78
- def replace_span_id_flags(tracestring, span_id_flags)
79
- return unless REGEXP.match(tracestring)
80
- return tracestring unless span_id_flags =~ /^[a-f0-9]{16}-[a-f0-9]{2}$/
81
-
82
- matches = REGEXP.match(tracestring)
83
-
84
- "#{matches[:version]}-#{matches[:trace_id]}-#{span_id_flags}"
85
- end
86
-
87
- end
88
- end
89
- end