solarwinds_apm 6.1.2 → 7.0.0.prev1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/lib/solarwinds_apm/api/current_trace_info.rb +10 -6
  4. data/lib/solarwinds_apm/api/custom_metrics.rb +8 -25
  5. data/lib/solarwinds_apm/api/tracing.rb +12 -27
  6. data/lib/solarwinds_apm/api/transaction_name.rb +6 -10
  7. data/lib/solarwinds_apm/config.rb +1 -1
  8. data/lib/solarwinds_apm/constants.rb +1 -0
  9. data/lib/solarwinds_apm/noop/api.rb +5 -2
  10. data/lib/solarwinds_apm/noop.rb +0 -24
  11. data/lib/solarwinds_apm/opentelemetry/otlp_processor.rb +90 -69
  12. data/lib/solarwinds_apm/opentelemetry/solarwinds_propagator.rb +0 -2
  13. data/lib/solarwinds_apm/opentelemetry/solarwinds_response_propagator.rb +5 -4
  14. data/lib/solarwinds_apm/opentelemetry.rb +5 -7
  15. data/lib/solarwinds_apm/otel_native_config.rb +177 -0
  16. data/lib/solarwinds_apm/patch/README.md +15 -0
  17. data/lib/solarwinds_apm/{noop/metadata.rb → sampling/dice.rb} +19 -17
  18. data/lib/solarwinds_apm/sampling/http_sampler.rb +87 -0
  19. data/lib/solarwinds_apm/sampling/json_sampler.rb +52 -0
  20. data/lib/solarwinds_apm/sampling/metrics.rb +38 -0
  21. data/lib/solarwinds_apm/sampling/oboe_sampler.rb +348 -0
  22. data/lib/solarwinds_apm/sampling/sampler.rb +197 -0
  23. data/lib/solarwinds_apm/sampling/sampling_constants.rb +127 -0
  24. data/lib/solarwinds_apm/sampling/sampling_patch.rb +49 -0
  25. data/lib/solarwinds_apm/sampling/setting_example.txt +1 -0
  26. data/lib/solarwinds_apm/{noop/context.rb → sampling/settings.rb} +14 -25
  27. data/lib/solarwinds_apm/sampling/token_bucket.rb +126 -0
  28. data/lib/solarwinds_apm/sampling/trace_options.rb +100 -0
  29. data/lib/solarwinds_apm/{patch.rb → sampling.rb} +20 -4
  30. data/lib/solarwinds_apm/{noop/span.rb → support/aws_resource_detector.rb} +5 -18
  31. data/lib/solarwinds_apm/support/logger_formatter.rb +1 -1
  32. data/lib/solarwinds_apm/support/logging_log_event.rb +1 -1
  33. data/lib/solarwinds_apm/support/lumberjack_formatter.rb +1 -1
  34. data/lib/solarwinds_apm/support/otlp_endpoint.rb +99 -0
  35. data/lib/solarwinds_apm/support/resource_detector/aws/beanstalk.rb +51 -0
  36. data/lib/solarwinds_apm/support/resource_detector/aws/ec2.rb +145 -0
  37. data/lib/solarwinds_apm/support/resource_detector/aws/ecs.rb +173 -0
  38. data/lib/solarwinds_apm/support/resource_detector/aws/eks.rb +174 -0
  39. data/lib/solarwinds_apm/support/resource_detector/aws/lambda.rb +66 -0
  40. data/lib/solarwinds_apm/support/resource_detector.rb +192 -0
  41. data/lib/solarwinds_apm/support/service_key_checker.rb +12 -6
  42. data/lib/solarwinds_apm/support/transaction_settings.rb +6 -0
  43. data/lib/solarwinds_apm/support/txn_name_manager.rb +54 -9
  44. data/lib/solarwinds_apm/support/utils.rb +9 -0
  45. data/lib/solarwinds_apm/support.rb +3 -4
  46. data/lib/solarwinds_apm/version.rb +4 -4
  47. data/lib/solarwinds_apm.rb +27 -73
  48. metadata +99 -40
  49. data/ext/oboe_metal/extconf.rb +0 -168
  50. data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +0 -1
  51. data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +0 -1
  52. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +0 -1
  53. data/ext/oboe_metal/lib/liboboe-1.0-lambda-aarch64.so.sha256 +0 -1
  54. data/ext/oboe_metal/lib/liboboe-1.0-lambda-x86_64.so.sha256 +0 -1
  55. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +0 -1
  56. data/ext/oboe_metal/src/VERSION +0 -1
  57. data/ext/oboe_metal/src/bson/bson.h +0 -220
  58. data/ext/oboe_metal/src/bson/platform_hacks.h +0 -91
  59. data/ext/oboe_metal/src/init_solarwinds_apm.cc +0 -18
  60. data/ext/oboe_metal/src/oboe.h +0 -930
  61. data/ext/oboe_metal/src/oboe_api.cpp +0 -793
  62. data/ext/oboe_metal/src/oboe_api.h +0 -621
  63. data/ext/oboe_metal/src/oboe_debug.h +0 -17
  64. data/ext/oboe_metal/src/oboe_swig_wrap.cc +0 -11045
  65. data/lib/oboe_metal.rb +0 -187
  66. data/lib/solarwinds_apm/cert/star.appoptics.com.issuer.crt +0 -24
  67. data/lib/solarwinds_apm/oboe_init_options.rb +0 -222
  68. data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +0 -239
  69. data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +0 -174
  70. data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +0 -333
  71. data/lib/solarwinds_apm/otel_config.rb +0 -174
  72. data/lib/solarwinds_apm/otel_lambda_config.rb +0 -56
  73. data/lib/solarwinds_apm/patch/dummy_patch.rb +0 -12
  74. data/lib/solarwinds_apm/support/oboe_tracing_mode.rb +0 -33
  75. data/lib/solarwinds_apm/support/support_report.rb +0 -99
  76. data/lib/solarwinds_apm/support/transaction_cache.rb +0 -57
  77. data/lib/solarwinds_apm/support/x_trace_options.rb +0 -138
data/lib/oboe_metal.rb DELETED
@@ -1,187 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # © 2023 SolarWinds Worldwide, LLC. All rights reserved.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:http://www.apache.org/licenses/LICENSE-2.0
6
- #
7
- # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
8
-
9
- # Disable docs and Camelcase warns since we're implementing
10
- # an interface here. See OboeBase for details.
11
- module SolarWindsAPM
12
- include Oboe_metal
13
-
14
- @loaded = false
15
- @reporter = nil
16
- @oboe_api = nil
17
- @init_sent = false
18
-
19
- class << self
20
- attr_accessor :reporter, :loaded, :oboe_api, :init_sent
21
-
22
- def sample_rate(rate)
23
- return unless SolarWindsAPM.loaded
24
-
25
- # Update liboboe with the new SampleRate value
26
- SolarWindsAPM::Context.setDefaultSampleRate(rate.to_i)
27
- end
28
- end
29
-
30
- # Reporter that send span data to SWO
31
- class Reporter
32
- class << self
33
- ##
34
- # start
35
- #
36
- # Start the SolarWindsAPM Reporter
37
- #
38
- def start
39
- options = SolarWindsAPM::OboeInitOptions.instance.array_for_oboe # creates an array with the options in the right order
40
- SolarWindsAPM.reporter = Oboe_metal::Reporter.new(*options)
41
- SolarWindsAPM.loaded = true
42
- report_init if (options[22]).zero? # report init at beginning if no after fork enabled
43
- rescue StandardError => e
44
- warn e.message
45
- SolarWindsAPM.loaded = false
46
- end
47
- alias restart start
48
-
49
- ##
50
- # sendReport
51
- #
52
- # Send the report for the given event
53
- #
54
- def send_report(evt, with_system_timestamp: true)
55
- SolarWindsAPM.reporter.sendReport(evt, with_system_timestamp)
56
- end
57
-
58
- ##
59
- # sendStatus
60
- #
61
- # Send the report for the given event
62
- #
63
- def send_status(evt, context = nil, with_system_timestamp: true)
64
- SolarWindsAPM.reporter.sendStatus(evt, context, with_system_timestamp)
65
- end
66
-
67
- private
68
-
69
- # Internal: Report that instrumentation for the given layer has been
70
- # installed, as well as the version of instrumentation and version of
71
- # layer.
72
- #
73
- def report_init(layer = :rack) # :nodoc:
74
- # Don't send __Init in test or if SolarWindsAPM isn't fully loaded (e.g. missing c-extension)
75
- # or if already sent (e.g. SolarWindsAPM.init_sent = true)
76
- return if SolarWindsAPM.init_sent
77
- return unless SolarWindsAPM.loaded
78
-
79
- platform_info = build_swo_init_report
80
- log_init(layer, platform_info)
81
-
82
- SolarWindsAPM.init_sent = true
83
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] Init message has been sent." }
84
- end
85
-
86
- ##
87
- # :nodoc:
88
- # Internal: Reports agent init to the collector
89
- #
90
- # ==== Arguments
91
- #
92
- # * +layer+ - The layer the reported event belongs to
93
- # * +kvs+ - A hash containing key/value pairs that will be reported along with this event
94
- def log_init(layer = :rack, kvs = {})
95
- context = SolarWindsAPM::Metadata.makeRandom
96
- return SolarWindsAPM::Context.toString unless context.isValid
97
-
98
- event = context.createEvent
99
- event.addInfo('Layer', layer.to_s)
100
- event.addInfo('Label', 'single')
101
- kvs.each do |k, v|
102
- event.addInfo(k, v.to_s)
103
- end
104
-
105
- SolarWindsAPM::Reporter.send_status(event, context, with_system_timestamp: true)
106
- SolarWindsAPM::Context.toString
107
- end
108
-
109
- ##
110
- # build_swo_init_report
111
- #
112
- # Internal: Build a hash of KVs that reports on the status of the
113
- # running environment for swo only. This is used on stack boot in __Init reporting
114
- # and for SolarWindsAPM.support_report.
115
- #
116
- def build_swo_init_report
117
- platform_info = { '__Init' => true }
118
-
119
- begin
120
- platform_info['APM.Version'] = SolarWindsAPM::Version::STRING
121
- platform_info['APM.Extension.Version'] = extension_lib_version
122
-
123
- # OTel Resource Attributes (Optional)
124
- platform_info['process.executable.path'] =
125
- File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
126
- platform_info['process.executable.name'] = RbConfig::CONFIG['ruby_install_name']
127
- platform_info['process.command_line'] = $PROGRAM_NAME
128
- platform_info['process.telemetry.path'] = Gem::Specification.find_by_name('solarwinds_apm')&.full_gem_path
129
- platform_info['os.type'] = RUBY_PLATFORM
130
-
131
- platform_info.merge!(report_gem_in_use)
132
-
133
- # Collect up opentelemetry sdk version (Instrumented Library Versions) (Required)
134
- begin
135
- require 'opentelemetry/sdk'
136
- ::OpenTelemetry::SDK::Resources::Resource.telemetry_sdk.attribute_enumerator.each do |k, v|
137
- platform_info[k] = v
138
- end
139
- ::OpenTelemetry::SDK::Resources::Resource.process.attribute_enumerator.each { |k, v| platform_info[k] = v }
140
- rescue StandardError => e
141
- SolarWindsAPM.logger.warn do
142
- "[#{self.class}/#{__method__}] Fail to extract telemetry attributes. Error: #{e.message}"
143
- end
144
- end
145
- rescue StandardError, ScriptError => e
146
- # Also rescue ScriptError (aka SyntaxError) in case one of the expected
147
- # version defines don't exist
148
-
149
- platform_info['Error'] = "Error in build_report: #{e.message}"
150
-
151
- SolarWindsAPM.logger.warn { "[#{self.class}/#{__method__}] Error in build_init_report: #{e.message}" }
152
- SolarWindsAPM.logger.debug { e.backtrace }
153
- end
154
- platform_info
155
- end
156
-
157
- ##
158
- # Collect up the loaded gems
159
- ##
160
- def report_gem_in_use
161
- platform_info = {}
162
- if defined?(Gem) && Gem.respond_to?(:loaded_specs)
163
- Gem.loaded_specs.each_pair { |k, v| platform_info["Ruby.#{k}.Version"] = v.version.to_s }
164
- else
165
- platform_info.merge!(legacy_build_init_report)
166
- end
167
- platform_info
168
- end
169
-
170
- ##
171
- # get extension library version by looking at the VERSION file
172
- # oboe not loaded yet, can't use oboe_api function to read oboe VERSION
173
- ##
174
- def extension_lib_version
175
- gem_location = Gem::Specification.find_by_name('solarwinds_apm')
176
- clib_version_file = File.join(gem_location&.gem_dir, 'ext', 'oboe_metal', 'src', 'VERSION')
177
- File.read(clib_version_file).strip
178
- end
179
- end
180
- end
181
- end
182
-
183
- # Setup an alias
184
- SolarWindsApm = SolarWindsAPM
185
- SolarwindsApm = SolarWindsAPM
186
- SolarwindsAPM = SolarWindsAPM
187
- Solarwindsapm = SolarWindsAPM
@@ -1,24 +0,0 @@
1
- -----BEGIN CERTIFICATE-----
2
- MIID8TCCAtmgAwIBAgIJAMoDz7Npas2/MA0GCSqGSIb3DQEBCwUAMIGOMQswCQYD
3
- VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j
4
- aXNjbzEVMBMGA1UECgwMTGlicmF0byBJbmMuMRUwEwYDVQQDDAxBcHBPcHRpY3Mg
5
- Q0ExJDAiBgkqhkiG9w0BCQEWFXN1cHBvcnRAYXBwb3B0aWNzLmNvbTAeFw0xNzA5
6
- MTUyMjAxMzlaFw0yNzA5MTMyMjAxMzlaMIGOMQswCQYDVQQGEwJVUzETMBEGA1UE
7
- CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEVMBMGA1UECgwM
8
- TGlicmF0byBJbmMuMRUwEwYDVQQDDAxBcHBPcHRpY3MgQ0ExJDAiBgkqhkiG9w0B
9
- CQEWFXN1cHBvcnRAYXBwb3B0aWNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
10
- ADCCAQoCggEBAOxO0wsGba3iI4r3L5BMST0rAO/gGaUhpQre6nRwVTmPCnLw1bmn
11
- GdiFgYv/oRRwU+VieumHSQqoOmyFrg+ajGmvUDp2WqQ0It+XhcbaHFiAp2H7+mLf
12
- cUH6S43/em0WUxZHeRzRupRDyO1bX6Hh2jgxykivlFrn5HCIQD5Hx1/SaZoW9v2n
13
- oATCbgFOiPW6kU/AVs4R0VBujon13HCehVelNKkazrAEBT1i6RvdOB6aQQ32seW+
14
- gLV5yVWSPEJvA9ZJqad/nQ8EQUMSSlVN191WOjp4bGpkJE1svs7NmM+Oja50W56l
15
- qOH5eWermr/8qWjdPlDJ+I0VkgN0UyHVuRECAwEAAaNQME4wHQYDVR0OBBYEFOuL
16
- KDTFhRQXwlBRxhPqhukrNYeRMB8GA1UdIwQYMBaAFOuLKDTFhRQXwlBRxhPqhukr
17
- NYeRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJQtH446NZhjusy6
18
- iCyvmnD95ybfNPDpjHmNx5n9Y6w9n+9y1o3732HUJE+WjvbLS3h1o7wujGKMcRJn
19
- 7I7eTDd26ZhLvnh5/AitYjdxrtUkQDgyxwLFJKhZu0ik2vXqj0fL961/quJL8Gyp
20
- hNj3Nf7WMohQMSohEmCCX2sHyZGVGYmQHs5omAtkH/NNySqmsWNcpgd3M0aPDRBZ
21
- 5VFreOSGKBTJnoLNqods/S9RV0by84hm3j6aQ/tMDIVE9VCJtrE6evzC0MWyVFwR
22
- ftgwcxyEq5SkiR+6BCwdzAMqADV37TzXDHLjwSrMIrgLV5xZM20Kk6chxI5QAr/f
23
- 7tsqAxw=
24
- -----END CERTIFICATE-----
@@ -1,222 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # © 2023 SolarWinds Worldwide, LLC. All rights reserved.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:http://www.apache.org/licenses/LICENSE-2.0
6
- #
7
- # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
8
-
9
- require 'singleton'
10
- require 'uri'
11
-
12
- require_relative 'support/service_key_checker'
13
-
14
- module SolarWindsAPM
15
- # OboeInitOptions
16
- class OboeInitOptions
17
- include Singleton
18
-
19
- attr_reader :reporter, :host, :service_name, :ec2_md_timeout, :grpc_proxy, :lambda_env # exposing these mainly for testing
20
-
21
- def initialize
22
- # determining the lambda env based on env var (not used in array_for_oboe for oboe initialization)
23
- @lambda_env = determine_lambda
24
- # optional hostname alias
25
- @hostname_alias = ENV['SW_APM_HOSTNAME_ALIAS'] || SolarWindsAPM::Config[:hostname_alias] || ''
26
- # level at which log messages will be written to log file (0-6)
27
- @debug_level = (ENV['SW_APM_DEBUG_LEVEL'] || SolarWindsAPM::Config[:debug_level] || 3).to_i
28
- # file name including path for log file
29
- # TODO eventually find better way to combine ruby and oboe logs
30
- @log_file_path = ENV['SW_APM_LOG_FILEPATH'] || ''
31
- # maximum number of transaction names to track
32
- @max_transactions = (ENV['SW_APM_MAX_TRANSACTIONS'] || -1).to_i
33
- # maximum wait time for flushing data before terminating in milli seconds
34
- @max_flush_wait_time = (ENV['SW_APM_FLUSH_MAX_WAIT_TIME'] || -1).to_i
35
- # events flush timeout in seconds (threshold for batching messages before sending off)
36
- @events_flush_interval = (ENV['SW_APM_EVENTS_FLUSH_INTERVAL'] || -1).to_i
37
- # events flush batch size in KB (threshold for batching messages before sending off)
38
- @event_flush_batch_size = (ENV['SW_APM_EVENTS_FLUSH_BATCH_SIZE'] || -1).to_i
39
-
40
- # the reporter to be used (ssl, upd, file, null)
41
- # collector endpoint (reporter=ssl), udp address (reporter=udp), or file path (reporter=file)
42
- @reporter, @host = reporter_and_host
43
-
44
- # the service key
45
- @service_key = read_and_validate_service_key
46
- # certificate content
47
- @certificates = read_certificates
48
- # size of the message buffer
49
- @buffer_size = (ENV['SW_APM_BUFSIZE'] || -1).to_i
50
- # flag indicating if trace metrics reporting should be enabled (default) or disabled
51
- @trace_metrics = (ENV['SW_APM_TRACE_METRICS'] || -1).to_i
52
- # the histogram precision (only for ssl)
53
- @histogram_precision = (ENV['SW_APM_HISTOGRAM_PRECISION'] || -1).to_i
54
- # custom token bucket capacity
55
- @token_bucket_capacity = (ENV['SW_APM_TOKEN_BUCKET_CAPACITY'] || -1).to_i
56
- # custom token bucket rate
57
- @token_bucket_rate = (ENV['SW_APM_TOKEN_BUCKET_RATE'] || -1).to_i
58
- # use single files in file reporter for each event
59
- @file_single = ENV['SW_APM_REPORTER_FILE_SINGLE'].to_s.casecmp('true').zero? ? 1 : 0
60
- # timeout for ec2 metadata
61
- @ec2_md_timeout = read_and_validate_ec2_md_timeout
62
- @grpc_proxy = read_and_validate_proxy
63
- # hardcoded arg for lambda (lambda not supported yet)
64
- # hardcoded arg for grpc hack
65
- # hardcoded arg for trace id format to use w3c format
66
- # flag for format of metric (0 = Both; 1 = AppOptics only; 2 = SWO only; default = 0)
67
- @metric_format = determine_the_metric_model
68
- # log type (0 = stderr; 1 = stdout; 2 = file; 3 = null; 4 = disabled; default = 0)
69
- @log_type = determine_oboe_log_type
70
- # after fork enablement (0 = disable; 1 = enabled, parent process will not init oboe but fork child process will init oboe; default = 0)
71
- @after_fork = determine_oboe_after_fork
72
- end
73
-
74
- # for testing with changed ENV vars
75
- def re_init
76
- initialize
77
- end
78
-
79
- def array_for_oboe
80
- [
81
- @hostname_alias, # 0
82
- @debug_level, # 1
83
- @log_file_path, # 2
84
- @max_transactions, # 3
85
- @max_flush_wait_time, # 4
86
- @events_flush_interval, # 5
87
- @event_flush_batch_size, # 6
88
- @reporter, # 7
89
- @host, # 8
90
- @service_key, # 9
91
- @certificates, # 10
92
- @buffer_size, # 11
93
- @trace_metrics, # 12
94
- @histogram_precision, # 13
95
- @token_bucket_capacity, # 14
96
- @token_bucket_rate, # 15
97
- @file_single, # 16
98
- @ec2_md_timeout, # 17
99
- @grpc_proxy, # 18
100
- 0, # 19 arg for lambda (no lambda for ruby yet)
101
- @metric_format, # 20
102
- @log_type, # 21
103
- @after_fork # 22
104
- ]
105
- end
106
-
107
- def service_key_ok?
108
- !@service_key.empty? || @reporter != 'ssl'
109
- end
110
-
111
- private
112
-
113
- def reporter_and_host
114
- reporter = ENV['SW_APM_REPORTER'] || 'ssl'
115
-
116
- host = case reporter
117
- when 'ssl', 'file'
118
- ENV['SW_APM_COLLECTOR'] || ''
119
- else
120
- ''
121
- end
122
-
123
- host = sanitize_collector_uri(host) unless reporter == 'file'
124
- [reporter, host]
125
- end
126
-
127
- def read_and_validate_service_key
128
- service_key_checker = SolarWindsAPM::ServiceKeyChecker.new(@reporter, @lambda_env)
129
- service_key = service_key_checker.read_and_validate_service_key
130
- @service_name = service_key.split(':', 2).last # instance variable used in testing
131
- service_key
132
- end
133
-
134
- def read_and_validate_ec2_md_timeout
135
- timeout = ENV['SW_APM_EC2_METADATA_TIMEOUT'] || SolarWindsAPM::Config[:ec2_metadata_timeout]
136
- return 1000 unless timeout.is_a?(Integer) || timeout =~ /^\d+$/
137
-
138
- timeout = timeout.to_i
139
- timeout.between?(0, 3000) ? timeout : 1000
140
- end
141
-
142
- def read_and_validate_proxy
143
- proxy = ENV['SW_APM_PROXY'] || SolarWindsAPM::Config[:http_proxy] || ''
144
- return proxy if proxy == ''
145
-
146
- unless %r{http://.*:\d+$}.match?(proxy)
147
- SolarWindsAPM.logger.error { "[#{self.class}/#{__method__}] SW_APM_PROXY/http_proxy doesn't start with 'http://', #{proxy}" }
148
- return '' # try without proxy, it may work, shouldn't crash but may not report
149
- end
150
-
151
- proxy
152
- end
153
-
154
- def read_certificates
155
- certificate = ''
156
-
157
- file = appoptics_collector? ? "#{__dir__}/cert/star.appoptics.com.issuer.crt" : ENV.fetch('SW_APM_TRUSTEDPATH', nil)
158
- return certificate if file.nil? || file&.empty?
159
-
160
- begin
161
- certificate = File.read(file)
162
- rescue StandardError => e
163
- SolarWindsAPM.logger.error do
164
- "[#{self.class}/#{__method__}] certificates: #{file} doesn't exist or caused by #{e.message}."
165
- end
166
- end
167
-
168
- certificate
169
- end
170
-
171
- def determine_the_metric_model
172
- appoptics_collector? ? 1 : 2
173
- end
174
-
175
- def appoptics_collector?
176
- allowed_uri = ['collector.appoptics.com', 'collector-stg.appoptics.com',
177
- 'collector.appoptics.com:443', 'collector-stg.appoptics.com:443']
178
-
179
- (allowed_uri.include? ENV.fetch('SW_APM_COLLECTOR', nil))
180
- end
181
-
182
- def java_collector?(uri)
183
- java_collector_regex = /java-collector:\d+/
184
- uri.match?(java_collector_regex)
185
- end
186
-
187
- def sanitize_collector_uri(uri)
188
- return uri if uri.nil? || uri.empty?
189
- return uri if java_collector?(uri)
190
-
191
- begin
192
- sanitized_uri = ::URI.parse("http://#{uri}").host
193
- return sanitized_uri unless sanitized_uri.nil?
194
- rescue StandardError => e
195
- SolarWindsAPM.logger.error do
196
- "[#{self.class}/#{__method__}] uri for collector #{uri} is malformat. Error: #{e.message}"
197
- end
198
- end
199
- ''
200
- end
201
-
202
- def determine_oboe_log_type
203
- log_type = 0
204
- log_type = 2 unless ENV['SW_APM_LOG_FILEPATH'].to_s.empty?
205
- log_type = 4 if @debug_level == -1
206
- log_type
207
- end
208
-
209
- def determine_lambda
210
- if ENV['LAMBDA_TASK_ROOT'].to_s.empty? && ENV['AWS_LAMBDA_FUNCTION_NAME'].to_s.empty?
211
- false
212
- else
213
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] lambda environment - LAMBDA_TASK_ROOT: #{ENV.fetch('LAMBDA_TASK_ROOT', nil)}; AWS_LAMBDA_FUNCTION_NAME: #{ENV.fetch('AWS_LAMBDA_FUNCTION_NAME', nil)}" }
214
- true
215
- end
216
- end
217
-
218
- def determine_oboe_after_fork
219
- ENV['SW_APM_ENABLE_AFTER_FORK'].to_s == 'true' ? 1 : 0
220
- end
221
- end
222
- end
@@ -1,239 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # © 2023 SolarWinds Worldwide, LLC. All rights reserved.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:http://www.apache.org/licenses/LICENSE-2.0
6
- #
7
- # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
8
-
9
- module SolarWindsAPM
10
- module OpenTelemetry
11
- # SolarWindsExporter
12
- class SolarWindsExporter
13
- SUCCESS = ::OpenTelemetry::SDK::Trace::Export::SUCCESS # ::OpenTelemetry #=> the OpenTelemetry at top level (to ignore SolarWindsAPM)
14
- FAILURE = ::OpenTelemetry::SDK::Trace::Export::FAILURE
15
-
16
- private_constant(:SUCCESS, :FAILURE)
17
-
18
- def initialize(txn_manager: nil)
19
- @shutdown = false
20
- @txn_manager = txn_manager
21
- @reporter = SolarWindsAPM::Reporter
22
- @context = SolarWindsAPM::Context
23
- @metadata = SolarWindsAPM::Metadata
24
- @version_cache = {}
25
- end
26
-
27
- def export(span_data, timeout: nil) # rubocop:disable Lint/UnusedMethodArgument
28
- return FAILURE if @shutdown
29
-
30
- status = SUCCESS
31
- span_data.each do |data|
32
- status = log_span_data(data)
33
- end
34
-
35
- status
36
- end
37
-
38
- def force_flush(timeout: nil) # rubocop:disable Lint/UnusedMethodArgument
39
- SUCCESS
40
- end
41
-
42
- def shutdown(timeout: nil) # rubocop:disable Lint/UnusedMethodArgument
43
- @shutdown = true
44
- SUCCESS
45
- end
46
-
47
- private
48
-
49
- def log_span_data(span_data)
50
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] span_data: #{span_data.inspect}\n" }
51
-
52
- md = build_meta_data(span_data)
53
- event = nil
54
- if span_data.parent_span_id == ::OpenTelemetry::Trace::INVALID_SPAN_ID
55
- event = @context.createEntry(md, (span_data.start_timestamp.to_i / 1000).to_i)
56
- add_info_transaction_name(span_data, event)
57
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] Start a new trace." }
58
- else
59
- parent_md = build_meta_data(span_data, parent: true)
60
- event = @context.createEntry(md, (span_data.start_timestamp.to_i / 1000).to_i, parent_md)
61
- SolarWindsAPM.logger.debug do
62
- "[#{self.class}/#{__method__}] Continue trace from parent metadata: #{parent_md.toString}."
63
- end
64
- end
65
-
66
- layer_name = "#{span_data.kind}:#{span_data.name}"
67
- event.addInfo('Layer', layer_name)
68
- event.addInfo('sw.span_kind', span_data.kind.to_s)
69
- event.addInfo('Language', 'Ruby')
70
-
71
- add_instrumentation_scope(event, span_data)
72
- add_instrumented_framework(event, span_data)
73
- add_span_data_attributes(event, span_data.attributes) if span_data.attributes
74
-
75
- event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_STATUS, span_data.status.ok? ? 'OK' : 'ERROR')
76
- unless span_data.status.description.empty?
77
- event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_STATUS_DESCRIPTION,
78
- span_data.status.description)
79
- end
80
-
81
- @reporter.send_report(event, with_system_timestamp: false)
82
-
83
- # info / exception event
84
- span_data.events&.each do |span_data_event|
85
- span_data_event.name == 'exception' ? report_exception_event(span_data_event) : report_info_event(span_data_event)
86
- end
87
-
88
- event = @context.createExit((span_data.end_timestamp.to_i / 1000).to_i)
89
- event.addInfo('Layer', layer_name)
90
- @reporter.send_report(event, with_system_timestamp: false)
91
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] Exit a trace: #{event.metadataString}" }
92
- SUCCESS
93
- rescue StandardError => e
94
- SolarWindsAPM.logger.info { "[#{self.class}/#{__method__}] exporter error: \n #{e.message} #{e.backtrace}\n" }
95
- FAILURE
96
- end
97
-
98
- ##
99
- # extract the span_data.attributes (OpenTelemetry::SDK::Trace::SpanData.attributes)
100
- def add_span_data_attributes(event, span_attributes)
101
- target = 'http.target'
102
- attributes = span_attributes.dup
103
- attributes[target] = attributes[target].split('?').first if attributes[target] && SolarWindsAPM::Config[:log_args] == false
104
- attributes.each { |k, v| event.addInfo(k, v) }
105
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] span_data attributes added: #{attributes.inspect}" }
106
- end
107
-
108
- ##
109
- # get instrumentation scope data: scope name and version.
110
- # the version if the opentelemetry-instrumentation-* gem version
111
- def add_instrumentation_scope(event, span_data)
112
- scope_name = ''
113
- scope_version = ''
114
- if span_data.instrumentation_scope
115
- scope_name = span_data.instrumentation_scope.name if span_data.instrumentation_scope.name
116
- scope_version = span_data.instrumentation_scope.version if span_data.instrumentation_scope.version
117
- end
118
- event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_SCOPE_NAME, scope_name)
119
- event.addInfo(SolarWindsAPM::Constants::INTL_SWO_OTEL_SCOPE_VERSION, scope_version)
120
- end
121
-
122
- ##
123
- # add the gem library version to event
124
- # p.s. gem library version is not same as the opentelemetry-instrumentation-* gem version
125
- def add_instrumented_framework(event, span_data)
126
- scope_name = span_data.instrumentation_scope.name
127
- scope_name = scope_name.downcase if scope_name
128
- return unless scope_name&.include? 'opentelemetry::instrumentation'
129
-
130
- framework = scope_name.split('::')[2..]&.join('::')
131
- return if framework.nil? || framework.empty?
132
-
133
- framework = normalize_framework_name(framework)
134
- framework_version = check_framework_version(framework)
135
- SolarWindsAPM.logger.debug do
136
- "[#{self.class}/#{__method__}] #{span_data.instrumentation_scope.name} with #{framework} and version #{framework_version}"
137
- end
138
- event.addInfo("Ruby.#{framework}.Version", framework_version) unless framework_version.nil?
139
- end
140
-
141
- ##
142
- # helper function that extract gem library version for func add_instrumented_framework
143
- def check_framework_version(framework)
144
- framework_version = nil
145
- if @version_cache.key?(framework)
146
-
147
- framework_version = @version_cache[framework]
148
- else
149
-
150
- begin
151
- require framework
152
- framework_version = Gem.loaded_specs[version_framework_name(framework)].version.to_s
153
- rescue LoadError => e
154
- SolarWindsAPM.logger.debug do
155
- "[#{self.class}/#{__method__}] couldn't load #{framework} with error #{e.message}; skip"
156
- end
157
- rescue StandardError => e
158
- SolarWindsAPM.logger.debug do
159
- "[#{self.class}/#{__method__}] couldn't find #{framework} with error #{e.message}; skip"
160
- end
161
- ensure
162
- @version_cache[framework] = framework_version
163
- end
164
- end
165
- SolarWindsAPM.logger.debug do
166
- "[#{self.class}/#{__method__}] current framework version cached: #{@version_cache.inspect}"
167
- end
168
- framework_version
169
- end
170
-
171
- ##
172
- # helper function that convert opentelemetry instrumentation name to gem library understandable
173
- def normalize_framework_name(framework)
174
- case framework
175
- when 'net::http'
176
- 'net/http'
177
- else
178
- framework
179
- end
180
- end
181
-
182
- ##
183
- # helper function that convert opentelemetry instrumentation name to gem library understandable
184
- def version_framework_name(framework)
185
- case framework
186
- when 'net/http'
187
- 'net-http'
188
- else
189
- framework
190
- end
191
- end
192
-
193
- ##
194
- # Add transaction name from cache to root span then removes from cache
195
- def add_info_transaction_name(span_data, event)
196
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] transaction manager: #{@txn_manager.inspect}." }
197
- trace_span_id = "#{span_data.hex_trace_id}-#{span_data.hex_span_id}"
198
- txname = @txn_manager.get(trace_span_id) || ''
199
- event.addInfo('TransactionName', txname)
200
- @txn_manager.del(trace_span_id)
201
- end
202
-
203
- ##
204
- # report exception event
205
- def report_exception_event(span_event)
206
- event = @context.createEvent((span_event.timestamp.to_i / 1000).to_i)
207
- event.addInfo('Label', 'error')
208
- event.addInfo('Spec', 'error')
209
-
210
- unless span_event.attributes.nil?
211
- attributes = span_event.attributes.dup
212
- attributes.delete('exception.type') if event.addInfo('ErrorClass', attributes['exception.type'])
213
- attributes.delete('exception.message') if event.addInfo('ErrorMsg', attributes['exception.message'])
214
- attributes.delete('exception.stacktrace') if event.addInfo('Backtrace', attributes['exception.stacktrace'])
215
- attributes.each { |key, value| event.addInfo(key, value) }
216
- end
217
-
218
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] exception event #{event.metadataString}" }
219
- @reporter.send_report(event, with_system_timestamp: false)
220
- end
221
-
222
- ##
223
- # report non-exception/info event
224
- def report_info_event(span_event)
225
- event = @context.createEvent((span_event.timestamp.to_i / 1000).to_i)
226
- event.addInfo('Label', 'info')
227
- span_event.attributes&.each { |key, value| event.addInfo(key, value) }
228
- SolarWindsAPM.logger.debug { "[#{self.class}/#{__method__}] info event #{event.metadataString}" }
229
- @reporter.send_report(event, with_system_timestamp: false)
230
- end
231
-
232
- def build_meta_data(span_data, parent: false)
233
- flag = span_data.trace_flags.sampled? ? 1 : 0
234
- xtr = parent == false ? "00-#{span_data.hex_trace_id}-#{span_data.hex_span_id}-0#{flag}" : "00-#{span_data.hex_trace_id}-#{span_data.hex_parent_span_id}-0#{flag}"
235
- @metadata.fromString(xtr)
236
- end
237
- end
238
- end
239
- end