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
@@ -2,10 +2,8 @@
2
2
  # (c) Copyright Instana Inc. 2017
3
3
 
4
4
  module Instana
5
- class SpanContext
6
- attr_accessor :trace_id
7
- attr_accessor :span_id
8
- attr_accessor :baggage
5
+ class SpanContext < OpenTelemetry::Trace::SpanContext
6
+ attr_accessor :trace_id, :span_id, :baggage
9
7
  attr_reader :level
10
8
 
11
9
  # Create a new SpanContext
@@ -15,9 +13,20 @@ module Instana
15
13
  # @param level [Integer] default 1
16
14
  # @param baggage [Hash] baggage applied to this trace
17
15
  #
18
- def initialize(tid, sid, level = 1, baggage = {})
19
- @trace_id = tid
20
- @span_id = sid
16
+ def initialize( # rubocop:disable Lint/MissingSuper, Metrics/ParameterLists
17
+ trace_id: Trace.generate_trace_id,
18
+ span_id: Trace.generate_span_id,
19
+ trace_flags: OpenTelemetry::Trace::TraceFlags::DEFAULT, # Todo - implement traceflags
20
+ tracestate: OpenTelemetry::Trace::Tracestate::DEFAULT, # Todo - implement tracestates
21
+ remote: false,
22
+ level: 1,
23
+ baggage: {}
24
+ )
25
+ @trace_id = trace_id
26
+ @span_id = span_id
27
+ @trace_flags = trace_flags
28
+ @tracestate = tracestate
29
+ @remote = remote
21
30
  @level = Integer(level || 1)
22
31
  @baggage = baggage || {}
23
32
  end
@@ -55,7 +64,7 @@ module Instana
55
64
  end
56
65
 
57
66
  def valid?
58
- @baggage && @trace_id && !@trace_id.emtpy?
67
+ @baggage && @trace_id && !@trace_id.empty?
59
68
  end
60
69
 
61
70
  def active?
@@ -0,0 +1,51 @@
1
+ # (c) Copyright IBM Corp. 2025
2
+
3
+ module Instana
4
+ # Type of span. Can be used to specify additional relationships between spans in addition to a
5
+ # parent/child relationship. For API ergonomics, use of the symbols rather than the constants
6
+ # may be preferred. For example:
7
+ #
8
+ # span = tracer.on_start('op', kind: :client)
9
+ module SpanKind
10
+ # Instana specific spans
11
+ REGISTERED_SPANS = [:actioncontroller, :actionview, :activerecord, :excon,
12
+ :memcache, :'net-http', :rack, :render, :'rpc-client',
13
+ :'rpc-server', :'sidekiq-client', :'sidekiq-worker',
14
+ :redis, :'resque-client', :'resque-worker', :'graphql.server', :dynamodb, :s3, :sns, :sqs, :'aws.lambda.entry', :activejob, :log, :"mail.actionmailer",
15
+ :"aws.lambda.invoke", :mongo, :sequel].freeze
16
+ ENTRY_SPANS = [:rack, :'resque-worker', :'rpc-server', :'sidekiq-worker', :'graphql.server', :sqs,
17
+ :'aws.lambda.entry'].freeze
18
+ EXIT_SPANS = [:activerecord, :excon, :'net-http', :'resque-client',
19
+ :'rpc-client', :'sidekiq-client', :redis, :dynamodb, :s3, :sns, :sqs, :log, :"mail.actionmailer",
20
+ :"aws.lambda.invoke", :mongo, :sequel].freeze
21
+ HTTP_SPANS = [:rack, :excon, :'net-http'].freeze
22
+
23
+ # Default value. Indicates that the span is used internally.
24
+ INTERNAL = :internal
25
+
26
+ # Indicates that the span covers server-side handling of an RPC or other remote request.
27
+ SERVER = :server
28
+
29
+ # Indicates that the span covers the client-side wrapper around an RPC or other remote request.
30
+ CLIENT = :client
31
+
32
+ # Indicates that the span describes producer sending a message to a broker. Unlike client and
33
+ # server, there is no direct critical path latency relationship between producer and consumer
34
+ # spans.
35
+ PRODUCER = :producer
36
+
37
+ # Indicates that the span describes consumer receiving a message from a broker. Unlike client
38
+ # and server, there is no direct critical path latency relationship between producer and
39
+ # consumer spans.
40
+ CONSUMER = :consumer
41
+
42
+ # Indicates an entry span. Equivalant to Server or Consumer
43
+ ENTRY = :entry
44
+
45
+ # Indicates an exit span. Equivalant to Client or Producer
46
+ EXIT = :exit
47
+
48
+ # Indicates an intermediate span. This used when sdk is used to produce intermediate traces
49
+ INTERMEDIATE = :intermediate
50
+ end
51
+ end
@@ -0,0 +1,63 @@
1
+ # (c) Copyright IBM Corp. 2025
2
+
3
+ require 'opentelemetry-common'
4
+
5
+ module Instana
6
+ module Trace
7
+ # Class that holds global trace parameters.
8
+ class SpanLimits
9
+ # The global default max number of attributes per {Span}.
10
+ attr_reader :attribute_count_limit
11
+
12
+ # The global default max length of attribute value per {Span}.
13
+ attr_reader :attribute_length_limit
14
+
15
+ # The global default max number of {OpenTelemetry::SDK::Trace::Event}s per {Span}.
16
+ attr_reader :event_count_limit
17
+
18
+ # The global default max number of {OpenTelemetry::Trace::Link} entries per {Span}.
19
+ attr_reader :link_count_limit
20
+
21
+ # The global default max number of attributes per {OpenTelemetry::SDK::Trace::Event}.
22
+ attr_reader :event_attribute_count_limit
23
+
24
+ # The global default max length of attribute value per {OpenTelemetry::SDK::Trace::Event}.
25
+ attr_reader :event_attribute_length_limit
26
+
27
+ # The global default max number of attributes per {OpenTelemetry::Trace::Link}.
28
+ attr_reader :link_attribute_count_limit
29
+
30
+ # Returns a {SpanLimits} with the desired values.
31
+ #
32
+ # @return [SpanLimits] with the desired values.
33
+ # @raise [ArgumentError] if any of the max numbers are not positive.
34
+ def initialize(attribute_count_limit: Integer(OpenTelemetry::Common::Utilities.config_opt('OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT', 'OTEL_ATTRIBUTE_COUNT_LIMIT', default: 128)), # rubocop:disable Metrics/ParameterLists
35
+ attribute_length_limit: OpenTelemetry::Common::Utilities.config_opt('OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT', 'OTEL_RUBY_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT',
36
+ 'OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT'),
37
+ event_count_limit: Integer(OpenTelemetry::Common::Utilities.config_opt('OTEL_SPAN_EVENT_COUNT_LIMIT', default: 128)),
38
+ link_count_limit: Integer(OpenTelemetry::Common::Utilities.config_opt('OTEL_SPAN_LINK_COUNT_LIMIT', default: 128)),
39
+ event_attribute_count_limit: Integer(OpenTelemetry::Common::Utilities.config_opt('OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT', default: 128)),
40
+ event_attribute_length_limit: OpenTelemetry::Common::Utilities.config_opt('OTEL_EVENT_ATTRIBUTE_VALUE_LENGTH_LIMIT', 'OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT'),
41
+ link_attribute_count_limit: Integer(OpenTelemetry::Common::Utilities.config_opt('OTEL_LINK_ATTRIBUTE_COUNT_LIMIT', default: 128)))
42
+ raise ArgumentError, 'attribute_count_limit must be positive' unless attribute_count_limit.positive?
43
+ raise ArgumentError, 'attribute_length_limit must not be less than 32' unless attribute_length_limit.nil? || Integer(attribute_length_limit) >= 32
44
+ raise ArgumentError, 'event_count_limit must be positive' unless event_count_limit.positive?
45
+ raise ArgumentError, 'link_count_limit must be positive' unless link_count_limit.positive?
46
+ raise ArgumentError, 'event_attribute_count_limit must be positive' unless event_attribute_count_limit.positive?
47
+ raise ArgumentError, 'event_attribute_length_limit must not be less than 32' unless event_attribute_length_limit.nil? || Integer(event_attribute_length_limit) >= 32
48
+ raise ArgumentError, 'link_attribute_count_limit must be positive' unless link_attribute_count_limit.positive?
49
+
50
+ @attribute_count_limit = attribute_count_limit
51
+ @attribute_length_limit = attribute_length_limit.nil? ? nil : Integer(attribute_length_limit)
52
+ @event_count_limit = event_count_limit
53
+ @link_count_limit = link_count_limit
54
+ @event_attribute_count_limit = event_attribute_count_limit
55
+ @event_attribute_length_limit = event_attribute_length_limit.nil? ? nil : Integer(event_attribute_length_limit)
56
+ @link_attribute_count_limit = link_attribute_count_limit
57
+ end
58
+
59
+ # The default {SpanLimits}.
60
+ DEFAULT = new
61
+ end
62
+ end
63
+ end
@@ -1,14 +1,14 @@
1
- # (c) Copyright IBM Corp. 2021
2
- # (c) Copyright Instana Inc. 2016
1
+ # (c) Copyright IBM Corp. 2025
3
2
 
4
- require "instana/tracing/span"
5
- require "instana/tracing/span_context"
3
+ require 'opentelemetry/trace/tracer'
4
+ require 'instana/trace/span'
5
+ require "instana/trace/span_context"
6
+ require 'opentelemetry/context'
6
7
 
7
8
  module Instana
8
- class Tracer
9
- # Support ::Instana::Tracer.xxx call style for the instantiated tracer
9
+ class Tracer < OpenTelemetry::Trace::Tracer
10
10
  class << self
11
- def method_missing(method, *args, &block)
11
+ def method_missing(method, *args, &block) # rubocop:disable Style/MissingRespondToMissing
12
12
  if ::Instana.tracer.respond_to?(method)
13
13
  ::Instana.tracer.send(method, *args, &block)
14
14
  else
@@ -17,7 +17,9 @@ module Instana
17
17
  end
18
18
  end
19
19
 
20
- def initialize(logger: Instana.logger)
20
+ def initialize(_name, _version, tracer_provider, logger = Instana.logger)
21
+ super()
22
+ @tracer_provider = tracer_provider
21
23
  @current_span = Concurrent::ThreadLocalVar.new
22
24
  @logger = logger
23
25
  end
@@ -29,8 +31,8 @@ module Instana
29
31
 
30
32
  # @param [Instana::Span, NilClas] v the new current span
31
33
  # Set the value of the current span
32
- def current_span=(v)
33
- @current_span.value = v
34
+ def current_span=(value)
35
+ @current_span.value = value
34
36
  end
35
37
 
36
38
  #######################################
@@ -48,10 +50,10 @@ module Instana
48
50
  # :span_id the ID of the parent span (must be an unsigned hex-string)
49
51
  # :level specifies data collection level (optional)
50
52
  #
51
- def start_or_continue_trace(name, kvs = {}, incoming_context = nil, &block)
53
+ def start_or_continue_trace(name, kvs = {}, incoming_context = nil)
52
54
  span = log_start_or_continue(name, kvs, incoming_context)
53
55
  yield(span)
54
- rescue Exception => e
56
+ rescue Exception => e # rubocop:disable Lint/RescueException
55
57
  log_error(e)
56
58
  raise
57
59
  ensure
@@ -69,10 +71,10 @@ module Instana
69
71
  # @param name [String, Symbol] the name of the span to start
70
72
  # @param kvs [Hash] list of key values to be reported in this new span
71
73
  #
72
- def trace(name, kvs = {}, &block)
74
+ def trace(name, kvs = {})
73
75
  span = log_entry(name, kvs)
74
76
  yield(span)
75
- rescue Exception => e
77
+ rescue Exception => e # rubocop:disable Lint/RescueException
76
78
  log_error(e)
77
79
  raise
78
80
  ensure
@@ -100,12 +102,12 @@ module Instana
100
102
  # Handle the potential variations on `incoming_context`
101
103
  if incoming_context
102
104
  if incoming_context.is_a?(Hash)
103
- if !incoming_context.empty?
105
+ unless incoming_context.empty?
104
106
  parent_context = SpanContext.new(
105
- incoming_context[:trace_id],
106
- incoming_context[:span_id],
107
- incoming_context[:level],
108
- {
107
+ trace_id: incoming_context[:trace_id],
108
+ span_id: incoming_context[:span_id],
109
+ level: incoming_context[:level],
110
+ baggage: {
109
111
  external_trace_id: incoming_context[:external_trace_id],
110
112
  external_state: incoming_context[:external_state]
111
113
  }
@@ -116,14 +118,14 @@ module Instana
116
118
  end
117
119
  end
118
120
 
119
- if parent_context
120
- self.current_span = Span.new(name, parent_ctx: parent_context)
121
- else
122
- self.current_span = Span.new(name)
123
- end
121
+ self.current_span = if parent_context
122
+ Span.new(name, parent_context)
123
+ else
124
+ Span.new(name)
125
+ end
124
126
 
125
- self.current_span.set_tags(kvs) unless kvs.empty?
126
- self.current_span
127
+ current_span.set_tags(kvs) unless kvs.empty?
128
+ current_span
127
129
  end
128
130
 
129
131
  # Will establish a new span as a child of the current span
@@ -132,13 +134,13 @@ module Instana
132
134
  # @param name [String, Symbol] the name of the span to create
133
135
  # @param kvs [Hash] list of key values to be reported in the span
134
136
  #
135
- def log_entry(name, kvs = nil, start_time = ::Instana::Util.now_in_ms, child_of = nil)
137
+ def log_entry(name, kvs = nil, _start_time = ::Instana::Util.now_in_ms, child_of = nil)
136
138
  return unless tracing? || child_of
137
139
 
138
- new_span = if child_of.nil? && !self.current_span.nil?
139
- Span.new(name, parent_ctx: self.current_span, start_time: start_time)
140
+ new_span = if child_of.nil? && !current_span.nil?
141
+ Span.new(name, current_span)
140
142
  else
141
- Span.new(name, parent_ctx: child_of, start_time: start_time)
143
+ Span.new(name, child_of)
142
144
  end
143
145
  new_span.set_tags(kvs) if kvs
144
146
  self.current_span = new_span
@@ -149,17 +151,19 @@ module Instana
149
151
  # @param kvs [Hash] list of key values to be reported in the span
150
152
  #
151
153
  def log_info(kvs)
152
- return unless self.current_span
153
- self.current_span.set_tags(kvs)
154
+ return unless current_span
155
+
156
+ current_span.set_tags(kvs)
154
157
  end
155
158
 
156
159
  # Add an error to the current span
157
160
  #
158
161
  # @param e [Exception] Add exception to the current span
159
162
  #
160
- def log_error(e)
161
- return unless self.current_span
162
- self.current_span.add_error(e)
163
+ def log_error(error)
164
+ return unless current_span
165
+
166
+ current_span.record_exception(error)
163
167
  end
164
168
 
165
169
  # Closes out the current span
@@ -171,16 +175,16 @@ module Instana
171
175
  # @param kvs [Hash] list of key values to be reported in the span
172
176
  #
173
177
  def log_exit(name, kvs = {})
174
- return unless self.current_span
178
+ return unless current_span
175
179
 
176
- if self.current_span.name != name
177
- @logger.warn "Span mismatch: Attempt to end #{name} span but #{self.current_span.name} is active."
180
+ if current_span.name != name
181
+ @logger.warn "Span mismatch: Attempt to end #{name} span but #{current_span.name} is active."
178
182
  end
179
183
 
180
- self.current_span.set_tags(kvs)
181
- self.current_span.close
184
+ current_span.set_tags(kvs)
185
+ current_span.close
182
186
 
183
- self.current_span = self.current_span.parent || nil
187
+ self.current_span = current_span.parent || nil
184
188
  end
185
189
 
186
190
  # Closes out the current span in the current trace
@@ -193,14 +197,14 @@ module Instana
193
197
  # @param kvs [Hash] list of key values to be reported in the span
194
198
  #
195
199
  def log_end(name, kvs = {}, end_time = ::Instana::Util.now_in_ms)
196
- return unless self.current_span
200
+ return unless current_span
197
201
 
198
- if self.current_span.name != name
199
- @logger.warn "Span mismatch: Attempt to end #{name} span but #{self.current_span.name} is active."
202
+ if current_span.name != name
203
+ @logger.warn "Span mismatch: Attempt to end #{name} span but #{current_span.name} is active."
200
204
  end
201
205
 
202
- self.current_span.set_tags(kvs)
203
- self.current_span.close(end_time)
206
+ current_span.set_tags(kvs)
207
+ current_span.close(end_time)
204
208
  self.current_span = nil
205
209
  end
206
210
 
@@ -220,7 +224,7 @@ module Instana
220
224
  def log_async_entry(name, kvs)
221
225
  return unless tracing?
222
226
 
223
- new_span = Span.new(name, parent_ctx: self.current_span)
227
+ new_span = Span.new(name, current_span)
224
228
  new_span.set_tags(kvs) unless kvs.empty?
225
229
  new_span
226
230
  end
@@ -239,8 +243,8 @@ module Instana
239
243
  # @param e [Exception] Add exception to the current span
240
244
  # @param span [Span] the span for this Async op (previously returned from `log_async_entry`)
241
245
  #
242
- def log_async_error(e, span)
243
- span.add_error(e)
246
+ def log_async_error(error, span)
247
+ span.record_exception(error)
244
248
  end
245
249
 
246
250
  # Closes out an asynchronous span
@@ -268,7 +272,7 @@ module Instana
268
272
  # The non-nil value of this instance variable
269
273
  # indicates if we are currently tracing
270
274
  # in this thread or not.
271
- (self.current_span ? true : false) ||
275
+ (current_span ? true : false) ||
272
276
  (::Instana.config[:allow_exit_as_root] && ::Instana.config[:tracing][:enabled])
273
277
  end
274
278
 
@@ -280,9 +284,10 @@ module Instana
280
284
  # @return [Boolean]
281
285
  #
282
286
  def tracing_span?(name)
283
- if self.current_span
284
- return self.current_span.name == name
287
+ if current_span
288
+ return current_span.name == name
285
289
  end
290
+
286
291
  false
287
292
  end
288
293
 
@@ -291,8 +296,9 @@ module Instana
291
296
  # @return [SpanContext] or nil if not tracing
292
297
  #
293
298
  def context
294
- return unless self.current_span
295
- self.current_span.context
299
+ return unless current_span
300
+
301
+ current_span.context
296
302
  end
297
303
 
298
304
  # Used in the test suite, this resets the tracer to non-tracing state.
@@ -300,5 +306,51 @@ module Instana
300
306
  def clear!
301
307
  self.current_span = nil
302
308
  end
309
+
310
+ # Creates a span that is active during the execution of the provided block.
311
+ # The span is automatically closed when the block completes, whether it completes
312
+ # normally or with an exception.
313
+ #
314
+ # @param name [String, Symbol] the name of the span to create
315
+ # @param attributes [Hash, nil] optional attributes to set on the span
316
+ # @param links [Array<Link>, nil] optional links to associate with the span
317
+ # @param start_timestamp [Integer, nil] optional start time for the span in milliseconds
318
+ # @param kind [Symbol, nil] optional span kind (e.g., :internal, :client, :server)
319
+ #
320
+ # @return [Object] the return value of the block
321
+ #
322
+ # @note This method is a wrapper around the parent class implementation and
323
+ # will only create a span if the Instana agent is ready and tracing is enabled.
324
+ #
325
+ def in_span(name, attributes: nil, links: nil, start_timestamp: nil, kind: nil)
326
+ return if !::Instana.agent.ready? || !::Instana.config[:tracing][:enabled]
327
+
328
+ super
329
+ end
330
+
331
+ # Starts a new span with the given parameters.
332
+ #
333
+ # @param name [String, Symbol] the name of the span to create (defaults to 'empty' if nil)
334
+ # @param with_parent [Context, nil] the parent context for the span (defaults to current context if nil)
335
+ # @param attributes [Hash, nil] optional attributes to set on the span
336
+ # @param links [Array<Link>, nil] optional links to associate with the span
337
+ # @param start_timestamp [Integer, nil] optional start time for the span in milliseconds
338
+ # @param kind [Symbol, nil] optional span kind (defaults to :internal if nil)
339
+ #
340
+ # @return [Span] the newly created span
341
+ #
342
+ # @note This method will only create a span if the Instana agent is ready and tracing is enabled.
343
+ # Default values are set for nil parameters: name='empty', kind=:internal,
344
+ # with_parent=current context, start_timestamp=current time.
345
+ #
346
+ def start_span(name, with_parent: nil, attributes: nil, links: nil, start_timestamp: ::Instana::Util.now_in_ms, kind: nil) # rubocop:disable Metrics/ParameterLists
347
+ return if !::Instana.agent.ready? || !::Instana.config[:tracing][:enabled]
348
+
349
+ with_parent ||= OpenTelemetry::Context.current
350
+ name ||= 'empty'
351
+ kind ||= :internal
352
+ start_timestamp ||= ::Instana::Util.now_in_ms
353
+ self.current_span = @tracer_provider.internal_start_span(name, kind, attributes, links, start_timestamp, with_parent, @instrumentation_scope)
354
+ end
303
355
  end
304
356
  end
@@ -0,0 +1,198 @@
1
+ # (c) Copyright IBM Corp. 2025
2
+
3
+ require 'opentelemetry/trace/tracer_provider'
4
+ require 'instana/samplers/samplers'
5
+ require 'instana/trace/span_limits'
6
+ require 'instana/trace/export'
7
+
8
+ module Instana
9
+ module Trace
10
+ # {TracerProvider} is the Instana implementation of {OpenTelemetry::Trace::TracerProvider}.
11
+ class TracerProvider < OpenTelemetry::Trace::TracerProvider
12
+ Key = Struct.new(:name, :version)
13
+ private_constant(:Key)
14
+
15
+ attr_accessor :span_limits, :id_generator, :sampler
16
+ attr_reader :resource
17
+
18
+ # Returns a new {TracerProvider} instance.
19
+ #
20
+ # @param [optional Sampler] sampler The sampling policy for new spans
21
+ # @param [optional Resource] resource The resource to associate with spans
22
+ # created by Tracers created by this TracerProvider
23
+ # @param [optional IDGenerator] id_generator The trace and span ID generation
24
+ # policy
25
+ # @param [optional SpanLimits] span_limits The limits to apply to attribute,
26
+ # event and link counts for Spans created by Tracers created by this
27
+ # TracerProvider
28
+ #
29
+ # @return [TracerProvider]
30
+ # def initialize
31
+ # super()
32
+ # end
33
+
34
+ def initialize(sampler: sampler_from_environment(Samplers.parent_based(root: Samplers::ALWAYS_ON)),
35
+ resource: nil, # Instana::Resources::Resource.create
36
+ id_generator: ::Instana::Trace,
37
+ span_limits: SpanLimits::DEFAULT)
38
+ super()
39
+ @mutex = Mutex.new
40
+ @registry = {}
41
+ @registry_mutex = Mutex.new
42
+ @span_processors = []
43
+ @span_limits = span_limits
44
+ @sampler = sampler
45
+ @id_generator = id_generator
46
+ @stopped = false
47
+ @resource = resource
48
+ end
49
+
50
+ # Returns a {Tracer} instance.
51
+ #
52
+ # @param [optional String] name Instrumentation package name
53
+ # @param [optional String] version Instrumentation package version
54
+ #
55
+ # @return [Tracer]
56
+ def tracer(name = nil, version = nil)
57
+ name ||= ''
58
+ version ||= ''
59
+ ::Instana.logger.warn 'calling TracerProvider#tracer without providing a tracer name.' if name.empty?
60
+ @registry_mutex.synchronize { @registry[Key.new(name, version)] ||= Tracer.new(name, version, self) }
61
+ end
62
+
63
+ # Attempts to stop all the activity for this {TracerProvider}. Calls
64
+ # SpanProcessor#shutdown for all registered SpanProcessors.
65
+ #
66
+ # This operation may block until all the Spans are processed. Must be
67
+ # called before turning off the main application to ensure all data are
68
+ # processed and exported.
69
+ #
70
+ # After this is called all the newly created {Span}s will be no-op.
71
+ #
72
+ # @param [optional Numeric] timeout An optional timeout in seconds.
73
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
74
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
75
+ def shutdown(timeout: nil)
76
+ @mutex.synchronize do
77
+ if @stopped
78
+ ::Instana.logger.warn('calling Tracer#shutdown multiple times.')
79
+ return Export::FAILURE
80
+ end
81
+
82
+ start_time = Instana::Util.timeout_timestamp
83
+ results = @span_processors.map do |processor|
84
+ remaining_timeout = Instana::Util.maybe_timeout(timeout, start_time)
85
+ break [Export::TIMEOUT] if remaining_timeout&.zero?
86
+
87
+ processor.shutdown(timeout: remaining_timeout)
88
+ end
89
+ @stopped = true
90
+ results.max || Export::SUCCESS
91
+ end
92
+ end
93
+
94
+ # Immediately export all spans that have not yet been exported for all the
95
+ # registered SpanProcessors.
96
+ #
97
+ # This method should only be called in cases where it is absolutely
98
+ # necessary, such as when using some FaaS providers that may suspend
99
+ # the process after an invocation, but before the `Processor` exports
100
+ # the completed spans.
101
+ #
102
+ # @param [optional Numeric] timeout An optional timeout in seconds.
103
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
104
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
105
+ def force_flush(timeout: nil)
106
+ @mutex.synchronize do
107
+ return Export::SUCCESS if @stopped
108
+
109
+ start_time = Instana::Util.timeout_timestamp
110
+ results = @span_processors.map do |processor|
111
+ remaining_timeout = Instana::Util.maybe_timeout(timeout, start_time)
112
+ return Export::TIMEOUT if remaining_timeout&.zero?
113
+
114
+ processor.force_flush(timeout: remaining_timeout)
115
+ end
116
+ results.max || Export::SUCCESS
117
+ end
118
+ end
119
+
120
+ # Adds a new SpanProcessor to this {Tracer}.
121
+ #
122
+ # @param span_processor the new SpanProcessor to be added.
123
+ def add_span_processor(span_processor)
124
+ @mutex.synchronize do
125
+ if @stopped
126
+ ::Instana.logger.warn('calling Tracer#add_span_processor after shutdown.')
127
+ return
128
+ end
129
+ @span_processors = @span_processors.dup.push(span_processor)
130
+ end
131
+ end
132
+
133
+ # This method serves as the primary entry point for span creation. It initializes
134
+ # an Instana span, handles context, and manages sampling before returning the created span.
135
+ def internal_start_span(name, kind, attributes, links, start_timestamp, parent_context, instrumentation_scope) # rubocop:disable Metrics/ParameterLists
136
+ parent_span = OpenTelemetry::Trace.current_span(parent_context)
137
+ parent_span_context = parent_span.context if parent_span
138
+ if parent_span_context&.valid?
139
+ parent_span_id = parent_span_context.span_id
140
+ trace_id = parent_span_context.trace_id
141
+ span_id = @id_generator.generate_span_id
142
+ end
143
+ trace_id ||= @id_generator.generate_trace_id
144
+
145
+ if OpenTelemetry::Common::Utilities.untraced?(parent_context)
146
+ span_id = parent_span_id || @id_generator.generate_span_id
147
+ return OpenTelemetry::Trace.non_recording_span(OpenTelemetry::Trace::SpanContext.new(trace_id: trace_id, span_id: span_id))
148
+ end
149
+
150
+ result = @sampler.should_sample?(trace_id: trace_id, parent_context: parent_context, links: links, name: name, kind: kind, attributes: attributes)
151
+ span_id ||= @id_generator.generate_span_id
152
+ if !@stopped && result.recording? && !@stopped
153
+ trace_flags = result.sampled? ? OpenTelemetry::Trace::TraceFlags::SAMPLED : OpenTelemetry::Trace::TraceFlags::DEFAULT
154
+ context = Instana::SpanContext.new(trace_id: trace_id, span_id: span_id, trace_flags: trace_flags, tracestate: result.tracestate)
155
+ attributes = attributes&.merge(result.attributes) || result.attributes.dup
156
+ Instana::Span.new(
157
+ name,
158
+ parent_span_context,
159
+ context,
160
+ parent_span,
161
+ kind,
162
+ parent_span_id,
163
+ @span_limits,
164
+ @span_processors,
165
+ attributes,
166
+ links,
167
+ start_timestamp,
168
+ @resource,
169
+ instrumentation_scope
170
+ )
171
+ else
172
+ Instana::Trace.non_recording_span(Instana::Trace::SpanContext.new(trace_id: trace_id, span_id: span_id, tracestate: result.tracestate)) # Todo add tracestate so that the trcing doesnot happen for this span # rubocop:disable Layout/LineLength
173
+ end
174
+ end
175
+
176
+ private
177
+
178
+ def sampler_from_environment(default_sampler)
179
+ case ENV['OTEL_TRACES_SAMPLER']
180
+ when 'always_on' then Samplers::ALWAYS_ON
181
+ when 'always_off' then Samplers::ALWAYS_OFF
182
+ when 'traceidratio' then Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACES_SAMPLER_ARG', 1.0)))
183
+ when 'parentbased_always_on' then Samplers.parent_based(root: Samplers::ALWAYS_ON)
184
+ when 'parentbased_always_off' then Samplers.parent_based(root: Samplers::ALWAYS_OFF)
185
+ when 'parentbased_traceidratio' then Samplers.parent_based(root: Samplers.trace_id_ratio_based(Float(ENV.fetch('OTEL_TRACES_SAMPLER_ARG', 1.0))))
186
+ else default_sampler
187
+ end
188
+ rescue StandardError => e
189
+ OpenTelemetry.handle_error(exception: e, message: "installing default sampler #{default_sampler.description}")
190
+ default_sampler
191
+ end
192
+
193
+ def timeout_timestamp
194
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
195
+ end
196
+ end
197
+ end
198
+ end