instana 2.3.0 → 2.5.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16fe1ce82ea4a8d0324dd72d015792e88af0389d8faecc54dfffe587ccb6ec50
4
- data.tar.gz: 7a8f22ed404bcede4d89fc8a2e5dc47f15617c3084ee6a4d7242545fca2e2e6f
3
+ metadata.gz: 465f9dad91e0e60f443e196091b1b725ed012094a5da4f8d0d9a8c525ba4b0de
4
+ data.tar.gz: e5c17ed36acd2197cbbc6e83a2c44b64562c7bd1785854fc4e2120fb01a99d3f
5
5
  SHA512:
6
- metadata.gz: e3a2941ff94173b97d8967d74be38f9f2a5776f38e19b6c2eaa4e4a8af827b3f2c126d58620a6843aae8d342229a6e227f9cb88a1508082b51d89fb00150818e
7
- data.tar.gz: bd6fedc2ae15e7533d703e09efdc128af3a9d6be5eb780ce83d3f42f4db91304bb40ab08fb962fc07eba05cee6b6dd587c380d49a8014aafc7f3792f157e380c
6
+ metadata.gz: ef5f5fe6ff3272ac729be2d1b36f9653a06ab8bc8393e15e897712558c0c09258a8730f08e1ef8f8d7503e8e6168c177afc5c98609616ec5ba9bbdf9aa3a42b5
7
+ data.tar.gz: aba66786130415c9154453bb7daf853ffa976c7b048cdf15985706b778ee92dad8d963ff02040228c79f22c08f67a0ca9099af90439a99217420b99549632040
@@ -40,6 +40,9 @@ module Instana
40
40
  wait_for_backend(discovery['pid'])
41
41
  @logger.debug("Agent ready.")
42
42
  @discovery.swap { discovery }
43
+
44
+ # Read configuration from agent right after discovery
45
+ ::Instana.config.read_config_from_agent(discovery)
43
46
  end
44
47
 
45
48
  socket.close
data/lib/instana/base.rb CHANGED
@@ -16,6 +16,15 @@ module Instana
16
16
  attr_reader :serverless
17
17
  attr_accessor :tracer_provider
18
18
 
19
+ ##
20
+ # span_filtering_config
21
+ #
22
+ # Returns the span filtering configuration instance
23
+ #
24
+ def span_filtering_config
25
+ ::Instana::SpanFiltering.configuration
26
+ end
27
+
19
28
  ##
20
29
  # setup
21
30
  #
@@ -1,6 +1,8 @@
1
1
  # (c) Copyright IBM Corp. 2021
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
+ require 'yaml'
5
+
4
6
  module Instana
5
7
  class Config
6
8
  def initialize(logger: ::Instana.logger, agent_host: ENV['INSTANA_AGENT_HOST'], agent_port: ENV['INSTANA_AGENT_PORT'])
@@ -43,8 +45,9 @@ module Instana
43
45
  # In Ruby, backtrace collection is very expensive so it's
44
46
  # (unfortunately) disabled by default. If you still want
45
47
  # backtraces, it can be enabled with this config option.
46
- # ::Instana.config[:collect_backtraces] = true
47
- @config[:collect_backtraces] = false
48
+ # @config[:back_trace][:stack_trace_level] = all
49
+ # @config[:back_trace] = { stack_trace_level: nil }
50
+ read_span_stack_config
48
51
 
49
52
  # By default, collected SQL will be sanitized to remove potentially sensitive bind params such as:
50
53
  # > SELECT "blocks".* FROM "blocks" WHERE "blocks"."name" = "Mr. Smith"
@@ -86,6 +89,177 @@ module Instana
86
89
  def []=(key, value)
87
90
  @config[key.to_sym] = value
88
91
  end
92
+
93
+ # Read stack trace configuration from environment variables, YAML file, or use defaults
94
+ # Priority: Environment variables > YAML file > Agent discovery > Defaults
95
+ def read_span_stack_config
96
+ # Try environment variables first
97
+ if ENV['INSTANA_STACK_TRACE'] || ENV['INSTANA_STACK_TRACE_LENGTH']
98
+ read_span_stack_config_from_env
99
+ @config[:back_trace_technologies] = {}
100
+ return
101
+ end
102
+
103
+ # Try YAML file
104
+ yaml_config = read_span_stack_config_from_yaml
105
+ if yaml_config
106
+ @config[:back_trace] = yaml_config[:global]
107
+ @config[:back_trace_technologies] = yaml_config[:technologies] || {}
108
+ return
109
+ end
110
+
111
+ # Use defaults
112
+ apply_default_stack_trace_config
113
+ end
114
+
115
+ # Read configuration from agent discovery response
116
+ # This is called after agent discovery is complete
117
+ # @param discovery [Hash] The discovery response from the agent
118
+ def read_config_from_agent(discovery)
119
+ return unless discovery.is_a?(Hash) && discovery['tracing']
120
+
121
+ tracing_config = discovery['tracing']
122
+
123
+ # Read stack trace configuration from agent if not already set from YAML or env
124
+ read_span_stack_config_from_agent(tracing_config) if should_read_from_agent?(:back_trace)
125
+ # Read span filtering configuration from agent
126
+ ::Instana.span_filtering_config&.read_config_from_agent(discovery)
127
+ rescue => e
128
+ ::Instana.logger.warn("Failed to read configuration from agent: #{e.message}")
129
+ end
130
+
131
+ # Read stack trace configuration from agent discovery
132
+ # @param tracing_config [Hash] The tracing configuration from discovery
133
+ def read_span_stack_config_from_agent(tracing_config)
134
+ return unless tracing_config['global']
135
+
136
+ global_config = parse_global_stack_trace_config(tracing_config['global'], 'agent')
137
+ @config[:back_trace] = global_config if global_config
138
+
139
+ # Read technology-specific configurations
140
+ @config[:back_trace_technologies] = parse_technology_configs(tracing_config)
141
+ end
142
+
143
+ # Read stack trace configuration from YAML file
144
+ # Returns hash with :global and :technologies keys or nil if not found
145
+ def read_span_stack_config_from_yaml
146
+ config_path = ENV['INSTANA_CONFIG_PATH']
147
+ return nil unless config_path && File.exist?(config_path)
148
+
149
+ begin
150
+ yaml_content = YAML.safe_load(File.read(config_path))
151
+
152
+ # Support both "tracing" and "com.instana.tracing" as top-level keys
153
+ if yaml_content['com.instana.tracing']
154
+ ::Instana.logger.warn('Please use "tracing" instead of "com.instana.tracing"')
155
+ end
156
+ tracing_config = yaml_content['tracing'] || yaml_content['com.instana.tracing']
157
+ return nil unless tracing_config
158
+
159
+ result = {}
160
+
161
+ # Look for global stack trace configuration
162
+ if tracing_config['global']
163
+ global_config = parse_global_stack_trace_config(tracing_config['global'], 'yaml')
164
+ result[:global] = global_config if global_config
165
+ end
166
+
167
+ # Look for technology-specific configurations
168
+ technologies = parse_technology_configs(tracing_config)
169
+ result[:technologies] = technologies unless technologies.empty?
170
+
171
+ result.empty? ? nil : result
172
+ rescue => e
173
+ ::Instana.logger.warn("Failed to load stack trace configuration from YAML: #{e.message}")
174
+ nil
175
+ end
176
+ end
177
+
178
+ # Read stack trace configuration from environment variables
179
+ def read_span_stack_config_from_env
180
+ @config[:back_trace] = {
181
+ stack_trace_level: ENV['INSTANA_STACK_TRACE'] || 'error',
182
+ stack_trace_length: ENV['INSTANA_STACK_TRACE_LENGTH']&.to_i || 30,
183
+ config_source: 'env'
184
+ }
185
+ end
186
+
187
+ # Apply default stack trace configuration
188
+ def apply_default_stack_trace_config
189
+ @config[:back_trace] = {
190
+ stack_trace_level: 'error',
191
+ stack_trace_length: 30,
192
+ config_source: 'default'
193
+ }
194
+ @config[:back_trace_technologies] = {}
195
+ end
196
+
197
+ # Check if we should read configuration from agent
198
+ # Returns true if config was not set from YAML or environment variables
199
+ def should_read_from_agent?(config_key)
200
+ return true unless @config[config_key]
201
+
202
+ source = @config[config_key][:config_source]
203
+ source.nil? || source == 'default'
204
+ end
205
+
206
+ # Get stack trace configuration for a specific technology
207
+ # Falls back to global configuration if technology-specific config is not found
208
+ # @param technology [Symbol] The technology name (e.g., :excon, :kafka, :activerecord)
209
+ # @return [Hash] Configuration hash with :stack_trace_level and :stack_trace_length
210
+ def get_stack_trace_config(technology)
211
+ tech_config = @config[:back_trace_technologies]&.[](technology)
212
+ global_config = @config[:back_trace] || {}
213
+
214
+ {
215
+ stack_trace_level: tech_config&.[](:stack_trace_level) || global_config[:stack_trace_level] || 'error',
216
+ stack_trace_length: tech_config&.[](:stack_trace_length) || global_config[:stack_trace_length] || 30
217
+ }
218
+ end
219
+
220
+ private
221
+
222
+ # Parse global stack trace configuration from a config hash
223
+ # @param global_config [Hash] The global configuration hash
224
+ # @param config_source [String] The source of the configuration ('yaml', 'agent', etc.)
225
+ # @return [Hash, nil] Parsed configuration or nil if no valid config found
226
+ def parse_global_stack_trace_config(global_config, config_source)
227
+ return nil unless global_config.is_a?(Hash)
228
+
229
+ stack_trace_level = global_config['stack-trace']
230
+ stack_trace_length = global_config['stack-trace-length']
231
+
232
+ # Only return config if at least one value is present
233
+ return nil unless stack_trace_level || stack_trace_length
234
+
235
+ {
236
+ stack_trace_level: stack_trace_level || 'error',
237
+ stack_trace_length: stack_trace_length ? stack_trace_length.to_i : 30,
238
+ config_source: config_source
239
+ }
240
+ end
241
+
242
+ # Parse technology-specific stack trace configurations from tracing config
243
+ # @param tracing_config [Hash] The tracing configuration hash
244
+ # @return [Hash] Technology-specific configurations
245
+ def parse_technology_configs(tracing_config)
246
+ technologies = {}
247
+ tracing_config.each do |key, value|
248
+ next if key == 'global' || !value.is_a?(Hash)
249
+
250
+ tech_stack_trace = value['stack-trace']
251
+ tech_stack_trace_length = value['stack-trace-length']
252
+
253
+ next unless tech_stack_trace || tech_stack_trace_length
254
+
255
+ technologies[key.to_sym] = {
256
+ stack_trace_level: tech_stack_trace,
257
+ stack_trace_length: tech_stack_trace_length ? tech_stack_trace_length.to_i : nil
258
+ }.compact
259
+ end
260
+ technologies
261
+ end
262
+
89
263
  end
90
264
  end
91
265
 
@@ -27,57 +27,21 @@ module Instana
27
27
  def load_configuration
28
28
  load_from_yaml
29
29
  load_from_env_vars unless rules_loaded?
30
- load_from_agent unless rules_loaded?
30
+ # Agent configuration will be loaded after discovery via read_config_from_agent
31
31
  end
32
32
 
33
- private
34
-
35
- # Load configuration from agent discovery response
36
- def load_from_agent
37
- # Try to get discovery value immediately first
38
- discovery = ::Instana.agent&.delegate&.send(:discovery_value)
39
- if discovery && discovery.is_a?(Hash) && !discovery.empty?
40
- process_discovery_config(discovery)
41
- return
42
- end
33
+ # Read configuration from agent discovery response
34
+ # This is called from Config#read_config_from_agent after discovery is complete
35
+ # @param discovery [Hash] The discovery response from the agent
36
+ def read_config_from_agent(discovery)
37
+ return if rules_loaded? # Don't override if already loaded from YAML or env
43
38
 
44
- # If not available, set up a timer task to periodically check for discovery
45
- setup_discovery_timer
39
+ process_discovery_config(discovery)
46
40
  rescue => e
47
- Instana.logger.warn("Failed to load span filtering configuration from agent: #{e.message}")
41
+ Instana.logger.warn("Failed to read span filtering configuration from agent: #{e.message}")
48
42
  end
49
43
 
50
- # Set up a timer task to periodically check for discovery
51
- def setup_discovery_timer
52
- # Don't create a timer task if we're in a test environment
53
- return if ENV.key?('INSTANA_TEST')
54
-
55
- # Create a timer task that checks for discovery every second
56
- @discovery_timer = Concurrent::TimerTask.new(execution_interval: 1) do
57
- check_discovery
58
- end
59
-
60
- # Start the timer task
61
- @discovery_timer.execute
62
- end
63
-
64
- # Check if discovery is available and process it
65
- def check_discovery
66
- discovery = ::Instana.agent&.delegate.send(:discovery_value)
67
- if discovery && discovery.is_a?(Hash) && !discovery.empty?
68
- process_discovery_config(discovery)
69
-
70
- # Shutdown the timer task after successful processing
71
- @discovery_timer.shutdown if @discovery_timer
72
-
73
- return true
74
- end
75
-
76
- false
77
- rescue => e
78
- Instana.logger.warn("Error checking discovery in timer task: #{e.message}")
79
- false
80
- end
44
+ private
81
45
 
82
46
  # Process the discovery configuration
83
47
  def process_discovery_config(discovery)
@@ -70,27 +70,31 @@ module Instana
70
70
  set_tags(attributes)
71
71
  ::Instana.processor.on_start(self)
72
72
  # Attach a backtrace to all exit spans
73
- add_stack if ::Instana.config[:collect_backtraces] && exit_span?
73
+ add_stack if should_collect_stack_trace?
74
74
  end
75
75
 
76
76
  # Adds a backtrace to this span
77
77
  #
78
78
  # @param limit [Integer] Limit the backtrace to the top <limit> frames
79
79
  #
80
- def add_stack(limit: 30, stack: Kernel.caller)
80
+ def add_stack(span_stack_config: nil, stack: Kernel.caller)
81
+ # Get technology-specific config if not provided
82
+ span_stack_config ||= current_span_stack_config
83
+
84
+ limit = span_stack_config[:stack_trace_length]
81
85
  cleaner = ::Instana.config[:backtrace_cleaner]
82
86
  stack = cleaner.call(stack) if cleaner
83
87
 
84
88
  @attributes[:stack] = stack
85
89
  .map do |call|
86
- file, line, *method = call.split(':')
90
+ file, line, *method = call.split(':')
87
91
 
88
- {
89
- c: file,
90
- n: line,
91
- m: method.join(' ')
92
- }
93
- end.take(limit > 40 ? 40 : limit)
92
+ {
93
+ c: file,
94
+ n: line,
95
+ m: method.join(' ')
96
+ }
97
+ end.take([limit, 40].min)
94
98
  end
95
99
 
96
100
  # Log an error into the span
@@ -530,5 +534,20 @@ module Instana
530
534
  #
531
535
  # @return [void]
532
536
  def status=(status); end
537
+
538
+ def should_collect_stack_trace?
539
+ return false unless exit_span?
540
+
541
+ config = current_span_stack_config
542
+ config[:stack_trace_level] == "all"
543
+ end
544
+
545
+ # Get the stack trace configuration for this span's technology
546
+ # Falls back to global configuration if technology-specific config is not found
547
+ # @return [Hash] Configuration hash with :stack_trace_level and :stack_trace_length
548
+ def current_span_stack_config
549
+ technology = @attributes[:n]
550
+ ::Instana.config.get_stack_trace_config(technology)
551
+ end
533
552
  end
534
553
  end
@@ -2,6 +2,6 @@
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
4
  module Instana
5
- VERSION = "2.3.0"
5
+ VERSION = "2.5.0"
6
6
  VERSION_FULL = "instana-#{VERSION}"
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instana
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Giacomo Lombardo
@@ -191,6 +191,20 @@ dependencies:
191
191
  - - ">="
192
192
  - !ruby/object:Gem::Version
193
193
  version: '0'
194
+ - !ruby/object:Gem::Dependency
195
+ name: cgi
196
+ requirement: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ type: :runtime
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
194
208
  - !ruby/object:Gem::Dependency
195
209
  name: oj
196
210
  requirement: !ruby/object:Gem::Requirement
@@ -348,7 +362,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
348
362
  - !ruby/object:Gem::Version
349
363
  version: '0'
350
364
  requirements: []
351
- rubygems_version: 4.0.2
365
+ rubygems_version: 4.0.7
352
366
  specification_version: 4
353
367
  summary: Ruby Distributed Tracing & Metrics Sensor for Instana
354
368
  test_files: []