instana 1.217.1 → 2.1.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.
Files changed (228) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/lib/instana/base.rb +4 -2
  4. data/lib/instana/instrumentation/action_cable.rb +8 -4
  5. data/lib/instana/instrumentation/action_controller.rb +2 -4
  6. data/lib/instana/instrumentation/action_mailer.rb +1 -1
  7. data/lib/instana/instrumentation/action_view.rb +4 -4
  8. data/lib/instana/instrumentation/active_job.rb +20 -5
  9. data/lib/instana/instrumentation/active_record.rb +1 -1
  10. data/lib/instana/instrumentation/aws_sdk_dynamodb.rb +1 -1
  11. data/lib/instana/instrumentation/aws_sdk_lambda.rb +1 -1
  12. data/lib/instana/instrumentation/aws_sdk_s3.rb +1 -1
  13. data/lib/instana/instrumentation/aws_sdk_sns.rb +1 -1
  14. data/lib/instana/instrumentation/aws_sdk_sqs.rb +1 -1
  15. data/lib/instana/instrumentation/dalli.rb +1 -1
  16. data/lib/instana/instrumentation/excon.rb +2 -2
  17. data/lib/instana/instrumentation/graphql.rb +3 -3
  18. data/lib/instana/instrumentation/grpc.rb +14 -13
  19. data/lib/instana/instrumentation/mongo.rb +3 -3
  20. data/lib/instana/instrumentation/net-http.rb +5 -4
  21. data/lib/instana/instrumentation/rack.rb +36 -4
  22. data/lib/instana/instrumentation/redis.rb +1 -1
  23. data/lib/instana/instrumentation/resque.rb +10 -8
  24. data/lib/instana/instrumentation/rest-client.rb +4 -4
  25. data/lib/instana/instrumentation/sequel.rb +3 -3
  26. data/lib/instana/instrumentation/shoryuken.rb +4 -1
  27. data/lib/instana/instrumentation/sidekiq-client.rb +21 -19
  28. data/lib/instana/instrumentation/sidekiq-worker.rb +22 -21
  29. data/lib/instana/instrumented_logger.rb +1 -1
  30. data/lib/instana/samplers/result.rb +32 -0
  31. data/lib/instana/samplers/samplers.rb +76 -0
  32. data/lib/instana/serverless.rb +4 -2
  33. data/lib/instana/setup.rb +5 -5
  34. data/lib/instana/span_filtering/condition.rb +134 -0
  35. data/lib/instana/span_filtering/configuration.rb +262 -0
  36. data/lib/instana/span_filtering/filter_rule.rb +31 -0
  37. data/lib/instana/span_filtering.rb +62 -0
  38. data/lib/instana/trace/export.rb +36 -0
  39. data/lib/instana/{tracing → trace}/processor.rb +19 -15
  40. data/lib/instana/trace/span.rb +534 -0
  41. data/lib/instana/{tracing → trace}/span_context.rb +17 -8
  42. data/lib/instana/trace/span_kind.rb +51 -0
  43. data/lib/instana/trace/span_limits.rb +63 -0
  44. data/lib/instana/{tracer.rb → trace/tracer.rb} +106 -54
  45. data/lib/instana/trace/tracer_provider.rb +198 -0
  46. data/lib/instana/trace.rb +74 -0
  47. data/lib/instana/util.rb +11 -0
  48. data/lib/instana/version.rb +1 -1
  49. metadata +89 -267
  50. data/.circleci/config.yml +0 -485
  51. data/.codeclimate.yml +0 -23
  52. data/.editorconfig +0 -10
  53. data/.fasterer.yml +0 -23
  54. data/.github/ISSUE_TEMPLATE/bug.yml +0 -39
  55. data/.github/ISSUE_TEMPLATE/config.yml +0 -8
  56. data/.github/workflows/pr_commits_signed_off.yml +0 -16
  57. data/.github/workflows/release-notification-on-slack.yml +0 -34
  58. data/.gitignore +0 -19
  59. data/.rubocop.yml +0 -34
  60. data/.rubocop_todo.yml +0 -1140
  61. data/.tekton/.currency/docs/report.md +0 -20
  62. data/.tekton/.currency/resources/requirements.txt +0 -4
  63. data/.tekton/.currency/resources/table.json +0 -100
  64. data/.tekton/.currency/scripts/generate_report.py +0 -136
  65. data/.tekton/README.md +0 -278
  66. data/.tekton/github-interceptor-secret.yaml +0 -8
  67. data/.tekton/github-pr-eventlistener.yaml +0 -104
  68. data/.tekton/github-pr-pipeline.yaml.part +0 -38
  69. data/.tekton/github-set-status-task.yaml +0 -43
  70. data/.tekton/github-webhook-ingress.yaml +0 -20
  71. data/.tekton/pipeline.yaml +0 -571
  72. data/.tekton/pipelinerun.yaml +0 -21
  73. data/.tekton/ruby-tracer-prepuller.yaml +0 -87
  74. data/.tekton/run_unittests.sh +0 -87
  75. data/.tekton/scheduled-eventlistener.yaml +0 -108
  76. data/.tekton/task.yaml +0 -449
  77. data/.tekton/tekton-triggers-eventlistener-serviceaccount.yaml +0 -29
  78. data/Appraisals +0 -124
  79. data/CONTRIBUTING.md +0 -86
  80. data/Gemfile +0 -17
  81. data/LICENSE +0 -22
  82. data/MAINTAINERS.md +0 -3
  83. data/Rakefile +0 -49
  84. data/bin/announce_release_on_slack.py +0 -103
  85. data/docker-compose.yml +0 -20
  86. data/download.sh +0 -85
  87. data/examples/opentracing.rb +0 -35
  88. data/examples/tracing.rb +0 -84
  89. data/extras/license_header.rb +0 -44
  90. data/gemfiles/.bundle/config +0 -2
  91. data/gemfiles/aws_30.gemfile +0 -21
  92. data/gemfiles/aws_60.gemfile +0 -16
  93. data/gemfiles/cuba_30.gemfile +0 -16
  94. data/gemfiles/cuba_40.gemfile +0 -13
  95. data/gemfiles/dalli_20.gemfile +0 -15
  96. data/gemfiles/dalli_30.gemfile +0 -12
  97. data/gemfiles/dalli_32.gemfile +0 -12
  98. data/gemfiles/excon_0100.gemfile +0 -14
  99. data/gemfiles/excon_021.gemfile +0 -17
  100. data/gemfiles/excon_079.gemfile +0 -17
  101. data/gemfiles/excon_100.gemfile +0 -14
  102. data/gemfiles/graphql_10.gemfile +0 -16
  103. data/gemfiles/graphql_20.gemfile +0 -15
  104. data/gemfiles/grpc_10.gemfile +0 -15
  105. data/gemfiles/mongo_216.gemfile +0 -15
  106. data/gemfiles/mongo_219.gemfile +0 -12
  107. data/gemfiles/net_http_01.gemfile +0 -17
  108. data/gemfiles/rack_16.gemfile +0 -15
  109. data/gemfiles/rack_20.gemfile +0 -15
  110. data/gemfiles/rack_30.gemfile +0 -13
  111. data/gemfiles/rails_42.gemfile +0 -18
  112. data/gemfiles/rails_50.gemfile +0 -19
  113. data/gemfiles/rails_52.gemfile +0 -19
  114. data/gemfiles/rails_60.gemfile +0 -19
  115. data/gemfiles/rails_61.gemfile +0 -20
  116. data/gemfiles/rails_70.gemfile +0 -17
  117. data/gemfiles/rails_71.gemfile +0 -17
  118. data/gemfiles/rails_80.gemfile +0 -17
  119. data/gemfiles/redis_40.gemfile +0 -15
  120. data/gemfiles/redis_50.gemfile +0 -13
  121. data/gemfiles/redis_51.gemfile +0 -13
  122. data/gemfiles/resque_122.gemfile +0 -16
  123. data/gemfiles/resque_1274_3scale.gemfile +0 -17
  124. data/gemfiles/resque_20.gemfile +0 -16
  125. data/gemfiles/rest_client_16.gemfile +0 -17
  126. data/gemfiles/rest_client_20.gemfile +0 -17
  127. data/gemfiles/roda_20.gemfile +0 -16
  128. data/gemfiles/roda_30.gemfile +0 -16
  129. data/gemfiles/rubocop_162.gemfile +0 -6
  130. data/gemfiles/sequel_56.gemfile +0 -16
  131. data/gemfiles/sequel_57.gemfile +0 -16
  132. data/gemfiles/sequel_58.gemfile +0 -16
  133. data/gemfiles/shoryuken_50.gemfile +0 -16
  134. data/gemfiles/shoryuken_60.gemfile +0 -13
  135. data/gemfiles/sidekiq_42.gemfile +0 -15
  136. data/gemfiles/sidekiq_50.gemfile +0 -15
  137. data/gemfiles/sidekiq_60.gemfile +0 -12
  138. data/gemfiles/sidekiq_65.gemfile +0 -12
  139. data/gemfiles/sidekiq_70.gemfile +0 -12
  140. data/gemfiles/sinatra_14.gemfile +0 -15
  141. data/gemfiles/sinatra_22.gemfile +0 -12
  142. data/gemfiles/sinatra_30.gemfile +0 -12
  143. data/gemfiles/sinatra_40.gemfile +0 -12
  144. data/instana.gemspec +0 -48
  145. data/lib/instana/open_tracing/carrier.rb +0 -7
  146. data/lib/instana/open_tracing/instana_tracer.rb +0 -99
  147. data/lib/instana/tracing/span.rb +0 -431
  148. data/lib/opentracing.rb +0 -32
  149. data/log/.keep +0 -0
  150. data/sonar-project.properties +0 -9
  151. data/test/activator_test.rb +0 -50
  152. data/test/backend/agent_test.rb +0 -80
  153. data/test/backend/gc_snapshot_test.rb +0 -11
  154. data/test/backend/host_agent_activation_observer_test.rb +0 -73
  155. data/test/backend/host_agent_lookup_test.rb +0 -78
  156. data/test/backend/host_agent_reporting_observer_test.rb +0 -276
  157. data/test/backend/host_agent_test.rb +0 -89
  158. data/test/backend/process_info_test.rb +0 -83
  159. data/test/backend/request_client_test.rb +0 -39
  160. data/test/backend/serverless_agent_test.rb +0 -83
  161. data/test/benchmarks/bench_id_generation.rb +0 -15
  162. data/test/benchmarks/bench_opentracing.rb +0 -16
  163. data/test/config_test.rb +0 -34
  164. data/test/frameworks/cuba_test.rb +0 -61
  165. data/test/frameworks/roda_test.rb +0 -60
  166. data/test/frameworks/sinatra_test.rb +0 -71
  167. data/test/instana_test.rb +0 -37
  168. data/test/instrumentation/aws_test.rb +0 -241
  169. data/test/instrumentation/dalli_test.rb +0 -325
  170. data/test/instrumentation/excon_test.rb +0 -204
  171. data/test/instrumentation/graphql_test.rb +0 -289
  172. data/test/instrumentation/grpc_test.rb +0 -420
  173. data/test/instrumentation/mongo_test.rb +0 -68
  174. data/test/instrumentation/net_http_test.rb +0 -220
  175. data/test/instrumentation/rack_instrumented_request_test.rb +0 -211
  176. data/test/instrumentation/rack_test.rb +0 -415
  177. data/test/instrumentation/rails_action_cable_test.rb +0 -135
  178. data/test/instrumentation/rails_action_controller_test.rb +0 -218
  179. data/test/instrumentation/rails_action_mailer_test.rb +0 -66
  180. data/test/instrumentation/rails_action_view_test.rb +0 -154
  181. data/test/instrumentation/rails_active_job_test.rb +0 -65
  182. data/test/instrumentation/rails_active_record_database_missing_test.rb +0 -45
  183. data/test/instrumentation/rails_active_record_test.rb +0 -115
  184. data/test/instrumentation/redis_test.rb +0 -152
  185. data/test/instrumentation/resque_test.rb +0 -188
  186. data/test/instrumentation/rest_client_test.rb +0 -107
  187. data/test/instrumentation/sequel_test.rb +0 -105
  188. data/test/instrumentation/shoryuken_test.rb +0 -47
  189. data/test/instrumentation/sidekiq-client_test.rb +0 -169
  190. data/test/instrumentation/sidekiq-worker_test.rb +0 -180
  191. data/test/secrets_test.rb +0 -112
  192. data/test/serverless_test.rb +0 -369
  193. data/test/snapshot/deltable_test.rb +0 -17
  194. data/test/snapshot/docker_container_test.rb +0 -82
  195. data/test/snapshot/fargate_container_test.rb +0 -82
  196. data/test/snapshot/fargate_process_test.rb +0 -35
  197. data/test/snapshot/fargate_task_test.rb +0 -49
  198. data/test/snapshot/google_cloud_run_instance_test.rb +0 -74
  199. data/test/snapshot/google_cloud_run_process_test.rb +0 -33
  200. data/test/snapshot/lambda_function_test.rb +0 -37
  201. data/test/snapshot/ruby_process_test.rb +0 -32
  202. data/test/support/apps/active_record/active_record.rb +0 -24
  203. data/test/support/apps/grpc/boot.rb +0 -23
  204. data/test/support/apps/grpc/grpc_server.rb +0 -84
  205. data/test/support/apps/http_endpoint/boot.rb +0 -28
  206. data/test/support/apps/rails/boot.rb +0 -219
  207. data/test/support/apps/rails/models/block.rb +0 -21
  208. data/test/support/apps/rails/models/block6.rb +0 -21
  209. data/test/support/apps/resque/boot.rb +0 -5
  210. data/test/support/apps/resque/jobs/resque_error_job.rb +0 -22
  211. data/test/support/apps/resque/jobs/resque_fast_job.rb +0 -23
  212. data/test/support/apps/sidekiq/boot.rb +0 -25
  213. data/test/support/apps/sidekiq/jobs/sidekiq_job_1.rb +0 -9
  214. data/test/support/apps/sidekiq/jobs/sidekiq_job_2.rb +0 -10
  215. data/test/support/apps/sidekiq/worker.rb +0 -37
  216. data/test/support/helpers.rb +0 -85
  217. data/test/support/mock_timer.rb +0 -20
  218. data/test/test_helper.rb +0 -69
  219. data/test/tracing/custom_test.rb +0 -226
  220. data/test/tracing/id_management_test.rb +0 -80
  221. data/test/tracing/instrumented_logger_test.rb +0 -39
  222. data/test/tracing/opentracing_test.rb +0 -382
  223. data/test/tracing/processor_test.rb +0 -58
  224. data/test/tracing/span_context_test.rb +0 -22
  225. data/test/tracing/span_test.rb +0 -179
  226. data/test/tracing/tracer_async_test.rb +0 -230
  227. data/test/tracing/tracer_test.rb +0 -352
  228. data/test/util_test.rb +0 -10
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright IBM Corp. 2025
4
+
5
+ require 'instana/span_filtering/configuration'
6
+ require 'instana/span_filtering/filter_rule'
7
+ require 'instana/span_filtering/condition'
8
+
9
+ module Instana
10
+ # SpanFiltering module provides functionality to filter spans based on configured rules
11
+ module SpanFiltering
12
+ class << self
13
+ attr_reader :configuration
14
+
15
+ # Initialize the span filtering configuration
16
+ # @return [Configuration] The span filtering configuration
17
+ def initialize
18
+ @configuration = Configuration.new
19
+ end
20
+
21
+ # Check if span filtering is deactivated
22
+ # @return [Boolean] True if span filtering is deactivated
23
+ def deactivated?
24
+ @configuration&.deactivated || false
25
+ end
26
+
27
+ # Check if a span should be filtered out
28
+ # @param span [Hash] The span to check
29
+ # @return [Hash, nil] A result hash with filtered and suppression keys if filtered, nil if not filtered
30
+ def filter_span(span)
31
+ return nil if deactivated?
32
+ return nil unless @configuration
33
+
34
+ # Check include rules first (whitelist)
35
+ if @configuration.include_rules.any?
36
+ # If we have include rules, only keep spans that match at least one include rule
37
+ unless @configuration.include_rules.any? { |rule| rule.matches?(span) }
38
+ return { filtered: true, suppression: false }
39
+ end
40
+ # If it matches an include rule, continue to exclude rules
41
+ end
42
+
43
+ # Check exclude rules (blacklist)
44
+ @configuration.exclude_rules.each do |rule|
45
+ if rule.matches?(span)
46
+ return { filtered: true, suppression: rule.suppression }
47
+ end
48
+ end
49
+
50
+ nil # Keep the span if no rules match
51
+ end
52
+
53
+ # Reset the configuration (mainly for testing)
54
+ def reset
55
+ @configuration = nil
56
+ end
57
+ end
58
+
59
+ # Initialize on module load
60
+ initialize
61
+ end
62
+ end
@@ -0,0 +1,36 @@
1
+ # (c) Copyright IBM Corp. 2025
2
+
3
+ module Instana
4
+ module Trace
5
+ # The Export module contains the built-in exporters and span processors for the OpenTelemetry
6
+ # reference implementation.
7
+ module Export
8
+ # Raised when an export fails; spans are available via :spans accessor
9
+ class ExportError < OpenTelemetry::Error
10
+ # Returns the {Span} array for this exception
11
+ #
12
+ # @return [Array<OpenTelemetry::SDK::Trace::Span>]
13
+ attr_reader :spans
14
+
15
+ # @param [Array<OpenTelemetry::SDK::Trace::Span>] spans the array of spans that failed to export
16
+ def initialize(spans)
17
+ super("Unable to export #{spans.size} spans")
18
+ @spans = spans
19
+ end
20
+ end
21
+
22
+ # Result codes for the SpanExporter#export method and the SpanProcessor#force_flush and SpanProcessor#shutdown methods.
23
+
24
+ # The operation finished successfully.
25
+ SUCCESS = 0
26
+
27
+ # The operation finished with an error.
28
+ FAILURE = 1
29
+
30
+ # Additional result code for the SpanProcessor#force_flush and SpanProcessor#shutdown methods.
31
+
32
+ # The operation timed out.
33
+ TIMEOUT = 2
34
+ end
35
+ end
36
+ end
@@ -1,7 +1,6 @@
1
1
  # (c) Copyright IBM Corp. 2021
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
- require 'thread'
5
4
  require 'forwardable'
6
5
 
7
6
  module Instana
@@ -25,10 +24,13 @@ module Instana
25
24
  @spans_closed = Concurrent::AtomicFixnum.new(0)
26
25
  end
27
26
 
28
- # Adds a span to the span queue
29
- #
30
- # @param [Trace] - the trace to be added to the queue
31
- def add_span(span)
27
+ # Note that we've started a new span. Used to
28
+ # generate monitoring metrics.
29
+ def on_start(_)
30
+ @spans_opened.increment
31
+ end
32
+
33
+ def on_finish(span)
32
34
  # :nocov:
33
35
  if @pid != Process.pid
34
36
  @logger.info("Proces `#{@pid}` has forked into #{Process.pid}. Running post fork hook.")
@@ -41,12 +43,6 @@ module Instana
41
43
  @queue.push(span)
42
44
  end
43
45
 
44
- # Note that we've started a new span. Used to
45
- # generate monitoring metrics.
46
- def start_span(_)
47
- @spans_opened.increment
48
- end
49
-
50
46
  # Clears and retrieves metrics associated with span creation and submission
51
47
  def span_metrics
52
48
  response = {
@@ -94,9 +90,13 @@ module Instana
94
90
  return [] if @queue.empty?
95
91
 
96
92
  spans = []
97
- until @queue.empty? do
93
+ until @queue.empty?
98
94
  # Non-blocking pop; ignore exception
99
- span = @queue.pop(true) rescue nil
95
+ span = begin
96
+ @queue.pop(true)
97
+ rescue
98
+ nil
99
+ end
100
100
  spans << span.raw if span.is_a?(Span) && span.context.level == 1
101
101
  end
102
102
 
@@ -110,9 +110,13 @@ module Instana
110
110
  @spans_opened.value = 0
111
111
  @spans_closed.value = 0
112
112
 
113
- until @queue.empty? do
113
+ until @queue.empty?
114
114
  # Non-blocking pop; ignore exception
115
- @queue.pop(true) rescue nil
115
+ begin
116
+ @queue.pop(true)
117
+ rescue
118
+ nil
119
+ end
116
120
  end
117
121
  end
118
122
  end
@@ -0,0 +1,534 @@
1
+ # (c) Copyright IBM Corp. 2025
2
+
3
+ require 'opentelemetry'
4
+ require 'instana/trace/span_kind'
5
+
6
+ module Instana
7
+ class Span < OpenTelemetry::Trace::Span
8
+ include SpanKind
9
+
10
+ attr_accessor :parent, :baggage, :is_root, :context
11
+
12
+ def initialize(name, parent_ctx = nil, _context = nil, parent_span = nil, _kind = nil, parent_span_id = nil, _span_limits = nil, _span_processors = nil, attributes = nil, _links = nil, start_timestamp = ::Instana::Util.now_in_ms, _resource = nil, _instrumentation_scope = nil) # rubocop:disable Lint/MissingSuper, Metrics/ParameterLists, Layout/LineLength
13
+ @attributes = {}
14
+
15
+ @ended = false
16
+ if parent_span.is_a?(::Instana::Span)
17
+ @parent = parent_span
18
+ end
19
+ if parent_ctx.is_a?(::Instana::Span)
20
+ @parent = parent_ctx
21
+ parent_ctx = parent_ctx.context
22
+ end
23
+
24
+ if parent_ctx.is_a?(::Instana::SpanContext)
25
+ @is_root = false
26
+
27
+ # If we have a parent trace, link to it
28
+ if parent_ctx.trace_id
29
+ @attributes[:t] = parent_ctx.trace_id # Trace ID
30
+ @attributes[:p] = parent_span_id || parent_ctx.span_id # Parent ID
31
+ else
32
+ @attributes[:t] = ::Instana::Trace.generate_trace_id
33
+ end
34
+
35
+ @attributes[:s] = ::Instana::Trace.generate_span_id # Span ID
36
+
37
+ @baggage = parent_ctx.baggage.dup
38
+ @level = parent_ctx.level
39
+ else
40
+ # No parent specified so we're starting a new Trace - this will be the root span
41
+ @is_root = true
42
+ @level = 1
43
+
44
+ id = ::Instana::Trace.generate_span_id
45
+ @attributes[:t] = id # Trace ID
46
+ @attributes[:s] = id # Span ID
47
+ end
48
+
49
+ @attributes[:data] = {}
50
+
51
+ if ENV.key?('INSTANA_SERVICE_NAME')
52
+ @attributes[:data][:service] = ENV['INSTANA_SERVICE_NAME']
53
+ end
54
+
55
+ # Entity Source
56
+ @attributes[:f] = ::Instana.agent.source
57
+ # Start time
58
+ @attributes[:ts] = if start_timestamp.is_a?(Time)
59
+ ::Instana::Util.time_to_ms(start_timestamp)
60
+ else
61
+ start_timestamp
62
+ end
63
+
64
+ # Check for custom tracing
65
+ if REGISTERED_SPANS.include?(name&.to_sym) # Todo remove the safe & operator once all the tests are adapted to new init structure
66
+ @attributes[:n] = name.to_sym
67
+ else
68
+ configure_custom(name)
69
+ end
70
+ set_tags(attributes)
71
+ ::Instana.processor.on_start(self)
72
+ # Attach a backtrace to all exit spans
73
+ add_stack if ::Instana.config[:collect_backtraces] && exit_span?
74
+ end
75
+
76
+ # Adds a backtrace to this span
77
+ #
78
+ # @param limit [Integer] Limit the backtrace to the top <limit> frames
79
+ #
80
+ def add_stack(limit: 30, stack: Kernel.caller)
81
+ cleaner = ::Instana.config[:backtrace_cleaner]
82
+ stack = cleaner.call(stack) if cleaner
83
+
84
+ @attributes[:stack] = stack
85
+ .map do |call|
86
+ file, line, *method = call.split(':')
87
+
88
+ {
89
+ c: file,
90
+ n: line,
91
+ m: method.join(' ')
92
+ }
93
+ end.take(limit > 40 ? 40 : limit)
94
+ end
95
+
96
+ # Log an error into the span
97
+ #
98
+ # @param e [Exception] The exception to be logged
99
+ #
100
+ def record_exception(error)
101
+ @attributes[:error] = true
102
+
103
+ @attributes[:ec] = if @attributes.key?(:ec)
104
+ @attributes[:ec] + 1
105
+ else
106
+ 1
107
+ end
108
+
109
+ # If a valid exception has been passed in, log the information about it
110
+ # In case of just logging an error for things such as HTTP client 5xx
111
+ # responses, an exception/backtrace may not exist.
112
+ if error
113
+ if error.backtrace.is_a?(Array)
114
+ add_stack(stack: error.backtrace)
115
+ end
116
+
117
+ if HTTP_SPANS.include?(@attributes[:n])
118
+ set_tags(:http => { :error => "#{error.class}: #{error.message}" })
119
+ elsif @attributes[:n] == :activerecord
120
+ @attributes[:data][:activerecord][:error] = error.message
121
+ else
122
+ log(:error, Time.now, message: error.message, parameters: error.class.to_s)
123
+ end
124
+ error.instance_variable_set(:@instana_logged, true)
125
+ end
126
+ self
127
+ end
128
+
129
+ # Configure this span to be a custom span per the
130
+ # SDK generic span type.
131
+ #
132
+ # Default to an intermediate kind span. Can be overridden by
133
+ # setting a span.kind tag.
134
+ #
135
+ # @param name [String] name of the span
136
+ # @param kvs [Hash] list of key values to be reported in the span
137
+ #
138
+ def configure_custom(name)
139
+ @attributes[:n] = :sdk
140
+ @attributes[:data] = { :sdk => { :name => name&.to_sym } } # Todo remove safe operator once other tests adapt to new init structure
141
+ @attributes[:data][:sdk][:custom] = { :tags => {}, :logs => {} }
142
+
143
+ if @is_root
144
+ # For custom root spans (via SDK or opentracing), default to entry type
145
+ @attributes[:k] = 1
146
+ @attributes[:data][:sdk][:type] = :entry
147
+ else
148
+ @attributes[:k] = 3
149
+ @attributes[:data][:sdk][:type] = :intermediate
150
+ end
151
+ self
152
+ end
153
+
154
+ # Closes out the span. This difference between this and
155
+ # the finish method tells us how the tracing is being
156
+ # performed (with OpenTracing or Instana default)
157
+ #
158
+ # @param end_time [Time] custom end time, if not now
159
+ # @return [Span]
160
+ #
161
+ def close(end_time = ::Instana::Util.now_in_ms)
162
+ result = ::Instana::SpanFiltering.filter_span(self)
163
+ if end_time.is_a?(Time)
164
+ end_time = ::Instana::Util.time_to_ms(end_time)
165
+ end
166
+ @attributes[:d] = end_time - @attributes[:ts]
167
+ @ended = true
168
+
169
+ if result.nil?
170
+ # Add this span to the queue for reporting
171
+ ::Instana.processor.on_finish(self)
172
+ end
173
+ self
174
+ end
175
+
176
+ #############################################################
177
+ # Accessors
178
+ #############################################################
179
+
180
+ # Retrieve the context of this span.
181
+ #
182
+ # @return [Instana::SpanContext]
183
+ #
184
+ def context # rubocop:disable Lint/DuplicateMethods
185
+ @context ||= ::Instana::SpanContext.new(trace_id: @attributes[:t], span_id: @attributes[:s], level: @level, baggage: @baggage)
186
+ end
187
+
188
+ # Retrieve the ID for this span
189
+ #
190
+ # @return [Integer] the span ID
191
+ def id
192
+ @attributes[:s]
193
+ end
194
+
195
+ # Retrieve the Trace ID for this span
196
+ #
197
+ # @return [Integer] the Trace ID
198
+ def trace_id
199
+ @attributes[:t]
200
+ end
201
+
202
+ # Retrieve the parent ID of this span
203
+ #
204
+ # @return [Integer] parent span ID
205
+ def parent_id
206
+ @attributes[:p]
207
+ end
208
+
209
+ # Set the parent ID of this span
210
+ #
211
+ # @return [Integer] parent span ID
212
+ def parent_id=(id)
213
+ @attributes[:p] = id
214
+ end
215
+
216
+ # Get the name (operation) of this Span
217
+ #
218
+ # @return [String] or [Symbol] representing the span name
219
+ def name
220
+ if custom?
221
+ @attributes[:data][:sdk][:name]
222
+ else
223
+ @attributes[:n]
224
+ end
225
+ end
226
+
227
+ # Set the name (operation) for this Span
228
+ #
229
+ # @params name [String] or [Symbol]
230
+ #
231
+ def name=(name)
232
+ if custom?
233
+ @attributes[:data][:sdk][:name] = name
234
+ else
235
+ @attributes[:n] = name
236
+ end
237
+ end
238
+
239
+ # Get the duration value for this Span
240
+ #
241
+ # @return [Integer] the duration in milliseconds
242
+ def duration
243
+ @attributes[:d]
244
+ end
245
+
246
+ # Hash accessor to the internal @attributes hash
247
+ #
248
+ def [](key)
249
+ @attributes[key.to_sym]
250
+ end
251
+
252
+ # Hash setter to the internal @attributes hash
253
+ #
254
+ def []=(key, value)
255
+ @attributes[key.to_sym] = value
256
+ end
257
+
258
+ # Hash key query to the internal @attributes hash
259
+ #
260
+ def key?(key)
261
+ @attributes.key?(key.to_sym)
262
+ end
263
+
264
+ # Get the raw @attributes hash that summarizes this span
265
+ #
266
+ def raw
267
+ @attributes
268
+ end
269
+
270
+ # Indicates whether this span is a custom or registered Span
271
+ def custom?
272
+ @attributes[:n] == :sdk
273
+ end
274
+
275
+ def inspect
276
+ @attributes.inspect
277
+ end
278
+
279
+ # Check to see if the current span indicates an exit from application
280
+ # code and into an external service
281
+ def exit_span?
282
+ EXIT_SPANS.include?(@attributes[:n])
283
+ end
284
+
285
+ #############################################################
286
+ # OpenTracing Compatibility Methods
287
+ #############################################################
288
+
289
+ # Set the name of the operation
290
+ # Spec: OpenTracing API
291
+ #
292
+ # @params name [String] or [Symbol]
293
+ #
294
+ def operation_name=(name)
295
+ @attributes[:n] = name
296
+ end
297
+
298
+ # Set a tag value on this span
299
+ # Spec: OpenTracing API
300
+ #
301
+ # @param key [String] the key of the tag
302
+ # @param value [String, Numeric, Boolean] the value of the tag. If it's not
303
+ # a String, Numeric, or Boolean it will be encoded with to_s
304
+ #
305
+ def set_tag(key, value)
306
+ unless [Symbol, String].include?(key.class)
307
+ key = key.to_s
308
+ end
309
+
310
+ # If <value> is not a Symbol, String, Array, Hash or Numeric - convert to string
311
+ if ![Symbol, String, Array, TrueClass, FalseClass, Hash].include?(value.class) && !value.is_a?(Numeric)
312
+ value = value.to_s
313
+ end
314
+
315
+ if custom?
316
+ @attributes[:data][:sdk][:custom] ||= {}
317
+ @attributes[:data][:sdk][:custom][:tags] ||= {}
318
+ @attributes[:data][:sdk][:custom][:tags][key] = value
319
+
320
+ if key.to_sym == :'span.kind'
321
+ case value.to_sym
322
+ when ENTRY, SERVER, CONSUMER
323
+ @attributes[:data][:sdk][:type] = ENTRY
324
+ @attributes[:k] = 1
325
+ when EXIT, CLIENT, PRODUCER
326
+ @attributes[:data][:sdk][:type] = EXIT
327
+ @attributes[:k] = 2
328
+ else
329
+ @attributes[:data][:sdk][:type] = INTERMEDIATE
330
+ @attributes[:k] = 3
331
+ end
332
+ end
333
+ elsif value.is_a?(Hash) && @attributes[:data][key].is_a?(Hash)
334
+ @attributes[:data][key].merge!(value)
335
+ else
336
+ @attributes[:data][key] = value
337
+ end
338
+ self
339
+ end
340
+
341
+ # Helper method to add multiple tags to this span
342
+ #
343
+ # @params tags [Hash]
344
+ # @return [Span]
345
+ #
346
+ def set_tags(tags) # rubocop:disable Naming
347
+ return unless tags.is_a?(Hash)
348
+
349
+ tags.each do |k, v|
350
+ set_tag(k, v)
351
+ end
352
+ self
353
+ end
354
+
355
+ # Set a baggage item on the span
356
+ # Spec: OpenTracing API
357
+ #
358
+ # @param key [String] the key of the baggage item
359
+ # @param value [String] the value of the baggage item
360
+ # Todo Evalute if baggage is used anywhere in instana
361
+ def set_baggage_item(key, value)
362
+ @baggage ||= {}
363
+ @baggage[key] = value
364
+
365
+ # Init/Update the SpanContext item
366
+ if @context
367
+ @context.baggage = @baggage
368
+ else
369
+ @context ||= ::Instana::SpanContext.new(trace_id: @attributes[:t], span_id: @attributes[:s], level: @level, baggage: @baggage)
370
+ end
371
+ self
372
+ end
373
+
374
+ # Get a baggage item
375
+ # Spec: OpenTracing API
376
+ #
377
+ # @param key [String] the key of the baggage item
378
+ # @return Value of the baggage item
379
+ #
380
+ def get_baggage_item(key)
381
+ @baggage[key]
382
+ end
383
+
384
+ # Retrieve the hash of tags for this span
385
+ #
386
+ def tags(key = nil)
387
+ tags = if custom?
388
+ @attributes[:data][:sdk][:custom][:tags]
389
+ else
390
+ @attributes[:data]
391
+ end
392
+ key ? tags[key] : tags
393
+ end
394
+
395
+ # Add a log entry to this span
396
+ # Spec: OpenTracing API
397
+ #
398
+ # @param event [String] event name for the log
399
+ # @param timestamp [Time] time of the log
400
+ # @param fields [Hash] Additional information to log
401
+ #
402
+ def log(event = nil, timestamp = Time.now, **fields)
403
+ ts = ::Instana::Util.time_to_ms(timestamp).to_s
404
+ if custom?
405
+ @attributes[:data][:sdk][:custom][:logs][ts] = fields
406
+ @attributes[:data][:sdk][:custom][:logs][ts][:event] = event
407
+ else
408
+ set_tags(:log => fields)
409
+ end
410
+ rescue StandardError => e
411
+ Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
412
+ end
413
+
414
+ # Finish the {Span}
415
+ # Spec: OpenTracing API
416
+ #
417
+ # @param end_time [Time] custom end time, if not now
418
+ #
419
+ def finish(end_time = ::Instana::Util.now_in_ms)
420
+ close(end_time)
421
+ ::Instana.tracer.current_span = ::Instana.tracer.current_span&.parent || nil
422
+ self
423
+ end
424
+
425
+ # Return the flag whether this span is recording events
426
+ #
427
+ # @return [Boolean] true if this Span is active and recording information
428
+ # like events with the #add_event operation and attributes using
429
+ # #set_attribute.
430
+ def recording?
431
+ !@ended
432
+ end
433
+
434
+ # Set attribute
435
+ #
436
+ # Note that the OpenTelemetry project
437
+ # {https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
438
+ # documents} certain "standard attributes" that have prescribed semantic
439
+ # meanings.
440
+ #
441
+ # @param [String] key
442
+ # @param [String, Boolean, Numeric, Array<String, Numeric, Boolean>] value
443
+ # Values must be non-nil and (array of) string, boolean or numeric type.
444
+ # Array values must not contain nil elements and all elements must be of
445
+ # the same basic type (string, numeric, boolean).
446
+ #
447
+ # @return [self] returns itself
448
+ def set_attribute(key, value)
449
+ @attributes ||= {}
450
+ @attributes[key] = value
451
+ self
452
+ end
453
+ # alias []= set_attribute
454
+
455
+ # Add attributes
456
+ #
457
+ # Note that the OpenTelemetry project
458
+ # {https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
459
+ # documents} certain "standard attributes" that have prescribed semantic
460
+ # meanings.
461
+ #
462
+ # @param [Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}] attributes
463
+ # Values must be non-nil and (array of) string, boolean or numeric type.
464
+ # Array values must not contain nil elements and all elements must be of
465
+ # the same basic type (string, numeric, boolean).
466
+ #
467
+ # @return [self] returns itself
468
+ def add_attributes(attributes)
469
+ @attributes ||= {}
470
+ @attributes.merge!(attributes)
471
+ self
472
+ end
473
+
474
+ # Add a link to a {Span}.
475
+ #
476
+ # Adding links at span creation using the `links` option is preferred
477
+ # to calling add_link later, because head sampling decisions can only
478
+ # consider information present during span creation.
479
+ #
480
+ # Example:
481
+ #
482
+ # span.add_link(OpenTelemetry::Trace::Link.new(span_to_link_from.context))
483
+ #
484
+ # Note that the OpenTelemetry project
485
+ # {https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
486
+ # documents} certain "standard attributes" that have prescribed semantic
487
+ # meanings.
488
+ #
489
+ # @param [OpenTelemetry::Trace::Link] the link object to add on the {Span}.
490
+ #
491
+ # @return [self] returns itself
492
+ # Todo add link logic later
493
+ def add_link(_link)
494
+ self
495
+ end
496
+
497
+ # Add an event to a {Span}.
498
+ #
499
+ # Example:
500
+ #
501
+ # span.add_event('event', attributes: {'eager' => true})
502
+ #
503
+ # Note that the OpenTelemetry project
504
+ # {https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
505
+ # documents} certain "standard event names and keys" which have
506
+ # prescribed semantic meanings.
507
+ #
508
+ # @param [String] name Name of the event.
509
+ # @param [optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}]
510
+ # attributes One or more key:value pairs, where the keys must be
511
+ # strings and the values may be (array of) string, boolean or numeric
512
+ # type.
513
+ # @param [optional Time] timestamp Optional timestamp for the event.
514
+ #
515
+ # @return [self] returns itself
516
+ # Todo Add the vent logic later
517
+ def add_event(_name, attributes: nil, timestamp: nil) # rubocop:disable Lint/UnusedMethodArgument
518
+ self
519
+ end
520
+
521
+ # Sets the Status to the Span
522
+ #
523
+ # If used, this will override the default Span status. Default status is unset.
524
+ #
525
+ # Only the value of the last call will be recorded, and implementations
526
+ # are free to ignore previous calls.
527
+ #
528
+ # @param [Status] status The new status, which overrides the default Span
529
+ # status, which is OK.
530
+ #
531
+ # @return [void]
532
+ def status=(status); end
533
+ end
534
+ end