1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
# frozen_string_literal: true
require "active_support"
require "active_support/core_ext"
require "jaeger/client"
module Labkit
module Tracing
# JaegerFactory will configure Jaeger distributed tracing
class JaegerFactory
# When the probabilistic sampler is used, by default 0.1% of requests will be traced
DEFAULT_PROBABILISTIC_RATE = 0.001
# The default port for the Jaeger agent UDP listener
DEFAULT_UDP_PORT = 6831
# Reduce this from default of 10 seconds as the Ruby jaeger
# client doesn't have overflow control, leading to very large
# messages which fail to send over UDP (max packet = 64k)
# Flush more often, with smaller packets
FLUSH_INTERVAL = 5
def self.create_tracer(service_name, options)
# The service_name parameter from GITLAB_TRACING takes precedence over the application one
service_name = options[:service_name] if options[:service_name]
# parse reporter headers as necessary
headers = build_headers(options)
kwargs = {
service_name: service_name,
sampler: get_sampler(options[:sampler], options[:sampler_param]),
reporter: get_reporter(service_name, options[:http_endpoint], options[:udp_endpoint], headers),
}.compact
extra_params = options.except(:sampler, :sampler_param, :http_endpoint, :udp_endpoint, :strict_parsing, :debug)
if extra_params.present?
message = "jaeger tracer: invalid option: #{extra_params.keys.join(", ")}"
raise message if options[:strict_parsing]
warn message
end
Jaeger::Client.build(**kwargs)
end
def self.build_headers(options)
return unless options&.key?(:http_endpoint)
http_endpoint = options[:http_endpoint]
parsed = URI.parse(http_endpoint)
headers = {}
# add basic auth header only when both user and password are setup correctly
user = parsed.user
password = parsed.password
if user.present? && password.present?
headers["Authorization"] = "Basic " + Base64.strict_encode64("#{user}:#{password}")
end
return headers
end
private_class_method :build_headers
def self.get_sampler(sampler_type, sampler_param)
case sampler_type
when "probabilistic"
sampler_rate = sampler_param ? sampler_param.to_f : DEFAULT_PROBABILISTIC_RATE
Jaeger::Samplers::Probabilistic.new(rate: sampler_rate)
when "const"
const_value = sampler_param == "1"
Jaeger::Samplers::Const.new(const_value)
end
end
private_class_method :get_sampler
def self.get_reporter(service_name, http_endpoint, udp_endpoint, headers)
encoder = Jaeger::Encoders::ThriftEncoder.new(service_name: service_name)
if http_endpoint.present?
sender = get_http_sender(encoder, http_endpoint, headers)
elsif udp_endpoint.present?
sender = get_udp_sender(encoder, udp_endpoint)
else
return nil
end
Jaeger::Reporters::RemoteReporter.new(sender: sender, flush_interval: FLUSH_INTERVAL)
end
private_class_method :get_reporter
def self.get_http_sender(encoder, address, headers)
Jaeger::HttpSender.new(url: address, headers: headers, encoder: encoder, logger: Logger.new(STDOUT))
end
private_class_method :get_http_sender
def self.get_udp_sender(encoder, address)
pair = address.split(":", 2)
host = pair[0]
port = pair[1] ? pair[1].to_i : DEFAULT_UDP_PORT
Jaeger::UdpSender.new(host: host, port: port, encoder: encoder, logger: Logger.new(STDOUT))
end
private_class_method :get_udp_sender
end
end
end
|