Skip to content

Commit

Permalink
Add thread_local_tracer_state configuration option that switches betw…
Browse files Browse the repository at this point in the history
…een thread-local and fiber-local storage
  • Loading branch information
markiz committed Mar 7, 2024
1 parent bcb0d5c commit 554a459
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 3 deletions.
7 changes: 7 additions & 0 deletions lib/new_relic/agent/configuration/default_source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,13 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil)
:allowed_from_server => false,
:description => 'When set to `true`, forces a synchronous connection to the New Relic [collector](/docs/using-new-relic/welcome-new-relic/get-started/glossary/#collector) during application startup. For very short-lived processes, this helps ensure the New Relic agent has time to report.'
},
:thread_local_tracer_state => {
:default => false,
:public => true,
:type => Boolean,
:allowed_from_server => false,
:description => 'If `true`, tracer state storage is thread-local, otherwise, fiber-local'
},
:timeout => {
:default => 2 * 60, # 2 minutes
:public => true,
Expand Down
12 changes: 10 additions & 2 deletions lib/new_relic/thread_local_storage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@
module NewRelic
module ThreadLocalStorage
def self.get(thread, key)
thread[key]
if Agent.config[:thread_local_tracer_state]
thread.thread_variable_get(key)
else
thread[key]
end
end

def self.set(thread, key, value)
thread[key] = value
if Agent.config[:thread_local_tracer_state]
thread.thread_variable_set(key, value)
else
thread[key] = value
end
end

def self.[](key)
Expand Down
3 changes: 3 additions & 0 deletions newrelic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,9 @@ common: &default_settings
# the New Relic agent has time to report.
# sync_startup: false

# If true, tracer state storage is thread-local, otherwise, fiber-local
# thread_local_tracer_state: false

# If true, enables use of the thread profiler.
# thread_profiler.enabled: false

Expand Down
2 changes: 1 addition & 1 deletion test/multiverse/suites/rake/instrumentation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def test_invoke_with_tracing_with_exception
NewRelic::Agent::Instrumentation::Rake.stub :should_trace?, true, [instance.name] do
error = RuntimeError.new('expected')
# produce the exception we want to have the method rescue
NewRelic::Agent.stub :config, -> { raise error } do
NewRelic::Agent.stub :instance, -> { raise error } do
logger = MiniTest::Mock.new
NewRelic::Agent.stub :logger, logger do
logger.expect :error, nil, [/^Exception/, error]
Expand Down
10 changes: 10 additions & 0 deletions test/new_relic/agent/tracer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ def test_tracer_aliases
refute_nil state
end

def test_tracer_state_in_fiber_with_thread_local_tracer_state
with_config(:thread_local_tracer_state => true) do
state = Tracer.state
fiber = Fiber.new do
assert_equal Tracer.state, state
end
fiber.resume
end
end

def test_current_transaction_with_transaction
in_transaction do |txn|
assert_equal txn, Tracer.current_transaction
Expand Down
28 changes: 28 additions & 0 deletions test/new_relic/thread_local_storage_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def test_shortcut_ops
def test_new_thread
NewRelic::ThreadLocalStorage[:new_thread] = :parent
thread = Thread.new do
Thread.current.abort_on_exception = true

assert_nil NewRelic::ThreadLocalStorage[:new_thread]
NewRelic::ThreadLocalStorage[:new_thread] = :child
sleep
Expand All @@ -39,4 +41,30 @@ def test_new_thread
assert_equal(:child, NewRelic::ThreadLocalStorage.get(thread, :new_thread))
thread.exit
end

def test_new_fiber_without_thread_local_tracer_state_flag
with_config(:thread_local_tracer_state => false) do
NewRelic::ThreadLocalStorage[:new_fiber_no_flag] = 1
fiber = Fiber.new do
assert_nil NewRelic::ThreadLocalStorage[:new_fiber_no_flag]
NewRelic::ThreadLocalStorage[:new_fiber_no_flag] = 2
end
fiber.resume

assert_equal(1, NewRelic::ThreadLocalStorage[:new_fiber_no_flag])
end
end

def test_new_fiber_with_thread_local_tracer_state_flag
with_config(:thread_local_tracer_state => true) do
NewRelic::ThreadLocalStorage[:new_fiber_with_flag] = 1
fiber = Fiber.new do
assert_equal(1, NewRelic::ThreadLocalStorage[:new_fiber_with_flag])
NewRelic::ThreadLocalStorage[:new_fiber_with_flag] = 2
end
fiber.resume

assert_equal(2, NewRelic::ThreadLocalStorage[:new_fiber_with_flag])
end
end
end

0 comments on commit 554a459

Please sign in to comment.