solarwinds_apm 6.0.0.preV5 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/ext/oboe_metal/extconf.rb +5 -4
  3. data/ext/oboe_metal/lib/liboboe-1.0-aarch64.so.sha256 +1 -1
  4. data/ext/oboe_metal/lib/liboboe-1.0-alpine-aarch64.so.sha256 +1 -1
  5. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.sha256 +1 -1
  6. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.sha256 +1 -1
  7. data/ext/oboe_metal/src/VERSION +1 -1
  8. data/ext/oboe_metal/src/oboe.h +56 -13
  9. data/ext/oboe_metal/src/oboe_api.cpp +105 -6
  10. data/ext/oboe_metal/src/oboe_api.h +121 -2
  11. data/ext/oboe_metal/src/oboe_debug.h +4 -315
  12. data/ext/oboe_metal/src/oboe_swig_wrap.cc +2987 -549
  13. data/lib/oboe_metal.rb +23 -64
  14. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +1 -1
  15. data/lib/solarwinds_apm/api/current_trace_info.rb +2 -3
  16. data/lib/solarwinds_apm/api/opentelemetry.rb +2 -2
  17. data/lib/solarwinds_apm/api/tracing.rb +1 -1
  18. data/lib/solarwinds_apm/api.rb +1 -1
  19. data/lib/solarwinds_apm/config.rb +56 -17
  20. data/lib/solarwinds_apm/constants.rb +5 -7
  21. data/lib/solarwinds_apm/noop/README.md +1 -1
  22. data/lib/solarwinds_apm/noop/api.rb +83 -0
  23. data/lib/solarwinds_apm/noop/context.rb +13 -2
  24. data/lib/solarwinds_apm/noop/metadata.rb +5 -2
  25. data/lib/solarwinds_apm/{thread_local.rb → noop/span.rb} +14 -20
  26. data/lib/solarwinds_apm/{base.rb → noop.rb} +22 -27
  27. data/lib/solarwinds_apm/oboe_init_options.rb +23 -82
  28. data/lib/solarwinds_apm/opentelemetry/solarwinds_exporter.rb +1 -1
  29. data/lib/solarwinds_apm/opentelemetry/solarwinds_processor.rb +2 -2
  30. data/lib/solarwinds_apm/opentelemetry/solarwinds_sampler.rb +4 -3
  31. data/lib/solarwinds_apm/opentelemetry.rb +1 -1
  32. data/lib/solarwinds_apm/otel_config.rb +14 -43
  33. data/lib/solarwinds_apm/patch/dummy_patch.rb +12 -0
  34. data/lib/solarwinds_apm/patch.rb +11 -0
  35. data/lib/solarwinds_apm/support/logger_formatter.rb +1 -1
  36. data/lib/solarwinds_apm/support/oboe_tracing_mode.rb +20 -22
  37. data/lib/solarwinds_apm/support/service_key_checker.rb +94 -0
  38. data/lib/solarwinds_apm/{support_report.rb → support/support_report.rb} +11 -8
  39. data/lib/solarwinds_apm/support/swomarginalia/comment.rb +2 -2
  40. data/lib/solarwinds_apm/support/swomarginalia/swomarginalia.rb +1 -1
  41. data/lib/solarwinds_apm/support/transaction_settings.rb +1 -5
  42. data/lib/solarwinds_apm/support.rb +1 -0
  43. data/lib/solarwinds_apm/version.rb +1 -1
  44. data/lib/solarwinds_apm.rb +70 -55
  45. metadata +12 -7
@@ -7,6 +7,8 @@
7
7
  require 'singleton'
8
8
  require 'uri'
9
9
 
10
+ require_relative './support/service_key_checker'
11
+
10
12
  module SolarWindsAPM
11
13
  # OboeInitOptions
12
14
  class OboeInitOptions
@@ -21,7 +23,7 @@ module SolarWindsAPM
21
23
  @debug_level = (ENV['SW_APM_DEBUG_LEVEL'] || SolarWindsAPM::Config[:debug_level] || 3).to_i
22
24
  # file name including path for log file
23
25
  # TODO eventually find better way to combine ruby and oboe logs
24
- @log_file_path = ENV['SW_APM_LOGFILE'] || ''
26
+ @log_file_path = ENV['SW_APM_LOG_FILEPATH'] || ''
25
27
  # maximum number of transaction names to track
26
28
  @max_transactions = (ENV['SW_APM_MAX_TRANSACTIONS'] || -1).to_i
27
29
  # maximum wait time for flushing data before terminating in milli seconds
@@ -50,7 +52,7 @@ module SolarWindsAPM
50
52
  # custom token bucket rate
51
53
  @token_bucket_rate = (ENV['SW_APM_TOKEN_BUCKET_RATE'] || -1).to_i
52
54
  # use single files in file reporter for each event
53
- @file_single = ENV['SW_APM_REPORTER_FILE_SINGLE'].to_s.downcase == 'true' ? 1 : 0
55
+ @file_single = ENV['SW_APM_REPORTER_FILE_SINGLE'].to_s.casecmp('true').zero? ? 1 : 0
54
56
  # timeout for ec2 metadata
55
57
  @ec2_md_timeout = read_and_validate_ec2_md_timeout
56
58
  @grpc_proxy = read_and_validate_proxy
@@ -59,6 +61,8 @@ module SolarWindsAPM
59
61
  # hardcoded arg for trace id format to use w3c format
60
62
  # flag for format of metric (0 = Both; 1 = AppOptics only; 2 = SWO only; default = 0)
61
63
  @metric_format = determine_the_metric_model
64
+ # log type (0 = stderr; 1 = stdout; 2 = file; 3 = null; 4 = disabled; default = 0)
65
+ @log_type = determine_oboe_log_type
62
66
  end
63
67
 
64
68
  # for testing with changed ENV vars
@@ -75,7 +79,6 @@ module SolarWindsAPM
75
79
  @max_flush_wait_time, # 4
76
80
  @events_flush_interval, # 5
77
81
  @event_flush_batch_size, # 6
78
-
79
82
  @reporter, # 7
80
83
  @host, # 8
81
84
  @service_key, # 9
@@ -89,7 +92,8 @@ module SolarWindsAPM
89
92
  @ec2_md_timeout, #17
90
93
  @grpc_proxy, #18
91
94
  0, #19 arg for lambda (no lambda for ruby yet)
92
- @metric_format #22
95
+ @metric_format, #20
96
+ @log_type #21
93
97
  ]
94
98
  end
95
99
 
@@ -123,81 +127,10 @@ module SolarWindsAPM
123
127
  end
124
128
 
125
129
  def read_and_validate_service_key
126
- return '' unless @reporter == 'ssl'
127
-
128
- service_key = ENV['SW_APM_SERVICE_KEY'] || SolarWindsAPM::Config[:service_key]
129
- if service_key.nil? || service_key == ''
130
- SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY not configured."}
131
- return ''
132
- end
133
-
134
- match = service_key.match(/([^:]+)(:{0,1})(.*)/)
135
- token = match[1]
136
- service_name = match[3]
137
-
138
- return '' unless validate_token(token) # return if token is not even valid
139
-
140
- if service_name.empty?
141
- ENV.delete('OTEL_SERVICE_NAME')
142
- SolarWindsAPM.logger.warn {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY format problem. Service Name is missing."}
143
- return ''
144
- end
145
-
146
- # check OTEL_RESOURCE_ATTRIBUTES
147
- otel_resource_service_name = nil
148
- ENV['OTEL_RESOURCE_ATTRIBUTES']&.split(',')&.each do |pair|
149
- key, value = pair.split('=')
150
- if key == 'service.name'
151
- otel_resource_service_name = value
152
- break
153
- end
154
- end
155
-
156
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] provided otel_resource_service_name #{otel_resource_service_name}"} if otel_resource_service_name
157
- service_name = otel_resource_service_name if otel_resource_service_name && validate_transform_service_name(otel_resource_service_name)
158
-
159
- # check OTEL_SERVICE_NAME
160
- otel_service_name = ENV['OTEL_SERVICE_NAME']
161
- if otel_service_name && validate_transform_service_name(otel_service_name)
162
- service_name = otel_service_name
163
- SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] provided otel_service_name #{otel_service_name}"}
164
- elsif ENV['OTEL_SERVICE_NAME'].nil?
165
- ENV['OTEL_SERVICE_NAME'] = service_name
166
- end
167
-
168
- return '' unless validate_transform_service_name(service_name)
169
-
170
- "#{token}:#{service_name}"
171
- end
172
-
173
- def validate_token(token)
174
- if (token !~ /^[0-9a-zA-Z_-]{71}$/) && ENV['SW_APM_COLLECTOR'] !~ /java-collector:1222/
175
- masked = "#{token[0..3]}...#{token[-4..]}"
176
- SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY problem. API Token in wrong format. Masked token: #{masked}"}
177
- return false
178
- end
179
-
180
- true
181
- end
182
-
183
- def validate_transform_service_name(service_name)
184
- service_name = 'test_ssl_collector' if ENV['SW_APM_COLLECTOR'] =~ /java-collector:1222/
185
- if service_name.empty?
186
- SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY problem. Service Name is missing"}
187
- return false
188
- end
189
-
190
- name = service_name.dup
191
- name.downcase!
192
- name.gsub!(/[^a-z0-9.:_-]/, '')
193
- name = name[0..254]
194
-
195
- if name != service_name
196
- SolarWindsAPM.logger.warn {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY problem. Service Name transformed from #{service_name} to #{name}"}
197
- service_name = name
198
- end
199
- @service_name = service_name # instance variable used in testing
200
- true
130
+ service_key_checker = SolarWindsAPM::ServiceKeyChecker.new(@reporter)
131
+ service_key = service_key_checker.read_and_validate_service_key
132
+ @service_name = service_key.split(':',2).last # instance variable used in testing
133
+ service_key
201
134
  end
202
135
 
203
136
  def read_and_validate_ec2_md_timeout
@@ -212,7 +145,7 @@ module SolarWindsAPM
212
145
  proxy = ENV['SW_APM_PROXY'] || SolarWindsAPM::Config[:http_proxy] || ''
213
146
  return proxy if proxy == ''
214
147
 
215
- unless proxy =~ /http:\/\/.*:\d+$/
148
+ unless /http:\/\/.*:\d+$/.match?(proxy)
216
149
  SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_PROXY/http_proxy doesn't start with 'http://', #{proxy}"}
217
150
  return '' # try without proxy, it may work, shouldn't crash but may not report
218
151
  end
@@ -221,14 +154,15 @@ module SolarWindsAPM
221
154
  end
222
155
 
223
156
  def read_certificates
157
+ certificate = ''
158
+
224
159
  file = appoptics_collector?? "#{__dir__}/cert/star.appoptics.com.issuer.crt" : ENV['SW_APM_TRUSTEDPATH']
225
- return String.new if file.nil? || file&.empty?
160
+ return certificate if file.nil? || file&.empty?
226
161
 
227
162
  begin
228
163
  certificate = File.open(file,"r").read
229
164
  rescue StandardError => e
230
165
  SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] certificates: #{file} doesn't exist or caused by #{e.message}."}
231
- certificate = String.new
232
166
  end
233
167
 
234
168
  certificate
@@ -256,5 +190,12 @@ module SolarWindsAPM
256
190
  end
257
191
  ""
258
192
  end
193
+
194
+ def determine_oboe_log_type
195
+ log_type = 0
196
+ log_type = 2 unless ENV['SW_APM_LOG_FILEPATH'].to_s.empty?
197
+ log_type = 4 if @debug_level == -1
198
+ log_type
199
+ end
259
200
  end
260
201
  end
@@ -133,7 +133,7 @@ module SolarWindsAPM
133
133
  # helper function that extract gem library version for func add_instrumented_framework
134
134
  def check_framework_version(framework)
135
135
  framework_version = nil
136
- if @version_cache.keys.include? framework
136
+ if @version_cache.has_key?(framework)
137
137
 
138
138
  framework_version = @version_cache[framework]
139
139
  else
@@ -131,7 +131,7 @@ module SolarWindsAPM
131
131
 
132
132
  # This span from inbound HTTP request if from a SERVER by some http.method
133
133
  def span_http?(span)
134
- (span.kind == ::OpenTelemetry::Trace::SpanKind::SERVER && !span.attributes[HTTP_METHOD].nil?)
134
+ span.kind == ::OpenTelemetry::Trace::SpanKind::SERVER && !span.attributes[HTTP_METHOD].nil?
135
135
  end
136
136
 
137
137
  # Calculate if this span instance has_error
@@ -173,4 +173,4 @@ module SolarWindsAPM
173
173
  end
174
174
  end
175
175
  end
176
- end
176
+ end
@@ -102,7 +102,7 @@ module SolarWindsAPM
102
102
  end
103
103
 
104
104
  sw_member_value = parent_span_context.tracestate[SolarWindsAPM::Constants::INTL_SWO_TRACESTATE_KEY]
105
- trigger_trace_mode = OboeTracingMode.get_oboe_trigger_trace_mode(@config["trigger_trace"])
105
+ trigger_trace_mode = SolarWindsAPM::OboeTracingMode.get_oboe_trigger_trace_mode(@config["trigger_trace"])
106
106
  sample_rate = UNSET
107
107
  options = xtraceoptions&.options
108
108
  trigger_trace = xtraceoptions&.intify_trigger_trace || 0
@@ -272,7 +272,8 @@ module SolarWindsAPM
272
272
  SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] trace_state_no_response #{trace_state_no_response.inspect}"}
273
273
 
274
274
  trace_state_no_response = parent_span_context.tracestate.delete(XTraceOptions.sw_xtraceoptions_response_key)
275
- no_sw_count = trace_state_no_response.to_h.reject { |k, _v| k == "sw" }.count
275
+ no_sw_count = trace_state_no_response.to_h.count { |k, _v| k != 'sw' }
276
+
276
277
  new_attributes[SW_TRACESTATE_CAPTURE_KEY] = Utils.trace_state_header(trace_state_no_response) if no_sw_count > 0
277
278
  SolarWindsAPM.logger.debug {"[#{self.class}/#{__method__}] new_attributes after add_tracestate_capture_to_new_attributes: #{new_attributes.inspect}"}
278
279
 
@@ -290,4 +291,4 @@ module SolarWindsAPM
290
291
  end
291
292
  end
292
293
  end
293
- end
294
+ end
@@ -11,4 +11,4 @@ require_relative './opentelemetry/solarwinds_propagator'
11
11
  require_relative './opentelemetry/solarwinds_processor'
12
12
  require_relative './opentelemetry/solarwinds_sampler'
13
13
  require_relative './opentelemetry/solarwinds_exporter'
14
- require_relative './opentelemetry/solarwinds_response_propagator'
14
+ require_relative './opentelemetry/solarwinds_response_propagator'
@@ -22,27 +22,13 @@ module SolarWindsAPM
22
22
  SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] Agent disabled. No Trace exported."}
23
23
  end
24
24
 
25
- def self.validate_service_key
26
- return unless (ENV['SW_APM_REPORTER'] || 'ssl') == 'ssl'
27
-
28
- disable_agent unless ENV['SW_APM_SERVICE_KEY'] || SolarWindsAPM::Config[:service_key]
29
- end
30
-
31
25
  def self.resolve_sampler
32
-
33
- resolve_sampler_config
26
+ sampler_config = {"trigger_trace" => SolarWindsAPM::Config[:trigger_tracing_mode]}
34
27
  @@config[:sampler] =
35
28
  ::OpenTelemetry::SDK::Trace::Samplers.parent_based(
36
- root: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(@@config[:sampler_config]),
37
- remote_parent_sampled: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(@@config[:sampler_config]),
38
- remote_parent_not_sampled: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(@@config[:sampler_config]))
39
- end
40
-
41
- def self.resolve_sampler_config
42
- sampler_config = {}
43
- sampler_config["trigger_trace"] = "enabled"
44
- sampler_config["trigger_trace"] = nil if ENV["SW_APM_TRIGGER_TRACING_MODE"] == 'disabled'
45
- @@config[:sampler_config] = sampler_config
29
+ root: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(sampler_config),
30
+ remote_parent_sampled: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(sampler_config),
31
+ remote_parent_not_sampled: SolarWindsAPM::OpenTelemetry::SolarWindsSampler.new(sampler_config))
46
32
  end
47
33
 
48
34
  #
@@ -65,31 +51,18 @@ module SolarWindsAPM
65
51
  end
66
52
  end
67
53
 
68
- def self.obfuscate_helper(instrumentation)
69
- if @@config_map[instrumentation] # user provided the option
70
- @@config_map[instrumentation][:db_statement] = :obfuscate unless @@config_map[instrumentation][:db_statement] # user provided the db_statement, ignore our default setting
71
- else
72
- @@config_map[instrumentation] = {db_statement: :obfuscate}
73
- end
74
- end
75
-
76
- def self.obfuscate_query
77
- obfuscate_helper("OpenTelemetry::Instrumentation::Dalli")
78
- obfuscate_helper("OpenTelemetry::Instrumentation::Mysql2")
79
- obfuscate_helper("OpenTelemetry::Instrumentation::PG")
80
- end
81
-
82
54
  def self.[](key)
83
55
  @@config[key.to_sym]
84
56
  end
85
57
 
86
58
  def self.print_config
87
- @@config.each do |config, value|
88
- SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] config: #{config} = #{value}"}
59
+ @@config.each do |k,v|
60
+ SolarWindsAPM.logger.debug {"[#{name}/#{__method__}] Config Key/Value: #{k}, #{v.class}"}
89
61
  end
90
- @@config_map.each do |config, value|
91
- SolarWindsAPM.logger.warn {"[#{name}/#{__method__}] config_map: #{config} = #{value}"}
62
+ @@config_map.each do |k,v|
63
+ SolarWindsAPM.logger.debug {"[#{name}/#{__method__}] Config Key/Value: #{k}, #{v}"}
92
64
  end
65
+ nil
93
66
  end
94
67
 
95
68
  def self.resolve_solarwinds_processor
@@ -122,21 +95,19 @@ module SolarWindsAPM
122
95
  return
123
96
  end
124
97
 
125
- validate_service_key
126
-
127
- return unless @@agent_enabled
128
-
129
98
  resolve_sampler
130
-
131
99
  resolve_solarwinds_propagator
132
100
  resolve_solarwinds_processor
133
101
  resolve_response_propagator
134
102
 
135
- obfuscate_query
136
-
137
103
  print_config if SolarWindsAPM.logger.level.zero?
138
104
 
105
+ # resolve OTEL environmental variables
139
106
  ENV['OTEL_TRACES_EXPORTER'] = 'none' if ENV['OTEL_TRACES_EXPORTER'].to_s.empty?
107
+ if ENV['OTEL_LOG_LEVEL'].to_s.empty?
108
+ log_level = (ENV['SW_APM_DEBUG_LEVEL'] || SolarWindsAPM::Config[:debug_level] || 3).to_i
109
+ ENV['OTEL_LOG_LEVEL'] = SolarWindsAPM::Config::SW_LOG_LEVEL_MAPPING.dig(log_level, :otel)
110
+ end
140
111
 
141
112
  ::OpenTelemetry::SDK.configure { |c| c.use_all(@@config_map) }
142
113
 
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module SolarWindsAPM
8
+ module Patch
9
+ module DummyPatch
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # © 2023 SolarWinds Worldwide, LLC. All rights reserved.
2
+ #
3
+ # 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
4
+ #
5
+ # 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.
6
+
7
+ # This file is for loading any customized patch for upstream
8
+
9
+ # e.g.
10
+ # require_relative './patch/dummy_patch'
11
+ # OpenTelemetry::Instrumentation::Registry.prepend(SolarWindsAPM::Patch::DummyPatch) if defined? OpenTelemetry::Instrumentation::Registry && OpenTelemetry::Instrumentation::Registry::VERSION <= '0.3.0'
@@ -19,7 +19,7 @@ module SolarWindsAPM
19
19
  private
20
20
 
21
21
  def insert_trace_id(msg)
22
- return msg if msg =~ /trace_id=/
22
+ return msg if /trace_id=/.match?(msg)
23
23
 
24
24
  current_trace = SolarWindsAPM::API.current_trace_info
25
25
  if current_trace.do_log
@@ -5,29 +5,27 @@
5
5
  # 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.
6
6
 
7
7
  module SolarWindsAPM
8
- module OpenTelemetry
9
- # OboeTracingMode
10
- # Used in solarwinds_sampler
11
- class OboeTracingMode
12
- OBOE_SETTINGS_UNSET = -1
13
- OBOE_TRACE_DISABLED = 0
14
- OBOE_TRACE_ENABLED = 1
15
- OBOE_TRIGGER_DISABLED = 0
16
- OBOE_TRIGGER_ENABLED = 1
8
+ # OboeTracingMode
9
+ # Used in solarwinds_sampler
10
+ class OboeTracingMode
11
+ OBOE_SETTINGS_UNSET = -1
12
+ OBOE_TRACE_DISABLED = 0
13
+ OBOE_TRACE_ENABLED = 1
14
+ OBOE_TRIGGER_DISABLED = 0
15
+ OBOE_TRIGGER_ENABLED = 1
17
16
 
18
- def self.get_oboe_trace_mode(tracing_mode)
19
- mode = OBOE_SETTINGS_UNSET
20
- mode = OBOE_TRACE_ENABLED if tracing_mode == 'enabled'
21
- mode = OBOE_TRACE_DISABLED if tracing_mode == 'disabled'
22
- mode
23
- end
17
+ def self.get_oboe_trace_mode(tracing_mode)
18
+ mode = OBOE_SETTINGS_UNSET
19
+ mode = OBOE_TRACE_ENABLED if tracing_mode == :enabled
20
+ mode = OBOE_TRACE_DISABLED if tracing_mode == :disabled
21
+ mode
22
+ end
24
23
 
25
- def self.get_oboe_trigger_trace_mode(trigger_trace_mode)
26
- mode = OBOE_SETTINGS_UNSET
27
- mode = OBOE_TRIGGER_ENABLED if trigger_trace_mode == 'enabled'
28
- mode = OBOE_TRIGGER_DISABLED if trigger_trace_mode == 'disabled'
29
- mode
30
- end
24
+ def self.get_oboe_trigger_trace_mode(trigger_trace_mode)
25
+ mode = OBOE_SETTINGS_UNSET
26
+ mode = OBOE_TRIGGER_ENABLED if trigger_trace_mode == :enabled
27
+ mode = OBOE_TRIGGER_DISABLED if trigger_trace_mode == :disabled
28
+ mode
31
29
  end
32
30
  end
33
- end
31
+ end
@@ -0,0 +1,94 @@
1
+ # © 2023 SolarWinds Worldwide, LLC. All rights reserved.
2
+ #
3
+ # 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
4
+ #
5
+ # 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.
6
+
7
+ module SolarWindsAPM
8
+ # ServiceKeyChecker
9
+ # It is a service that validate the service_key
10
+ class ServiceKeyChecker
11
+ def initialize(reporter)
12
+ @reporter = reporter
13
+ end
14
+
15
+ def read_and_validate_service_key
16
+ return '' unless @reporter == 'ssl'
17
+
18
+ service_key = fetch_service_key
19
+ if service_key.empty?
20
+ SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY not configured."}
21
+ return ''
22
+ end
23
+
24
+ token, _, service_name = parse_service_key(service_key)
25
+ if token.empty? || !validate_token(token)
26
+ SolarWindsAPM.logger.error {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY problem. API Token in wrong format. Masked token: #{token[0..3]}...#{token[-4..]}"}
27
+ return ''
28
+ end
29
+
30
+ # if no service_name from service_key, then the SW_APM_SERVICE_KEY is not right format, return
31
+ if service_name.empty?
32
+ ENV.delete('OTEL_SERVICE_NAME')
33
+ SolarWindsAPM.logger.warn {"[#{self.class}/#{__method__}] SW_APM_SERVICE_KEY format problem. Service Name is missing."}
34
+ return ''
35
+ end
36
+
37
+ service_name = transform_service_name(service_name)
38
+
39
+ # check if otel_resource_service or otel_service_name has service name to override the original service name
40
+ otel_resource_service_name = fetch_otel_resource_service_name
41
+ service_name = transform_service_name(otel_resource_service_name) unless otel_resource_service_name.empty?
42
+
43
+ otel_service_name = fetch_otel_service_name
44
+ if otel_service_name.empty?
45
+ ENV['OTEL_SERVICE_NAME'] = service_name
46
+ else
47
+ service_name = transform_service_name(otel_service_name)
48
+ end
49
+
50
+ "#{token}:#{service_name}"
51
+ end
52
+
53
+ private
54
+
55
+ # since oboe_init_options init afte config, so [:service_key] will be present at this point
56
+ def fetch_service_key
57
+ ENV['SW_APM_SERVICE_KEY'] || SolarWindsAPM::Config[:service_key] || ''
58
+ end
59
+
60
+ def parse_service_key(service_key)
61
+ match = service_key.match(/([^:]+)(:{0,1})(.*)/)
62
+ return ['', '', ''] if match.nil?
63
+
64
+ [match[1], match[2], match[3]]
65
+ end
66
+
67
+ # precedence: OTEL_SERVICE_NAME > OTEL_RESOURCE_ATTRIBUTES > service_key
68
+ def fetch_otel_service_name
69
+ ENV['OTEL_SERVICE_NAME'] || ''
70
+ end
71
+
72
+ def fetch_otel_resource_service_name
73
+ ENV['OTEL_RESOURCE_ATTRIBUTES']&.split(',')&.find do |pair|
74
+ key, value = pair.split('=')
75
+ break value if key == 'service.name'
76
+ end || ''
77
+ end
78
+
79
+ # In case of java-collector, please provide a dummy service key
80
+ def validate_token(token)
81
+ /^[0-9a-zA-Z_-]{71}$/.match?(token)
82
+ end
83
+
84
+ def transform_service_name(service_name)
85
+ name_ = service_name.dup
86
+ name_.downcase!
87
+ name_.gsub!(/[^a-z0-9.:_-]/, '')
88
+ name_ = name_[0..254]
89
+ SolarWindsAPM.logger.warn {"[#{self.class}/#{__method__}] Service Name transformed from #{service_name} to #{name_}"} if name_ != service_name
90
+
91
+ name_
92
+ end
93
+ end
94
+ end
@@ -7,12 +7,11 @@
7
7
  require 'rbconfig'
8
8
  require 'logger'
9
9
 
10
+ ##
11
+ # This module is used to debug problematic setups and/or environments.
12
+ # Depending on the environment, output may be to stdout or the framework
13
+ # log file (e.g. log/production.log)
10
14
  module SolarWindsAPM
11
- ##
12
- # This module is used to debug problematic setups and/or environments.
13
- # Depending on the environment, output may be to stdout or the framework
14
- # log file (e.g. log/production.log)
15
-
16
15
  ##
17
16
  # yesno
18
17
  #
@@ -71,6 +70,12 @@ module SolarWindsAPM
71
70
  SolarWindsAPM.logger.warn '********************************************************'
72
71
  SolarWindsAPM.logger.warn '* SolarWindsAPM::Config Values'
73
72
  SolarWindsAPM.logger.warn '********************************************************'
73
+ SolarWindsAPM.logger.warn SolarWindsAPM::Config.print_config.to_s
74
+
75
+ SolarWindsAPM.logger.warn '********************************************************'
76
+ SolarWindsAPM.logger.warn '* SolarWindsAPM::OTelConfig Values'
77
+ SolarWindsAPM.logger.warn '********************************************************'
78
+ SolarWindsAPM.logger.warn SolarWindsAPM::OTelConfig.print_config.to_s
74
79
 
75
80
  SolarWindsAPM.logger.warn '********************************************************'
76
81
  SolarWindsAPM.logger.warn '* OS, Platform + Env'
@@ -78,9 +83,7 @@ module SolarWindsAPM
78
83
  SolarWindsAPM.logger.warn "host_os: #{RbConfig::CONFIG['host_os']}"
79
84
  SolarWindsAPM.logger.warn "sitearch: #{RbConfig::CONFIG['sitearch']}"
80
85
  SolarWindsAPM.logger.warn "arch: #{RbConfig::CONFIG['arch']}"
81
- SolarWindsAPM.logger.warn RUBY_PLATFORM
82
- SolarWindsAPM.logger.warn "RACK_ENV: #{ENV['RACK_ENV']}"
83
- SolarWindsAPM.logger.warn "RAILS_ENV: #{ENV['RAILS_ENV']}" if using_rails
86
+ SolarWindsAPM.logger.warn "Platform: #{RUBY_PLATFORM}"
84
87
 
85
88
  SolarWindsAPM.logger.warn '********************************************************'
86
89
  SolarWindsAPM.logger.warn '* END SolarWindsAPM Support Report'
@@ -25,7 +25,7 @@ module SolarWindsAPM
25
25
  end
26
26
 
27
27
  def self.construct_comment
28
- ret = String.new
28
+ ret = +''
29
29
  components.each do |c|
30
30
  component_value = send(c)
31
31
  ret << "#{c}='#{component_value}'," if component_value.present?
@@ -107,7 +107,7 @@ module SolarWindsAPM
107
107
  marginalia_job["class"] if marginalia_job.respond_to?(:[])
108
108
  end
109
109
 
110
- DEFAULT_LINES_TO_IGNORE_REGEX = %r{\.rvm|/ruby/gems/|vendor/|marginalia|rbenv|monitor\.rb.*mon_synchronize}
110
+ DEFAULT_LINES_TO_IGNORE_REGEX = %r{\.rvm|/ruby/gems/|vendor/|marginalia|rbenv|monitor\.rb.*mon_synchronize}.freeze # rubocop:disable Style/RedundantFreeze
111
111
 
112
112
  def self.line
113
113
  SWOMarginalia::Comment.lines_to_ignore ||= DEFAULT_LINES_TO_IGNORE_REGEX
@@ -79,7 +79,7 @@ module SolarWindsAPM
79
79
 
80
80
  def self.with_annotation(comment, &block)
81
81
  SWOMarginalia::Comment.inline_annotations.push(comment)
82
- block.call if block.present?
82
+ yield if block.present?
83
83
  ensure
84
84
  SWOMarginalia::Comment.inline_annotations.pop
85
85
  end
@@ -21,15 +21,11 @@ module SolarWindsAPM
21
21
  # calculate trace mode to set either 1 or 0 based on url_path and name+kind
22
22
  # first check if url_path match, if not match, then match the name+kind
23
23
  def calculate_trace_mode
24
- tracing_mode_enabled? && tracing_enabled? ? SWO_TRACING_ENABLED : SWO_TRACING_DISABLED
24
+ SolarWindsAPM::Config[:tracing_mode] == :enabled && tracing_enabled? ? SWO_TRACING_ENABLED : SWO_TRACING_DISABLED
25
25
  end
26
26
 
27
27
  private
28
28
 
29
- def tracing_mode_enabled?
30
- SolarWindsAPM::Config[:tracing_mode] && ![:disabled, :never].include?(SolarWindsAPM::Config[:tracing_mode])
31
- end
32
-
33
29
  def tracing_enabled?
34
30
  span_layer = "#{@kind}:#{@name}"
35
31
 
@@ -15,6 +15,7 @@ require_relative './support/oboe_tracing_mode'
15
15
  require_relative './support/txn_name_manager'
16
16
  require_relative './support/utils'
17
17
  require_relative './support/x_trace_options'
18
+ require_relative './support/support_report'
18
19
 
19
20
  if SolarWindsAPM::Config[:tag_sql]
20
21
  if defined?(::Rails)
@@ -12,7 +12,7 @@ module SolarWindsAPM
12
12
  MAJOR = 6 # breaking,
13
13
  MINOR = 0 # feature,
14
14
  PATCH = 0 # fix => BFF
15
- PRE = 'preV5'.freeze # for pre-releases into packagecloud, set to nil for production releases into rubygems
15
+ PRE = nil
16
16
 
17
17
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
18
18
  end