# frozen_string_literal: true module OpenTracing module Instrumentation module Sidekiq # Sidekiq producer middleware class ClientMiddleware extend Forwardable DEFAULT_SPAN_KIND = 'producer' DEFAULT_OPERATION_NAME_TEMPLATE = \ 'sidekiq_enqueue(%s)' DEFAULT_OPERATION_NAME_BUILDER = \ Common::OperationNameBuilder.new( operation_name_template: DEFAULT_OPERATION_NAME_TEMPLATE, ) attr_reader :tracer, :tagger, :error_writter, :logger, :span_kind, :operation_name_builder # rubocop:disable Metrics/ParameterLists def initialize( tracer: OpenTracing.global_tracer, tagger: JobTagger.new, error_writter: Common::ErrorWriter.new, logger: nil, span_kind: DEFAULT_SPAN_KIND, operation_name_builder: DEFAULT_OPERATION_NAME_BUILDER ) @tracer = tracer @tagger = tagger @error_writter = error_writter @logger = logger @span_kind = span_kind @operation_name_builder = operation_name_builder end # rubocop:enable Metrics/ParameterLists def call(_worker_class, job, _queue, _redis_pool, &block) scope = safe_start_scope(job) inject(scope.span.context, job) log(scope.span, job, &block) ensure safe_close_scope(scope) end private def safe_start_scope(job) tags = build_tags(job) operation_name = operation_name_builder.build(tags) tracer.start_active_span(operation_name, tags: tags) rescue StandardError => e logger&.error(e) end def safe_close_scope(scope) return unless scope scope.close rescue StandardError => e logger&.error(e) end def log(span, job) tagger.write_args_log(span, job['jid'], job['args']) yield rescue StandardError => e error_writter.write_error(span, e) raise end def build_tags(job) tagger.build_tags(job, span_kind) end def inject(span_context, carrier) tracer.inject(span_context, OpenTracing::FORMAT_TEXT_MAP, carrier) end end end end end