class ZipkinTracer::HostnameResolver

Resolves hostnames in the endpoints of the spans. Resolving hostnames is a very expensive operation. We want to store them raw in the main thread and resolve them in a different thread where we do not affect execution times.

Constants

IP_FIELD
LOCALHOST
LOCALHOST_I32
MASK
MAX_I32

Public Instance Methods

spans_with_ips(spans, ip_format) click to toggle source
# File lib/zipkin-tracer/hostname_resolver.rb, line 8
def spans_with_ips(spans, ip_format)
  hosts = unique_hosts(spans)
  resolved_hosts = resolve(hosts, ip_format)

  each_endpoint(spans) do |endpoint|
    hostname = endpoint.ipv4
    next unless hostname
    next if resolved_ip_address?(hostname.to_s)

    endpoint.ipv4 = resolved_hosts[hostname]
  end
end

Private Instance Methods

each_endpoint(spans) { |endpoint| ... } click to toggle source
# File lib/zipkin-tracer/hostname_resolver.rb, line 36
def each_endpoint(spans, &block)
  spans.each do |span|
    [span.local_endpoint, span.remote_endpoint].each do |endpoint|
      yield endpoint if endpoint
    end
  end
end
host_to_format(hostname, ip_format) click to toggle source
# File lib/zipkin-tracer/hostname_resolver.rb, line 60
def host_to_format(hostname, ip_format)
  begin
    ip_format == :string ? Socket.getaddrinfo(hostname, nil, :INET).first[IP_FIELD] : host_to_i32(hostname)
  rescue
    ip_format == :string ? LOCALHOST : LOCALHOST_I32
  end
end
host_to_i32(host) click to toggle source
# File lib/zipkin-tracer/hostname_resolver.rb, line 68
def host_to_i32(host)
  unsigned_i32 = Socket.getaddrinfo(host, nil)[0][3].split(".").map do |i|
    i.to_i
  end.inject(0) { |a,e| (a << 8) + e }

  signed_i32 = if unsigned_i32 > MAX_I32
    -1 * ((unsigned_i32 ^ MASK) + 1)
  else
    unsigned_i32
  end

  signed_i32
end
resolve(hosts, ip_format) click to toggle source
# File lib/zipkin-tracer/hostname_resolver.rb, line 53
def resolve(hosts, ip_format)
  hosts.each_with_object({}) do |host, host_map|
    hostname = host.ipv4  # This field has been temporarly used to store the hostname.
    host_map[hostname] = host_to_format(hostname, ip_format) if hostname
  end
end
resolved_ip_address?(ip_string) click to toggle source
# File lib/zipkin-tracer/hostname_resolver.rb, line 29
def resolved_ip_address?(ip_string)
  # When the ip_format is string, we will match with one of these two regexp
  # When the ip_format is :i32 (used by kafka), we just check the string is a number
  !!(ip_string =~ Regexp.union(Resolv::IPv4::Regex, Resolv::IPv6::Regex)) ||
    ip_string.to_i.to_s == ip_string
end
unique_hosts(spans) click to toggle source

Using this to resolve only once per host

# File lib/zipkin-tracer/hostname_resolver.rb, line 45
def unique_hosts(spans)
  hosts = []
  each_endpoint(spans) do |endpoint|
    hosts.push(endpoint)
  end
  hosts.uniq
end