Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cede184
lint: change license header creation logic
arjun-rajappa Nov 14, 2025
cef3119
feat: base structure for bunny instrumentation
arjun-rajappa Nov 14, 2025
f16d667
feat(bunny): capture exception and increase error count on span
arjun-rajappa Nov 18, 2025
138691f
feat(bunny): change attribute sort
arjun-rajappa Nov 18, 2025
a17beb1
feat(bunny): error handling is done in in_span
arjun-rajappa Nov 18, 2025
3f6f953
feat(bunny): add instrumentation for pop method
arjun-rajappa Nov 19, 2025
d9753a9
feat(bunny): add config and span kind
arjun-rajappa Nov 19, 2025
3802455
test(bunny): add tests to publish and pop methods
arjun-rajappa Nov 19, 2025
d97caaa
feat(bunny): instrument subscribe method
arjun-rajappa Nov 20, 2025
dd5e6e1
feat(bunny): move context extraction logic to separate method
arjun-rajappa Nov 20, 2025
e6fa506
test(bunny): add more tests
arjun-rajappa Nov 21, 2025
bee02a2
lint(bunny): fix linting failures
arjun-rajappa Nov 21, 2025
c41810e
lint(bunny): fix linting failures
arjun-rajappa Nov 21, 2025
8abaf0d
feat(bunny): add rabbitmq as entry and exit spans
arjun-rajappa Nov 21, 2025
cdf81b6
test(bunny): add more test cases
arjun-rajappa Nov 24, 2025
bb80505
ci(bunny):add apprisals and gemfiles
arjun-rajappa Nov 25, 2025
4f252ea
ci(bunny): add rabbitmq tests to ci
arjun-rajappa Nov 27, 2025
da7f8c8
test(bunny): fix failing tests
arjun-rajappa Nov 27, 2025
4e1612d
test(bunny): fix lints and remove dependency on bundler
arjun-rajappa Dec 1, 2025
e84fe1b
feat(bunny): fix typo mistake rabbitmq
arjun-rajappa Dec 1, 2025
132f62d
feat(bunny): refactor to remove code duplication
arjun-rajappa Dec 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ library_gemfile: &library_gemfile
- "./gemfiles/graphql_20.gemfile"
- "./gemfiles/grpc_10.gemfile"
- "./gemfiles/net_http_01.gemfile"
- "./gemfiles/bunny_223.gemfile"
- "./gemfiles/bunny_224.gemfile"
- "./gemfiles/rack_20.gemfile"
- "./gemfiles/rack_30.gemfile"
- "./gemfiles/redis_40.gemfile"
Expand Down Expand Up @@ -56,6 +58,7 @@ executors:
- image: quay.io/minio/minio
command: ["server", "/data"]
- image: s12v/sns
- image: public.ecr.aws/docker/library/rabbitmq:latest
- image: public.ecr.aws/sprig/elasticmq-native
- image: public.ecr.aws/docker/library/mongo:5-focal
mysql2:
Expand Down
8 changes: 8 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,11 @@ end
appraise 'mongo-216' do
gem 'mongo', '>= 2.16', '< 3'
end

appraise 'bunny-223' do
gem 'bunny', '~> 2.23.0'
end

appraise 'bunny-224' do
gem 'bunny', '>= 2.24', '< 3.0'
end
1 change: 0 additions & 1 deletion extras/license_header.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class LicenseHeader < Base
HEADER = '(c) Copyright IBM Corp.'.freeze
HEADER_TEMPLATE = <<~HERE.freeze
# (c) Copyright IBM Corp. %d
# (c) Copyright Instana Inc. %d
HERE

def on_new_investigation
Expand Down
16 changes: 16 additions & 0 deletions gemfiles/bunny_223.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This file was generated by Appraisal

# (c) Copyright IBM Corp. 2025

source "https://rubygems.org"

gem "minitest-reporters"
gem "webmock"
gem "puma"
gem "rack"
gem "rackup"
gem "rack-test"
gem "simplecov", "~> 0.21.2"
gem "bunny", "~> 2.23.0"

gemspec path: "../"
16 changes: 16 additions & 0 deletions gemfiles/bunny_224.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This file was generated by Appraisal

# (c) Copyright IBM Corp. 2025

source "https://rubygems.org"

gem "minitest-reporters"
gem "webmock"
gem "puma"
gem "rack"
gem "rackup"
gem "rack-test"
gem "simplecov", "~> 0.21.2"
gem "bunny", '>= 2.24', '< 3.0'

gemspec path: "../"
2 changes: 1 addition & 1 deletion instana.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = '>= 3.0'
spec.platform = defined?(JRUBY_VERSION) ? 'java' : Gem::Platform::RUBY

spec.add_development_dependency "bundler", "~> 2.0"
# spec.add_development_dependency "bundler", "=> 2.0"
spec.add_development_dependency "rake", "~> 12.0"
spec.add_development_dependency "minitest", "~> 5.20"
spec.add_development_dependency "appraisal"
Expand Down
23 changes: 23 additions & 0 deletions lib/instana/activators/bunny.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# (c) Copyright IBM Corp. 2025

module Instana
module Activators
class Bunny < Activator
def can_instrument?
defined?(::Bunny) &&
defined?(::Bunny::Queue) &&
defined?(::Bunny::Exchange) &&
::Instana.config[:bunny][:enabled]
end

def instrument
require 'instana/instrumentation/bunny'

Check failure on line 14 in lib/instana/activators/bunny.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Move this 'require' statement to the top of the file before any class or module definitions.

See more on https://sonarcloud.io/project/issues?id=instana_ruby-sensor&issues=AZrYU_4bKoZU_B2l_CYb&open=AZrYU_4bKoZU_B2l_CYb&pullRequest=482

::Bunny::Exchange.prepend(::Instana::Instrumentation::BunnyProducer)
::Bunny::Queue.prepend(::Instana::Instrumentation::BunnyConsumer)

true
end
end
end
end
1 change: 1 addition & 0 deletions lib/instana/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def initialize(logger: ::Instana.logger, agent_host: ENV['INSTANA_AGENT_HOST'],
@config[:action_controller] = { :enabled => true }
@config[:action_view] = { :enabled => true }
@config[:active_record] = { :enabled => true }
@config[:bunny] = { :enabled => true }
@config[:dalli] = { :enabled => true }
@config[:excon] = { :enabled => true }
@config[:grpc] = { :enabled => true }
Expand Down
128 changes: 128 additions & 0 deletions lib/instana/instrumentation/bunny.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# (c) Copyright IBM Corp. 2025

module Instana
module Instrumentation
module BunnyProducer
def publish(payload, options = {})
if ::Instana.tracer.tracing?
exchange_name = name.empty? ? 'default' : name
routing_key = options[:routing_key] || ''

kvs = {
rabbitmq: {
sort: 'publish',
address: channel.connection.host,
key: routing_key,
exchange: exchange_name
}
}

::Instana.tracer.in_span(:rabbitmq, attributes: kvs) do |span|
# Inject trace context into message headers
options[:headers] ||= {}
options[:headers]['X-Instana-T'] = span.context.trace_id
options[:headers]['X-Instana-S'] = span.context.span_id
options[:headers]['X-Instana-L'] = span.context.level.to_s

super(payload, options)
end
else
super(payload, options)
end
rescue => e
::Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
raise
end
end

module BunnyConsumer
def pop(options = {})
delivery_info, properties, payload = super(options)

return [delivery_info, properties, payload] unless delivery_info

trace_rabbitmq_consume(delivery_info, properties) do
[delivery_info, properties, payload]
end
rescue => e
log_error(e)
raise
end

def subscribe(options = {}, &block)
if block_given?
wrapped_block = lambda do |delivery_info, properties, payload|
trace_rabbitmq_consume(delivery_info, properties) do
block.call(delivery_info, properties, payload)
end
end

super(options, &wrapped_block)
else
super(options, &block)
end
rescue => e
log_error(e)
raise
end

private

def trace_rabbitmq_consume(delivery_info, properties, &block)
return yield unless ::Instana.tracer.tracing? || extract_context_from_headers(properties)

kvs = build_consume_attributes(delivery_info)
context = extract_context_from_headers(properties)

if context[:trace_id]
trace_with_context(context, kvs, &block)
else
::Instana.tracer.in_span(:rabbitmq, attributes: kvs, &block)
end
end

def build_consume_attributes(delivery_info)
queue_name = name
exchange_name = delivery_info.exchange.empty? ? 'default' : delivery_info.exchange

{
rabbitmq: {
sort: 'consume',
address: channel.connection.host,
queue: queue_name,
exchange: exchange_name,
key: delivery_info.routing_key
}
}
end

def trace_with_context(context, kvs, &block)
instana_context = ::Instana::SpanContext.new(
trace_id: context[:trace_id],
span_id: context[:span_id],
level: context[:level]
)
span = OpenTelemetry::Trace.non_recording_span(instana_context)

Trace.with_span(span) do
::Instana.tracer.in_span(:rabbitmq, attributes: kvs, &block)
end
end

def extract_context_from_headers(properties)
return {} unless properties && properties.headers

headers = properties.headers
{
trace_id: headers['X-Instana-T'],
span_id: headers['X-Instana-S'],
level: headers['X-Instana-L']&.to_i
}.reject { |_, v| v.nil? }
end

def log_error(error)
::Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{error.message}" }
end
end
end
end
6 changes: 3 additions & 3 deletions lib/instana/trace/span_kind.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ module Instana
module SpanKind
# Instana specific spans
REGISTERED_SPANS = [:actioncontroller, :actionview, :activerecord, :excon,
:memcache, :'net-http', :rack, :render, :'rpc-client',
:memcache, :'net-http', :rack, :rabbitmq, :render, :'rpc-client',
:'rpc-server', :'sidekiq-client', :'sidekiq-worker',
:redis, :'resque-client', :'resque-worker', :'graphql.server', :dynamodb, :s3, :sns, :sqs, :'aws.lambda.entry', :activejob, :log, :"mail.actionmailer",
:"aws.lambda.invoke", :mongo, :sequel].freeze
ENTRY_SPANS = [:rack, :'resque-worker', :'rpc-server', :'sidekiq-worker', :'graphql.server', :sqs,
ENTRY_SPANS = [:rack, :rabbitmq, :'resque-worker', :'rpc-server', :'sidekiq-worker', :'graphql.server', :sqs,
:'aws.lambda.entry'].freeze
EXIT_SPANS = [:activerecord, :excon, :'net-http', :'resque-client',
EXIT_SPANS = [:activerecord, :excon, :'net-http', :rabbitmq, :'resque-client',
:'rpc-client', :'sidekiq-client', :redis, :dynamodb, :s3, :sns, :sqs, :log, :"mail.actionmailer",
:"aws.lambda.invoke", :mongo, :sequel].freeze
HTTP_SPANS = [:rack, :excon, :'net-http'].freeze
Expand Down
2 changes: 1 addition & 1 deletion test/activator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_unlimited_activated_set
ENV.delete('INSTANA_ACTIVATE_SET')
subject = activated_set
assert_instance_of Set, subject
assert_equal 32, subject.length
assert_equal 33, subject.length
ensure
ENV.delete('INSTANA_ACTIVATE_SET')
end
Expand Down
Loading
Loading