lib/opentelemetry/exporter/zipkin/exporter.rb in opentelemetry-exporter-zipkin-0.21.0 vs lib/opentelemetry/exporter/zipkin/exporter.rb in opentelemetry-exporter-zipkin-0.22.0

- old
+ new

@@ -27,11 +27,12 @@ WRITE_TIMEOUT_SUPPORTED = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6') private_constant(:KEEP_ALIVE_TIMEOUT, :RETRY_COUNT, :WRITE_TIMEOUT_SUPPORTED) def initialize(endpoint: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_ZIPKIN_ENDPOINT', default: 'http://localhost:9411/api/v2/spans'), headers: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_ZIPKIN_TRACES_HEADERS', 'OTEL_EXPORTER_ZIPKIN_HEADERS'), - timeout: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_ZIPKIN_TRACES_TIMEOUT', 'OTEL_EXPORTER_ZIPKIN_TIMEOUT', default: 10)) + timeout: OpenTelemetry::Common::Utilities.config_opt('OTEL_EXPORTER_ZIPKIN_TRACES_TIMEOUT', 'OTEL_EXPORTER_ZIPKIN_TIMEOUT', default: 10), + metrics_reporter: nil) raise ArgumentError, "invalid url for Zipkin::Exporter #{endpoint}" unless OpenTelemetry::Common::Utilities.valid_url?(endpoint) raise ArgumentError, 'headers must be comma-separated k=v pairs or a Hash' unless valid_headers?(headers) @uri = if endpoint == ENV['OTEL_EXPORTER_ZIPKIN_ENDPOINT'] URI("#{endpoint}/api/v2/spans") @@ -48,10 +49,11 @@ @headers = case headers when String then CSV.parse(headers, col_sep: '=', row_sep: ',').to_h when Hash then headers end + @metrics_reporter = metrics_reporter || OpenTelemetry::SDK::Trace::Export::MetricsReporter @shutdown = false end # Called to export sampled {OpenTelemetry::SDK::Trace::SpanData} structs. # @@ -64,10 +66,11 @@ return FAILURE if @shutdown zipkin_spans = encode_spans(span_data) send_spans(zipkin_spans, timeout: timeout) rescue StandardError => e + @metrics_reporter.add_to_counter('otel.zipkin_exporter.failure', labels: { 'reason' => e.class.to_s }) OpenTelemetry.handle_error(exception: e, message: 'unexpected error in Zipkin::Exporter#export') FAILURE end # Called when {OpenTelemetry::SDK::Trace::TracerProvider#force_flush} is called, if @@ -110,11 +113,11 @@ true rescue ArgumentError false end - def send_spans(zipkin_spans, timeout: nil) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength + def send_spans(zipkin_spans, timeout: nil) # rubocop:disable Metrics/MethodLength retry_count = 0 timeout ||= @timeout start_time = OpenTelemetry::Common::Utilities.timeout_timestamp around_request do # rubocop:disable Metrics/BlockLength request = Net::HTTP::Post.new(@path) @@ -128,11 +131,11 @@ @http.open_timeout = remaining_timeout @http.read_timeout = remaining_timeout @http.write_timeout = remaining_timeout if WRITE_TIMEOUT_SUPPORTED @http.start unless @http.started? - response = @http.request(request) + response = measure_request_duration { @http.request(request) } response.body # Read and discard body # in opentelemetry-js 200-399 is succcess, in opentelemetry-collector zipkin exporter,200-299 is a success # zipkin api docs list 202 as default success code # https://zipkin.io/zipkin-api/#/default/post_spans # TODO: redirect @@ -169,11 +172,11 @@ def handle_redirect(location) # TODO: figure out destination and reinitialize @http and @path end - def backoff?(retry_after: nil, retry_count:, reason:) + def backoff?(retry_count:, reason:, retry_after: nil) return false if retry_count > RETRY_COUNT # TODO: metric exporter sleep_interval = nil @@ -194,9 +197,22 @@ end sleep_interval ||= rand(2**retry_count) sleep(sleep_interval) true + end + + def measure_request_duration + start = Process.clock_gettime(Process::CLOCK_MONOTONIC) + begin + response = yield + ensure + stop = Process.clock_gettime(Process::CLOCK_MONOTONIC) + duration_ms = 1000.0 * (stop - start) + @metrics_reporter.record_value('otel.zipkin_exporter.request_duration', + value: duration_ms, + labels: { 'status' => response&.code || 'unknown' }) + end end end end end end