Skip to content

Commit d0911cf

Browse files
authored
Merge pull request #5 from instana/fix_forking_webservers
Ruby Sensor not detecting/handling forking webservers correctly
2 parents c5702f8 + 484fe6e commit d0911cf

File tree

3 files changed

+64
-9
lines changed

3 files changed

+64
-9
lines changed

lib/instana/agent.rb

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ def initialize
2222
# Supported two states (unannounced & announced)
2323
@state = :unannounced
2424

25+
# Store the pid from process boot so we can detect forks
26+
@pid = Process.pid
27+
2528
# Snapshot data is collected once per process but resent
2629
# every 10 minutes along side process metrics.
2730
@snapshot = take_snapshot
@@ -39,8 +42,9 @@ def initialize
3942
@announce_timer = nil
4043
@collect_timer = nil
4144

42-
# Detect if we're on linux or not (used in host_agent_ready?)
45+
# Detect platform flags
4346
@is_linux = (RUBY_PLATFORM =~ /linux/i) ? true : false
47+
@is_osx = (RUBY_PLATFORM =~ /darwin/i) ? true : false
4448

4549
# In case we're running in Docker, have the default gateway available
4650
# to check in case we're running in bridged network mode
@@ -53,23 +57,68 @@ def initialize
5357
# The agent UUID returned from the host agent
5458
@agent_uuid = nil
5559

60+
collect_process_info
61+
end
62+
63+
# Used in class initialization and after a fork, this method
64+
# collects up process information and stores it in @process
65+
#
66+
def collect_process_info
5667
@process = {}
5768
cmdline = ProcTable.ps(Process.pid).cmdline.split("\0")
5869
@process[:name] = cmdline.shift
5970
@process[:arguments] = cmdline
60-
@process[:original_pid] = Process.pid
71+
72+
if @is_osx
73+
# Handle OSX bug where env vars show up at the end of process name
74+
# such as MANPATH etc..
75+
@process[:name].gsub!(/[_A-Z]+=\S+/, '')
76+
@process[:name].rstrip!
77+
end
78+
79+
@process[:original_pid] = @pid
6180
# This is usually Process.pid but in the case of docker, the host agent
6281
# will return to us the true host pid in which we use to report data.
6382
@process[:report_pid] = nil
6483
end
6584

85+
# Determine whether the pid has changed since Agent start.
86+
#
87+
# @ return [Boolean] true or false to indicate if forked
88+
#
89+
def forked?
90+
@pid != Process.pid
91+
end
92+
93+
# Used post fork to re-initialize state and restart communications with
94+
# the host agent.
95+
#
96+
def after_fork
97+
::Instana.logger.debug "after_fork hook called. Falling back to unannounced state."
98+
99+
# Re-collect process information post fork
100+
@pid = Process.pid
101+
collect_process_info
102+
103+
# Set last snapshot to 10 minutes ago
104+
# so we send a snapshot sooner than later
105+
@last_snapshot = Time.now - 600
106+
107+
transition_to(:unannounced)
108+
start
109+
end
110+
66111
# Sets up periodic timers and starts the agent in a background thread.
67112
#
68113
def start
69114
# The announce timer
70115
# We attempt to announce this ruby sensor to the host agent.
71116
# In case of failure, we try again in 30 seconds.
72117
@announce_timer = @timers.now_and_every(30) do
118+
if forked?
119+
after_fork
120+
break
121+
end
73122
if host_agent_ready? && announce_sensor
74123
::Instana.logger.debug "Announce successful. Switching to metrics collection."
75124
transition_to(:announced)
@@ -81,6 +130,10 @@ def start
81130
# every ::Instana::Collector.interval seconds.
82131
@collect_timer = @timers.every(::Instana::Collector.interval) do
83132
if @state == :announced
133+
if forked?
134+
after_fork
135+
break
136+
end
84137
unless ::Instana::Collector.collect_and_report
85138
# If report has been failing for more than 1 minute,
86139
# fall back to unannounced state

lib/instana/instrumentation/rack.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,21 @@ def call(env)
2727

2828
status, headers, response = @app.call(env)
2929

30-
kvs[:http][:status] = status
30+
if ::Instana.tracer.tracing?
31+
kvs[:http][:status] = status
3132

32-
# Save the IDs before the trace ends so we can place
33-
# them in the response headers in the ensure block
34-
trace_id = ::Instana.tracer.trace_id
35-
span_id = ::Instana.tracer.span_id
33+
# Save the IDs before the trace ends so we can place
34+
# them in the response headers in the ensure block
35+
trace_id = ::Instana.tracer.trace_id
36+
span_id = ::Instana.tracer.span_id
37+
end
3638

3739
[status, headers, response]
3840
rescue Exception => e
3941
::Instana.tracer.log_error(e)
4042
raise
4143
ensure
42-
if headers
44+
if headers && ::Instana.tracer.tracing?
4345
# Set reponse headers; encode as hex string
4446
headers['X-Instana-T'] = ::Instana.tracer.id_to_header(trace_id)
4547
headers['X-Instana-S'] = ::Instana.tracer.id_to_header(span_id)

test/tracing/trace_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_max_value_of_generated_id
2424
# Max is the maximum value for a Java signed long
2525
max_value = 9223372036854775807
2626
100.times do
27-
assert t.send(:generate_id) < max_value
27+
assert t.send(:generate_id) <= max_value
2828
end
2929
end
3030
end

0 commit comments

Comments
 (0)