Skip to content

Commit

Permalink
Merge pull request #12 from instana/docker_improvements
Browse files Browse the repository at this point in the history
Improved Docker support.
  • Loading branch information
pglombardo committed Nov 17, 2016
2 parents 2872648 + 859261f commit fc96679
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 22 deletions.
88 changes: 67 additions & 21 deletions lib/instana/agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ def initialize
# every 10 minutes along side process metrics.
@snapshot = take_snapshot

# Set last snapshot to 10 minutes ago
# so we send a snapshot on first report
@last_snapshot = Time.now - 601
# Set last snapshot to just under 10 minutes ago
# so we send a snapshot sooner than later
@last_snapshot = Time.now - 570

# Timestamp of the last successful response from
# entity data reporting.
Expand All @@ -43,7 +43,23 @@ def initialize

# In case we're running in Docker, have the default gateway available
# to check in case we're running in bridged network mode
@default_gateway = `/sbin/ip route | awk '/default/ { print $3 }'`.chomp
if @is_linux
@default_gateway = `/sbin/ip route | awk '/default/ { print $3 }'`.chomp
else
@default_gateway = nil
end

# The agent UUID returned from the host agent
@agent_uuid = nil

@process = {}
cmdline = ProcTable.ps(Process.pid).cmdline.split("\0")
@process[:name] = cmdline.shift
@process[:arguments] = cmdline
@process[:original_pid] = Process.pid
# This is usually Process.pid but in the case of docker, the host agent
# will return to us the true host pid in which we use to report data.
@process[:report_pid] = nil
end

##
Expand Down Expand Up @@ -100,23 +116,30 @@ def start
# the host agent.
#
def announce_sensor
process = ProcTable.ps(Process.pid)
announce_payload = {}
announce_payload[:pid] = Process.pid

arguments = process.cmdline.split(' ')
arguments.shift
announce_payload[:args] = arguments
announce_payload[:pid] = pid_namespace? ? get_real_pid : Process.pid
announce_payload[:args] = @process[:arguments]

uri = URI.parse("http://#{@host}:#{@port}/#{DISCOVERY_PATH}")
req = Net::HTTP::Put.new(uri)
req.body = announce_payload.to_json

# ::Instana.logger.debug "Announce: http://#{@host}:#{@port}/#{DISCOVERY_PATH} - payload: #{req.body}"

response = make_host_agent_request(req)
response && (response.code.to_i == 200) ? true : false

if response && (response.code.to_i == 200)
data = JSON.parse(response.body)
@process[:report_pid] = data['pid']
@agent_uuid = data['agentUuid']
true
else
false
end
rescue => e
Instana.logger.debug "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}"
Instana.logger.debug e.backtrace.join("\r\n")
return false
end

##
Expand All @@ -126,14 +149,21 @@ def announce_sensor
#
def report_entity_data(payload)
with_snapshot = false
path = "com.instana.plugin.ruby.#{Process.pid}"
path = "com.instana.plugin.ruby.#{@process[:report_pid]}"
uri = URI.parse("http://#{@host}:#{@port}/#{path}")
req = Net::HTTP::Post.new(uri)

# Every 5 minutes, send snapshot data as well
if (Time.now - @last_snapshot) > 600
with_snapshot = true
payload.merge!(@snapshot)

# Add in process related that could have changed since
# snapshot was taken.
p = { :pid => @process[:report_pid] }
p[:name] = @process[:name]
p[:exec_args] = @process[:arguments]
payload.merge!(p)
end

req.body = payload.to_json
Expand All @@ -142,14 +172,14 @@ def report_entity_data(payload)
if response
last_entity_response = response.code.to_i

#::Instana.logger.debug "entity http://#{@host}:#{@port}/#{path}: response=#{last_entity_response}: #{payload.to_json}"

if last_entity_response == 200
@entity_last_seen = Time.now
@last_snapshot = Time.now if with_snapshot

#::Instana.logger.debug "entity response #{last_entity_response}: #{payload.to_json}"
return true
end
#::Instana.logger.debug "entity response #{last_entity_response}: #{payload.to_json}"
end
false
rescue => e
Expand Down Expand Up @@ -241,13 +271,35 @@ def make_host_agent_request(req)
end
response
rescue Errno::ECONNREFUSED => e
Instana.logger.debug "Agent not responding. Connection refused."
return nil
rescue => e
Instana.logger.debug "Host agent request error: #{e.inspect}"
return nil
end

##
# pid_namespace?
#
# Indicates whether we are running in a pid namespace (such as
# Docker).
#
def pid_namespace?
return false unless @is_linux
Process.pid != get_real_pid
end

##
# get_real_pid
#
# Attempts to determine the true process ID by querying the
# /proc/<pid>/sched file. This works on linux currently.
#
def get_real_pid
raise RuntimeError.new("Unsupported platform: get_real_pid") unless @is_linux
v = File.open("/proc/#{Process.pid}/sched", &:readline)
v.match(/\d+/).to_s.to_i
end

##
# take_snapshot
#
Expand All @@ -258,14 +310,8 @@ def take_snapshot
data = {}

data[:sensorVersion] = ::Instana::VERSION
data[:pid] = ::Process.pid
data[:ruby_version] = RUBY_VERSION

process = ::ProcTable.ps(Process.pid)
arguments = process.cmdline.split(' ')
data[:name] = arguments.shift
data[:exec_args] = arguments

# Since a snapshot is only taken on process boot,
# this is ok here.
data[:start_time] = Time.now.to_s
Expand Down
14 changes: 13 additions & 1 deletion test/agent_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ def test_no_host_agent

def test_announce_sensor
url = "http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/com.instana.plugin.ruby.discovery"
stub_request(:put, url)
json = { 'pid' => Process.pid, 'agentUuid' => 'abc' }.to_json
stub_request(:put, url).to_return(:body => json, :status => 200)

assert_equal true, ::Instana.agent.announce_sensor
end
Expand All @@ -30,6 +31,11 @@ def test_failed_announce_sensor
end

def test_entity_data_report
url = "http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/com.instana.plugin.ruby.discovery"
json = { 'pid' => Process.pid, 'agentUuid' => 'abc' }.to_json
stub_request(:put, url).to_return(:body => json, :status => 200)
::Instana.agent.announce_sensor

url = "http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/com.instana.plugin.ruby.#{Process.pid}"
stub_request(:post, url)

Expand All @@ -38,6 +44,12 @@ def test_entity_data_report
end

def test_failed_entity_data_report
url = "http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/com.instana.plugin.ruby.discovery"
json = { 'pid' => Process.pid, 'agentUuid' => 'abc' }.to_json
stub_request(:put, url).to_return(:body => json, :status => 200)

::Instana.agent.announce_sensor

url = "http://#{::Instana.config[:agent_host]}:#{::Instana.config[:agent_port]}/com.instana.plugin.ruby.#{Process.pid}"
stub_request(:post, url).to_raise(Errno::ECONNREFUSED)

Expand Down

0 comments on commit fc96679

Please sign in to comment.