solarwinds_apm 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
  4. data/.github/workflows/build_and_release_gem.yml +112 -0
  5. data/.github/workflows/build_for_packagecloud.yml +70 -0
  6. data/.github/workflows/docker-images.yml +47 -0
  7. data/.github/workflows/run_cpluplus_tests.yml +73 -0
  8. data/.github/workflows/run_tests.yml +155 -0
  9. data/.github/workflows/scripts/test_install.rb +23 -0
  10. data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
  11. data/.github/workflows/test_on_4_linux.yml +161 -0
  12. data/.gitignore +39 -0
  13. data/.rubocop.yml +29 -0
  14. data/.yardopts +7 -0
  15. data/CHANGELOG.md +769 -0
  16. data/CONFIG.md +31 -0
  17. data/Gemfile +14 -0
  18. data/LICENSE +202 -0
  19. data/README.md +383 -0
  20. data/bin/solarwinds_apm_config +15 -0
  21. data/examples/prepend.rb +13 -0
  22. data/examples/sdk_examples.rb +158 -0
  23. data/ext/oboe_metal/README.md +69 -0
  24. data/ext/oboe_metal/extconf.rb +141 -0
  25. data/ext/oboe_metal/extconf_local.rb +75 -0
  26. data/ext/oboe_metal/lib/.keep +0 -0
  27. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
  28. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
  29. data/ext/oboe_metal/noop/noop.c +8 -0
  30. data/ext/oboe_metal/src/README.md +6 -0
  31. data/ext/oboe_metal/src/VERSION +2 -0
  32. data/ext/oboe_metal/src/bson/bson.h +220 -0
  33. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  34. data/ext/oboe_metal/src/frames.cc +247 -0
  35. data/ext/oboe_metal/src/frames.h +40 -0
  36. data/ext/oboe_metal/src/init_solarwinds_apm.cc +21 -0
  37. data/ext/oboe_metal/src/logging.cc +95 -0
  38. data/ext/oboe_metal/src/logging.h +35 -0
  39. data/ext/oboe_metal/src/oboe.h +1169 -0
  40. data/ext/oboe_metal/src/oboe_api.cpp +658 -0
  41. data/ext/oboe_metal/src/oboe_api.hpp +433 -0
  42. data/ext/oboe_metal/src/oboe_debug.h +59 -0
  43. data/ext/oboe_metal/src/oboe_swig_wrap.cc +7562 -0
  44. data/ext/oboe_metal/src/profiling.cc +435 -0
  45. data/ext/oboe_metal/src/profiling.h +78 -0
  46. data/ext/oboe_metal/test/CMakeLists.txt +53 -0
  47. data/ext/oboe_metal/test/FindGMock.cmake +43 -0
  48. data/ext/oboe_metal/test/README.md +56 -0
  49. data/ext/oboe_metal/test/frames_test.cc +164 -0
  50. data/ext/oboe_metal/test/profiling_test.cc +93 -0
  51. data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
  52. data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
  53. data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
  54. data/ext/oboe_metal/test/test.h +11 -0
  55. data/ext/oboe_metal/test/test_main.cc +32 -0
  56. data/init.rb +4 -0
  57. data/lib/oboe.rb +7 -0
  58. data/lib/oboe_metal.rb +172 -0
  59. data/lib/rails/generators/solarwinds_apm/install_generator.rb +47 -0
  60. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +424 -0
  61. data/lib/solarwinds_apm/api/layerinit.rb +41 -0
  62. data/lib/solarwinds_apm/api/logging.rb +356 -0
  63. data/lib/solarwinds_apm/api/memcache.rb +37 -0
  64. data/lib/solarwinds_apm/api/metrics.rb +63 -0
  65. data/lib/solarwinds_apm/api/util.rb +98 -0
  66. data/lib/solarwinds_apm/api.rb +21 -0
  67. data/lib/solarwinds_apm/base.rb +160 -0
  68. data/lib/solarwinds_apm/config.rb +301 -0
  69. data/lib/solarwinds_apm/frameworks/grape.rb +96 -0
  70. data/lib/solarwinds_apm/frameworks/padrino.rb +78 -0
  71. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +100 -0
  72. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  73. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  74. data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +88 -0
  75. data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +26 -0
  76. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  77. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +22 -0
  78. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +103 -0
  79. data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +14 -0
  80. data/lib/solarwinds_apm/frameworks/rails.rb +100 -0
  81. data/lib/solarwinds_apm/frameworks/sinatra.rb +96 -0
  82. data/lib/solarwinds_apm/inst/bunny-client.rb +157 -0
  83. data/lib/solarwinds_apm/inst/bunny-consumer.rb +102 -0
  84. data/lib/solarwinds_apm/inst/curb.rb +288 -0
  85. data/lib/solarwinds_apm/inst/dalli.rb +89 -0
  86. data/lib/solarwinds_apm/inst/delayed_job.rb +100 -0
  87. data/lib/solarwinds_apm/inst/excon.rb +113 -0
  88. data/lib/solarwinds_apm/inst/faraday.rb +96 -0
  89. data/lib/solarwinds_apm/inst/graphql.rb +206 -0
  90. data/lib/solarwinds_apm/inst/grpc_client.rb +147 -0
  91. data/lib/solarwinds_apm/inst/grpc_server.rb +119 -0
  92. data/lib/solarwinds_apm/inst/httpclient.rb +181 -0
  93. data/lib/solarwinds_apm/inst/logger_formatter.rb +46 -0
  94. data/lib/solarwinds_apm/inst/logging_log_event.rb +24 -0
  95. data/lib/solarwinds_apm/inst/lumberjack_formatter.rb +9 -0
  96. data/lib/solarwinds_apm/inst/memcached.rb +86 -0
  97. data/lib/solarwinds_apm/inst/mongo.rb +246 -0
  98. data/lib/solarwinds_apm/inst/mongo2.rb +225 -0
  99. data/lib/solarwinds_apm/inst/moped.rb +466 -0
  100. data/lib/solarwinds_apm/inst/net_http.rb +60 -0
  101. data/lib/solarwinds_apm/inst/rack.rb +217 -0
  102. data/lib/solarwinds_apm/inst/rack_cache.rb +35 -0
  103. data/lib/solarwinds_apm/inst/redis.rb +273 -0
  104. data/lib/solarwinds_apm/inst/resque.rb +129 -0
  105. data/lib/solarwinds_apm/inst/rest-client.rb +43 -0
  106. data/lib/solarwinds_apm/inst/sequel.rb +241 -0
  107. data/lib/solarwinds_apm/inst/sidekiq-client.rb +63 -0
  108. data/lib/solarwinds_apm/inst/sidekiq-worker.rb +64 -0
  109. data/lib/solarwinds_apm/inst/typhoeus.rb +90 -0
  110. data/lib/solarwinds_apm/instrumentation.rb +22 -0
  111. data/lib/solarwinds_apm/loading.rb +65 -0
  112. data/lib/solarwinds_apm/logger.rb +14 -0
  113. data/lib/solarwinds_apm/noop/README.md +9 -0
  114. data/lib/solarwinds_apm/noop/context.rb +26 -0
  115. data/lib/solarwinds_apm/noop/metadata.rb +25 -0
  116. data/lib/solarwinds_apm/noop/profiling.rb +21 -0
  117. data/lib/solarwinds_apm/oboe_init_options.rb +191 -0
  118. data/lib/solarwinds_apm/ruby.rb +35 -0
  119. data/lib/solarwinds_apm/sdk/current_trace_info.rb +123 -0
  120. data/lib/solarwinds_apm/sdk/custom_metrics.rb +94 -0
  121. data/lib/solarwinds_apm/sdk/logging.rb +37 -0
  122. data/lib/solarwinds_apm/sdk/trace_context_headers.rb +69 -0
  123. data/lib/solarwinds_apm/sdk/tracing.rb +432 -0
  124. data/lib/solarwinds_apm/support/profiling.rb +22 -0
  125. data/lib/solarwinds_apm/support/trace_context.rb +53 -0
  126. data/lib/solarwinds_apm/support/trace_state.rb +69 -0
  127. data/lib/solarwinds_apm/support/trace_string.rb +89 -0
  128. data/lib/solarwinds_apm/support/transaction_metrics.rb +67 -0
  129. data/lib/solarwinds_apm/support/transaction_settings.rb +233 -0
  130. data/lib/solarwinds_apm/support/x_trace_options.rb +113 -0
  131. data/lib/solarwinds_apm/support.rb +12 -0
  132. data/lib/solarwinds_apm/support_report.rb +113 -0
  133. data/lib/solarwinds_apm/test.rb +165 -0
  134. data/lib/solarwinds_apm/thread_local.rb +26 -0
  135. data/lib/solarwinds_apm/util.rb +334 -0
  136. data/lib/solarwinds_apm/version.rb +17 -0
  137. data/lib/solarwinds_apm.rb +72 -0
  138. data/log/.keep +0 -0
  139. data/log/postgresql/.keep +0 -0
  140. data/solarwinds_apm.gemspec +52 -0
  141. data/yardoc_frontpage.md +24 -0
  142. metadata +228 -0
@@ -0,0 +1,67 @@
1
+ # Copyright (c) 2018 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ ##
6
+ # This module sends the duration of the call and
7
+ # sets the transaction_name
8
+ #
9
+ class TransactionMetrics
10
+ class << self
11
+
12
+ ##
13
+ # sends the duration of the call and
14
+ # sets the transaction_name
15
+ def metrics(env, settings)
16
+ if settings.do_metrics
17
+ req = ::Rack::Request.new(env)
18
+ # TODO rails 3x is not supported anymore ...
19
+ url = req.url # saving it here because rails3.2 overrides it when there is a 500 error
20
+ start = Time.now
21
+
22
+ begin
23
+ status, headers, response = yield
24
+
25
+ SolarWindsAPM.transaction_name = send_metrics(env, req, url, start, status)
26
+ rescue
27
+ SolarWindsAPM.transaction_name = send_metrics(env, req, url, start, status || '500')
28
+ raise
29
+ end
30
+ else
31
+ status, headers, response = yield
32
+ SolarWindsAPM.transaction_name = "#{domain(req)}#{transaction_name(env)}" if settings.do_sample
33
+ end
34
+
35
+ [status, headers, response]
36
+ end
37
+
38
+ private
39
+
40
+ def send_metrics(env, req, url, start, status)
41
+ name = transaction_name(env)
42
+
43
+ status = status.to_i
44
+ error = status.between?(500,599) ? 1 : 0
45
+ duration =(1000 * 1000 * (Time.now - start)).round(0)
46
+ method = req.request_method
47
+ # SolarWindsAPM.logger.warn "%%% Sending metrics: #{name}, #{url}, #{status} %%%"
48
+ SolarWindsAPM::Span.createHttpSpan(name, url, domain(req), duration, status, method, error) || ''
49
+ end
50
+
51
+ def domain(req)
52
+ if SolarWindsAPM::Config['transaction_name']['prepend_domain']
53
+ [80, 443].include?(req.port) ? req.host : "#{req.host}:#{req.port}"
54
+ end
55
+ end
56
+
57
+ def transaction_name(env)
58
+ return SolarWindsAPM.transaction_name if SolarWindsAPM.transaction_name
59
+
60
+ if env['solarwinds_apm.controller'] && env['solarwinds_apm.action']
61
+ [env['solarwinds_apm.controller'], env['solarwinds_apm.action']].join('.')
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,233 @@
1
+ # Copyright (c) 2018 SolarWinds, LLC.
2
+ # All rights reserved.
3
+ #
4
+
5
+ AO_TRACING_ENABLED = 1
6
+ AO_TRACING_DISABLED = 0
7
+ AO_TRACING_UNSET = -1
8
+
9
+ AO_TRACING_DECISIONS_OK = 0
10
+
11
+ OBOE_SETTINGS_UNSET = -1
12
+
13
+ module SolarWindsAPM
14
+ ##
15
+ # This module helps with setting up the transaction filters and applying them
16
+ #
17
+ class TransactionSettings
18
+
19
+ attr_accessor :do_sample, :do_metrics
20
+ attr_reader :auth_msg, :do_propagate, :status_msg, :type, :source, :rate, :tracestring, :sw_member_value
21
+
22
+ def initialize(url = '', headers = {}, options = nil)
23
+ @do_metrics = false
24
+ @do_sample = false
25
+ @do_propagate = true
26
+
27
+ SolarWindsAPM.trace_context = SolarWindsAPM::TraceContext.new(headers)
28
+ @tracestring = SolarWindsAPM.trace_context.tracestring
29
+ @sw_member_value = SolarWindsAPM.trace_context.sw_member_value
30
+ tracing_mode = AO_TRACING_ENABLED
31
+
32
+ # TODO
33
+ # NH-11132 will address this
34
+ # incoming tracing info has priority over existing context
35
+ # if SolarWindsAPM::Context.isValid && !@sw_member_value
36
+ # @do_sample = SolarWindsAPM.tracing?
37
+ # return
38
+ # end
39
+
40
+ if url && asset?(url)
41
+ @do_propagate = false
42
+ return
43
+ end
44
+
45
+ if tracing_mode_disabled? && !tracing_enabled?(url) ||
46
+ tracing_disabled?(url)
47
+
48
+ tracing_mode = AO_TRACING_DISABLED
49
+ end
50
+
51
+ # args (all optional)
52
+ # 0 char const *in_xtrace
53
+ # 1 char const *tracestate
54
+ # 2 int custom_tracing_mode
55
+ # 3 int custom_sample_rate
56
+ # 4 int request_type
57
+ # 5 int custom_trigger_mode
58
+ # 6 char const *header_options
59
+ # 7 char const *header_signature
60
+ # 8 long header_timestamp
61
+ args = [@tracestring, @sw_member_value] #0,1
62
+ args << tracing_mode #2
63
+ args << (SolarWindsAPM::Config[:sample_rate] || OBOE_SETTINGS_UNSET) #3
64
+
65
+ if options && (options.options || options.signature)
66
+ args << (options.trigger_trace ? 1 : 0) #4
67
+ args << (trigger_tracing_mode_disabled? ? 0 : 1) #5
68
+ args << options.options #6
69
+ args << options.signature #7
70
+ args << options.timestamp #8
71
+ end
72
+
73
+ metrics, sample, @rate, @source, @bucket_rate, @bucket_cap, @type, @auth, @status_msg, @auth_msg, @status =
74
+ SolarWindsAPM::Context.getDecisions(*args)
75
+
76
+ if @status > AO_TRACING_DECISIONS_OK
77
+ SolarWindsAPM.logger.warn "[solarwinds_apm/sample] Problem getting the sampling decisions: #{@status_msg} code: #{@status}"
78
+ end
79
+
80
+ @do_metrics = metrics > 0
81
+ @do_sample = sample > 0
82
+ end
83
+
84
+ def to_s
85
+ "do_propagate: #{do_propagate}, do_sample: #{do_sample}, do_metrics: #{do_metrics} rate: #{rate}, source: #{source}"
86
+ end
87
+
88
+ def add_kvs(kvs)
89
+ kvs[:SampleRate] = @rate
90
+ kvs[:SampleSource] = @source
91
+ end
92
+
93
+ def triggered_trace?
94
+ @type == 1
95
+ end
96
+
97
+ def auth_ok?
98
+ # @auth is undefined if initialize is called with an existing context
99
+ !@auth || @auth < 1
100
+ end
101
+
102
+ private
103
+
104
+ ##
105
+ # check the config setting for :tracing_mode
106
+ def tracing_mode_disabled?
107
+ SolarWindsAPM::Config[:tracing_mode] &&
108
+ [:disabled, :never].include?(SolarWindsAPM::Config[:tracing_mode])
109
+ end
110
+
111
+ ##
112
+ # tracing_enabled?
113
+ #
114
+ # Given a path, this method determines whether it matches any of the
115
+ # regexps to exclude it from metrics and traces
116
+ #
117
+ def tracing_enabled?(url)
118
+ return false unless SolarWindsAPM::Config[:url_enabled_regexps].is_a? Array
119
+ # once we only support Ruby >= 2.4.0 use `match?` instead of `=~`
120
+ return SolarWindsAPM::Config[:url_enabled_regexps].any? { |regex| regex =~ url }
121
+ rescue => e
122
+ SolarWindsAPM.logger.warn "[SolarWindsAPM/filter] Could not apply :enabled filter to path. #{e.inspect}"
123
+ true
124
+ end
125
+
126
+ ##
127
+ # tracing_disabled?
128
+ #
129
+ # Given a path, this method determines whether it matches any of the
130
+ # regexps to exclude it from metrics and traces
131
+ #
132
+ def tracing_disabled?(url)
133
+ return false unless SolarWindsAPM::Config[:url_disabled_regexps].is_a? Array
134
+ # once we only support Ruby >= 2.4.0 use `match?` instead of `=~`
135
+ return SolarWindsAPM::Config[:url_disabled_regexps].any? { |regex| regex =~ url }
136
+ rescue => e
137
+ SolarWindsAPM.logger.warn "[SolarWindsAPM/filter] Could not apply :disabled filter to path. #{e.inspect}"
138
+ false
139
+ end
140
+
141
+ def trigger_tracing_mode_disabled?
142
+ SolarWindsAPM::Config[:trigger_tracing_mode] &&
143
+ SolarWindsAPM::Config[:trigger_tracing_mode] == :disabled
144
+ end
145
+
146
+ ##
147
+ # asset?
148
+ #
149
+ # Given a path, this method determines whether it is a static asset
150
+ #
151
+ def asset?(path)
152
+ return false unless SolarWindsAPM::Config[:dnt_compiled]
153
+ # once we only support Ruby >= 2.4.0 use `match?` instead of `=~`
154
+ return SolarWindsAPM::Config[:dnt_compiled] =~ path
155
+ rescue => e
156
+ SolarWindsAPM.logger.warn "[SolarWindsAPM/filter] Could not apply do-not-trace filter to path. #{e.inspect}"
157
+ false
158
+ end
159
+
160
+ public
161
+
162
+ class << self
163
+
164
+ def asset?(path)
165
+ return false unless SolarWindsAPM::Config[:dnt_compiled]
166
+ # once we only support Ruby >= 2.4.0 use `match?` instead of `=~`
167
+ return SolarWindsAPM::Config[:dnt_compiled] =~ path
168
+ rescue => e
169
+ SolarWindsAPM.logger.warn "[SolarWindsAPM/filter] Could not apply do-not-trace filter to path. #{e.inspect}"
170
+ false
171
+ end
172
+
173
+ def compile_url_settings(settings)
174
+ if !settings.is_a?(Array) || settings.empty?
175
+ reset_url_regexps
176
+ return
177
+ end
178
+
179
+ # `tracing: disabled` is the default
180
+ disabled = settings.select { |v| !v.has_key?(:tracing) || v[:tracing] == :disabled }
181
+ enabled = settings.select { |v| v[:tracing] == :enabled }
182
+
183
+ SolarWindsAPM::Config[:url_enabled_regexps] = compile_regexp(enabled)
184
+ SolarWindsAPM::Config[:url_disabled_regexps] = compile_regexp(disabled)
185
+ end
186
+
187
+ def compile_regexp(settings)
188
+ regexp_regexp = compile_url_settings_regexp(settings)
189
+ extensions_regexp = compile_url_settings_extensions(settings)
190
+
191
+ regexps = [regexp_regexp, extensions_regexp].flatten.compact
192
+
193
+ regexps.empty? ? nil : regexps
194
+ end
195
+
196
+ def compile_url_settings_regexp(value)
197
+ regexps = value.select do |v|
198
+ v.key?(:regexp) &&
199
+ !(v[:regexp].is_a?(String) && v[:regexp].empty?) &&
200
+ !(v[:regexp].is_a?(Regexp) && v[:regexp].inspect == '//')
201
+ end
202
+
203
+ regexps.map! do |v|
204
+ begin
205
+ v[:regexp].is_a?(String) ? Regexp.new(v[:regexp], v[:opts]) : Regexp.new(v[:regexp])
206
+ rescue
207
+ SolarWindsAPM.logger.warn "[solarwinds_apm/config] Problem compiling transaction_settings item #{v}, will ignore."
208
+ nil
209
+ end
210
+ end
211
+ regexps.keep_if { |v| !v.nil? }
212
+ regexps.empty? ? nil : regexps
213
+ end
214
+
215
+ def compile_url_settings_extensions(value)
216
+ extensions = value.select do |v|
217
+ v.key?(:extensions) &&
218
+ v[:extensions].is_a?(Array) &&
219
+ !v[:extensions].empty?
220
+ end
221
+ extensions = extensions.map { |v| v[:extensions] }.flatten
222
+ extensions.keep_if { |v| v.is_a?(String) }
223
+
224
+ extensions.empty? ? nil : Regexp.new("(#{Regexp.union(extensions).source})(\\?.+){0,1}$")
225
+ end
226
+
227
+ def reset_url_regexps
228
+ SolarWindsAPM::Config[:url_enabled_regexps] = nil
229
+ SolarWindsAPM::Config[:url_disabled_regexps] = nil
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,113 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ class XTraceOptions
6
+
7
+ attr_reader :options, :signature, :trigger_trace, :timestamp
8
+ attr_reader :sw_keys, :custom_kvs, :ignored # used in tests
9
+
10
+ ##
11
+ # use by Trigger Tracing
12
+ # TODO - refactor for w3c when ticket ready
13
+ #
14
+ # Params:
15
+ # +options+ : An X-Trace-Options @options string
16
+ # +signature+ : hmac signature to pass on for verification
17
+ #
18
+ # populates:
19
+ # - @force_trace (true|false)
20
+ # - @app_id (as given by Pingdom)
21
+ # - @probe_id (as given by Pingdom)
22
+ # - @loc (2 characters given by Pingdom)
23
+ # - @custom_kvs (hash)
24
+ # - @ignored (array)
25
+ #
26
+ # split it up by ';' separator
27
+ # kv assignment by '='
28
+ # currently valid keys:
29
+ # - force_trace (valid: 0,1) unless we use just a kv
30
+ # - application_id (format defined by pingdom (no validation))
31
+ # - probe_id
32
+ # - custom_* (';=' not allowed in key), value (validate max. length)
33
+ # - ts (unix timestamp)
34
+ # - other keys will be reported in the response options as ignored
35
+
36
+ def initialize(options, signature = nil)
37
+ @options = options.dup
38
+ @signature = signature.dup
39
+ @trigger_trace = false
40
+ @custom_kvs = {}
41
+ @sw_keys = nil
42
+ @ignored = []
43
+ @timestamp = 0
44
+
45
+ options&.split(/;+/)&.each do |val|
46
+ k = val.split('=', 2)
47
+
48
+ next unless k[0] # it can be nil, eg when the header starts with ';'
49
+
50
+ k[0]&.strip!
51
+ case k[0]
52
+ when 'trigger-trace'
53
+ if k[1]
54
+ @ignored << 'trigger-trace'
55
+ else
56
+ @trigger_trace = true
57
+ end
58
+ when 'sw-keys'
59
+ if @sw_keys
60
+ SolarWindsAPM.logger.info "[solarwinds_apm/x-trace-options] Duplicate key: #{k[0]}"
61
+ else
62
+ @sw_keys = k[1].strip
63
+ end
64
+ when /^custom-[^\s]*$/
65
+ if @custom_kvs[k[0]]
66
+ SolarWindsAPM.logger.info "[solarwinds_apm/x-trace-options] Duplicate key: #{k[0]}"
67
+ else
68
+ @custom_kvs[k[0]] = k[1].strip
69
+ end
70
+ when 'ts'
71
+ if @timestamp > 0
72
+ SolarWindsAPM.logger.info "[solarwinds_apm/x-trace-options] Duplicate key: #{k[0]}"
73
+ else
74
+ @timestamp = k[1].to_i
75
+ end
76
+ else
77
+ @ignored << k[0]
78
+ end
79
+ end
80
+ unless @ignored.empty?
81
+ msg = "[solarwinds_apm/x-trace-options] Some keys were ignored: #{@ignored.join(',')}"
82
+ SolarWindsAPM.logger.info(msg)
83
+ end
84
+ end
85
+
86
+ def add_kvs(kvs, settings)
87
+ return unless settings.auth_ok?
88
+
89
+ @custom_kvs.each { |k,v| kvs[k] = v } unless @custom_kvs.empty?
90
+ kvs['SWKeys'] = @sw_keys if @sw_keys
91
+ kvs['TriggeredTrace'] = true if settings.triggered_trace?
92
+ end
93
+
94
+ def add_response_header(headers, settings)
95
+ return unless options
96
+
97
+ response = []
98
+ response << "auth=#{settings.auth_msg}" if @signature
99
+ if settings.auth_ok?
100
+ if @trigger_trace
101
+ trigger_msg = settings.tracestring && settings.type == 0 ? 'ignored' : settings.status_msg
102
+ else
103
+ trigger_msg = 'not-requested'
104
+ end
105
+ response << "trigger-trace=#{trigger_msg}"
106
+ response << "ignored=#{@ignored.join(',')}" unless @ignored.empty?
107
+ end
108
+
109
+ headers['X-Trace-Options-Response'] = response.join(';')
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,12 @@
1
+ # Copyright (c) SolarWinds, LLC.
2
+ # All rights reserved
3
+
4
+ pattern = File.join(File.dirname(__FILE__), 'support', '*.rb')
5
+ Dir.glob(pattern) do |f|
6
+ begin
7
+ require f
8
+ rescue => e
9
+ SolarWindsAPM.logger.error "[solarwinds_apm/loading] Error loading support file '#{f}' : #{e}"
10
+ SolarWindsAPM.logger.debug "[solarwinds_apm/loading] #{e.backtrace.first}"
11
+ end
12
+ end
@@ -0,0 +1,113 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'rbconfig'
5
+ require 'logger'
6
+
7
+ module SolarWindsAPM
8
+ ##
9
+ # This module is used to debug problematic setups and/or environments.
10
+ # Depending on the environment, output may be to stdout or the framework
11
+ # log file (e.g. log/production.log)
12
+
13
+ ##
14
+ # yesno
15
+ #
16
+ # Utility method to translate value/nil to "yes"/"no" strings
17
+ def self.yesno(x)
18
+ x ? 'yes' : 'no'
19
+ end
20
+
21
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
22
+ def self.support_report
23
+ @logger_level = SolarWindsAPM.logger.level
24
+ SolarWindsAPM.logger.level = ::Logger::DEBUG
25
+
26
+ SolarWindsAPM.logger.warn '********************************************************'
27
+ SolarWindsAPM.logger.warn '* BEGIN SolarWindsAPM Support Report'
28
+ SolarWindsAPM.logger.warn '* Please email the output of this report to technicalsupport@solarwinds.com'
29
+ SolarWindsAPM.logger.warn '********************************************************'
30
+ SolarWindsAPM.logger.warn "Ruby: #{RUBY_DESCRIPTION}"
31
+ SolarWindsAPM.logger.warn "$0: #{$0}"
32
+ SolarWindsAPM.logger.warn "$1: #{$1}" unless $1.nil?
33
+ SolarWindsAPM.logger.warn "$2: #{$2}" unless $2.nil?
34
+ SolarWindsAPM.logger.warn "$3: #{$3}" unless $3.nil?
35
+ SolarWindsAPM.logger.warn "$4: #{$4}" unless $4.nil?
36
+ SolarWindsAPM.logger.warn "SolarWindsAPM.loaded == #{SolarWindsAPM.loaded}"
37
+
38
+ on_heroku = SolarWindsAPM.heroku?
39
+ SolarWindsAPM.logger.warn "On Heroku?: #{yesno(on_heroku)}"
40
+ if on_heroku
41
+ SolarWindsAPM.logger.warn "SW_APM_URL: #{ENV['SW_APM_URL']}"
42
+ end
43
+
44
+ SolarWindsAPM.logger.warn "SolarWindsAPM::Ruby defined?: #{yesno(defined?(SolarWindsAPM::Ruby))}"
45
+ SolarWindsAPM.logger.warn "SolarWindsAPM.reporter: #{SolarWindsAPM.reporter}"
46
+
47
+ SolarWindsAPM.logger.warn '********************************************************'
48
+ SolarWindsAPM.logger.warn '* Frameworks'
49
+ SolarWindsAPM.logger.warn '********************************************************'
50
+
51
+ using_rails = defined?(::Rails)
52
+ SolarWindsAPM.logger.warn "Using Rails?: #{yesno(using_rails)}"
53
+ if using_rails
54
+ SolarWindsAPM.logger.warn "SolarWindsAPM::Rails loaded?: #{yesno(defined?(SolarWindsAPM::Rails))}"
55
+ if defined?(SolarWindsAPM::Rack)
56
+ SolarWindsAPM.logger.warn "SolarWindsAPM::Rack middleware loaded?: #{yesno(::Rails.configuration.middleware.include? SolarWindsAPM::Rack)}"
57
+ end
58
+ end
59
+
60
+ using_sinatra = defined?(::Sinatra)
61
+ SolarWindsAPM.logger.warn "Using Sinatra?: #{yesno(using_sinatra)}"
62
+
63
+ using_padrino = defined?(::Padrino)
64
+ SolarWindsAPM.logger.warn "Using Padrino?: #{yesno(using_padrino)}"
65
+
66
+ using_grape = defined?(::Grape)
67
+ SolarWindsAPM.logger.warn "Using Grape?: #{yesno(using_grape)}"
68
+
69
+ SolarWindsAPM.logger.warn '********************************************************'
70
+ SolarWindsAPM.logger.warn '* ActiveRecord Adapter'
71
+ SolarWindsAPM.logger.warn '********************************************************'
72
+ if defined?(::ActiveRecord)
73
+ if defined?(::ActiveRecord::Base.connection.adapter_name)
74
+ SolarWindsAPM.logger.warn "ActiveRecord adapter: #{::ActiveRecord::Base.connection.adapter_name}"
75
+ end
76
+ else
77
+ SolarWindsAPM.logger.warn 'No ActiveRecord'
78
+ end
79
+
80
+ SolarWindsAPM.logger.warn '********************************************************'
81
+ SolarWindsAPM.logger.warn '* SolarWindsAPM::Config Values'
82
+ SolarWindsAPM.logger.warn '********************************************************'
83
+ SolarWindsAPM::Config.print_config
84
+
85
+ SolarWindsAPM.logger.warn '********************************************************'
86
+ SolarWindsAPM.logger.warn '* OS, Platform + Env'
87
+ SolarWindsAPM.logger.warn '********************************************************'
88
+ SolarWindsAPM.logger.warn "host_os: " + RbConfig::CONFIG['host_os']
89
+ SolarWindsAPM.logger.warn "sitearch: " + RbConfig::CONFIG['sitearch']
90
+ SolarWindsAPM.logger.warn "arch: " + RbConfig::CONFIG['arch']
91
+ SolarWindsAPM.logger.warn RUBY_PLATFORM
92
+ SolarWindsAPM.logger.warn "RACK_ENV: #{ENV['RACK_ENV']}"
93
+ SolarWindsAPM.logger.warn "RAILS_ENV: #{ENV['RAILS_ENV']}" if using_rails
94
+
95
+ SolarWindsAPM.logger.warn '********************************************************'
96
+ SolarWindsAPM.logger.warn '* Raw __Init KVs'
97
+ SolarWindsAPM.logger.warn '********************************************************'
98
+ platform_info = SolarWindsAPM::Util.build_init_report
99
+ platform_info.each { |k,v|
100
+ SolarWindsAPM.logger.warn "#{k}: #{v}"
101
+ }
102
+
103
+ SolarWindsAPM.logger.warn '********************************************************'
104
+ SolarWindsAPM.logger.warn '* END SolarWindsAPM Support Report'
105
+ SolarWindsAPM.logger.warn '* Support Email: technicalsupport@solarwinds.com'
106
+ SolarWindsAPM.logger.warn '* Github: https://github.com/librato/ruby-solarwinds'
107
+ SolarWindsAPM.logger.warn '********************************************************'
108
+
109
+ SolarWindsAPM.logger.level = @logger_level
110
+ nil
111
+ end
112
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
113
+ end