opentracing-instrumentation 0.1.14 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.drone.jsonnet +3 -3
  3. data/.gitlab-ci.yml +9 -9
  4. data/.rubocop.yml +6 -0
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +4 -0
  7. data/GEM_VERSION +1 -1
  8. data/Gemfile +7 -7
  9. data/Gemfile.lock +29 -24
  10. data/lib/opentracing/instrumentation/bunny.rb +11 -11
  11. data/lib/opentracing/instrumentation/bunny/regexp_routing_key_sanitazer.rb +1 -1
  12. data/lib/opentracing/instrumentation/common.rb +2 -0
  13. data/lib/opentracing/instrumentation/common/error_writer.rb +7 -2
  14. data/lib/opentracing/instrumentation/common/operation_name_builder.rb +23 -0
  15. data/lib/opentracing/instrumentation/faraday/response_logger.rb +4 -4
  16. data/lib/opentracing/instrumentation/faraday/trace_middleware.rb +1 -1
  17. data/lib/opentracing/instrumentation/hutch.rb +6 -6
  18. data/lib/opentracing/instrumentation/mongo.rb +2 -0
  19. data/lib/opentracing/instrumentation/mongo/query_sanitazer.rb +18 -5
  20. data/lib/opentracing/instrumentation/mongo/sample_safety_argument_checker.rb +30 -0
  21. data/lib/opentracing/instrumentation/mongo/trace_subscriber.rb +5 -5
  22. data/lib/opentracing/instrumentation/rack/extract_middleware.rb +24 -5
  23. data/lib/opentracing/instrumentation/rack/http_tagger.rb +3 -3
  24. data/lib/opentracing/instrumentation/rack/trace_middleware.rb +5 -5
  25. data/lib/opentracing/instrumentation/redis/config.rb +5 -5
  26. data/lib/opentracing/instrumentation/redis/tracing_driver_wrapper.rb +4 -4
  27. data/lib/opentracing/instrumentation/sidekiq/client_middleware.rb +41 -18
  28. data/lib/opentracing/instrumentation/sidekiq/job_tagger.rb +7 -7
  29. data/lib/opentracing/instrumentation/sidekiq/server_middleware.rb +41 -15
  30. data/lib/opentracing/instrumentation/thrift.rb +13 -5
  31. data/lib/opentracing/instrumentation/thrift/traced_processor.rb +111 -0
  32. data/lib/opentracing/instrumentation/thrift/traced_processor_config.rb +37 -0
  33. data/lib/opentracing/instrumentation/thrift/traced_processor_operation_name_builder.rb +41 -0
  34. data/lib/opentracing/instrumentation/thrift/traced_processor_tags_builder.rb +30 -0
  35. data/lib/opentracing/instrumentation/thrift/traced_protocol.rb +31 -22
  36. data/lib/opentracing/instrumentation/thrift/traced_protocol_config.rb +7 -0
  37. data/lib/opentracing/instrumentation/thrift/traced_protocol_factory.rb +1 -0
  38. data/lib/opentracing/instrumentation/thrift/traced_protocol_operation_name_builder.rb +8 -2
  39. data/lib/opentracing/instrumentation/thrift/traced_protocol_tags_builder.rb +6 -2
  40. data/opentracing-instrumentation.gemspec +6 -4
  41. metadata +23 -16
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenTracing
4
+ module Instrumentation
5
+ module Mongo
6
+ # SampleSafetyArgumentChecker check argument to safety
7
+ # Draft implementation
8
+ class SampleSafetyArgumentChecker
9
+ DEFAULT_SAFE_ARGUMENTS = [
10
+ '$readPreference',
11
+ '$clusterTime',
12
+ ].freeze
13
+
14
+ attr_reader :safe_arguments
15
+
16
+ def initialize(safe_arguments: DEFAULT_SAFE_ARGUMENTS)
17
+ @safe_arguments = safe_arguments
18
+ end
19
+
20
+ # check
21
+ #
22
+ # @return (TrueClass, FalseClass) `true`, if argument safe and not
23
+ # not should be cleaned. Otherwise return `false``.
24
+ def argument_safe?(_command_name, argument_path, _argument_value)
25
+ safe_arguments.include?(argument_path)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -43,11 +43,11 @@ module OpenTracing
43
43
 
44
44
  private
45
45
 
46
- attr_reader :tracer
47
- attr_reader :scope_store
48
- attr_reader :monitor
49
- attr_reader :operation_name_builder
50
- attr_reader :sanitazer
46
+ attr_reader :tracer,
47
+ :scope_store,
48
+ :monitor,
49
+ :operation_name_builder,
50
+ :sanitazer
51
51
 
52
52
  def build_operation_name(event)
53
53
  operation_name_builder.build_operation_name(event)
@@ -18,15 +18,21 @@ module OpenTracing
18
18
 
19
19
  # @param app [RackApp] inner rack application
20
20
  # @param tracer [OpenTracing::Tracer]
21
- def initialize(app, tracer: OpenTracing.global_tracer)
21
+ # @param logger [Logger]
22
+ def initialize(
23
+ app,
24
+ tracer: OpenTracing.global_tracer,
25
+ logger: nil
26
+ )
22
27
  @app = app
23
28
  @tracer = tracer
29
+ @logger = logger
24
30
  end
25
31
 
26
32
  # @param env [Hash<String, String>] rack env
27
33
  def call(env)
28
34
  span_context = @tracer.extract(OpenTracing::FORMAT_RACK, env)
29
- return @app.call unless span_context
35
+ return @app.call(env) unless span_context
30
36
 
31
37
  with_scope(span_context) do
32
38
  @app.call(env)
@@ -36,12 +42,25 @@ module OpenTracing
36
42
  private
37
43
 
38
44
  def with_scope(span_context)
39
- fake_span = FakeSpan.new(span_context)
40
- scope = @tracer.scope_manager.activate(fake_span, finish_on_close: false)
45
+ scope = safe_create_scope(span_context)
41
46
 
42
47
  yield
43
48
  ensure
44
- scope.close
49
+ safe_close_scope(scope)
50
+ end
51
+
52
+ def safe_create_scope(span_context)
53
+ fake_span = FakeSpan.new(span_context)
54
+ @tracer.scope_manager.activate(fake_span, finish_on_close: false)
55
+ rescue StandardError => e
56
+ @logger&.error(e)
57
+ nil
58
+ end
59
+
60
+ def safe_close_scope(scope)
61
+ scope&.close
62
+ rescue StandardError => e
63
+ @logger&.error(e)
45
64
  end
46
65
  end
47
66
  end
@@ -50,15 +50,15 @@ module OpenTracing
50
50
 
51
51
  def prepare_request_mapping(source_mapping)
52
52
  source_mapping.map do |key, header|
53
- rack_header = 'HTTP_' + header.tr('-', '_').upcase
54
- tag_name = 'http.request.' + key.to_s
53
+ rack_header = "HTTP_#{header.tr('-', '_').upcase}"
54
+ tag_name = "http.request.#{key}"
55
55
  [tag_name, rack_header]
56
56
  end.to_h
57
57
  end
58
58
 
59
59
  def prepare_response_mapping(source_mapping)
60
60
  source_mapping.map do |key, header|
61
- tag_name = 'http.response.' + key.to_s
61
+ tag_name = "http.response.#{key}"
62
62
  header_regexp = /^#{header}$/i
63
63
  [tag_name, header_regexp]
64
64
  end.to_h
@@ -36,10 +36,10 @@ module OpenTracing
36
36
 
37
37
  private
38
38
 
39
- attr_reader :app
40
- attr_reader :http_tagger
41
- attr_reader :tracer
42
- attr_reader :logger
39
+ attr_reader :app,
40
+ :http_tagger,
41
+ :tracer,
42
+ :logger
43
43
 
44
44
  def trace_request(env)
45
45
  extracted_ctx = tracer.extract(OpenTracing::FORMAT_RACK, env)
@@ -84,7 +84,7 @@ module OpenTracing
84
84
  def set_header_tags(span, headers)
85
85
  http_tagger
86
86
  .response_tags(headers)
87
- .each(&span.method(:set_tag))
87
+ .each { |(key, value)| span.set_tag(key, value) }
88
88
  end
89
89
 
90
90
  def error_tag(span, error)
@@ -14,11 +14,11 @@ module OpenTracing
14
14
  DEFAULT_LOG_REPLY = false
15
15
  DEFAULT_COMPONENT = 'kv'
16
16
 
17
- attr_accessor :tracer
18
- attr_accessor :operation_name_pattern
19
- attr_accessor :log_args
20
- attr_accessor :log_reply
21
- attr_accessor :component
17
+ attr_accessor :tracer,
18
+ :operation_name_pattern,
19
+ :log_args,
20
+ :log_reply,
21
+ :component
22
22
 
23
23
  def initialize(
24
24
  tracer: OpenTracing.global_tracer,
@@ -35,8 +35,8 @@ module OpenTracing
35
35
  end
36
36
  end
37
37
 
38
- attr_reader :connection
39
- attr_reader :span_builder
38
+ attr_reader :connection,
39
+ :span_builder
40
40
 
41
41
  def initialize(
42
42
  connection:,
@@ -80,8 +80,8 @@ module OpenTracing
80
80
 
81
81
  private
82
82
 
83
- attr_reader :pipeline_scope
84
- attr_reader :error_writer
83
+ attr_reader :pipeline_scope,
84
+ :error_writer
85
85
 
86
86
  def peer_addr
87
87
  "#{@host}:#{@port}"
@@ -7,41 +7,66 @@ module OpenTracing
7
7
  class ClientMiddleware
8
8
  extend Forwardable
9
9
 
10
- DEFAULT_SPAN_NAME = 'sidekiq_enqueue'
11
10
  DEFAULT_SPAN_KIND = 'producer'
12
11
 
13
- attr_reader :tracer
14
- attr_reader :tagger
15
- attr_reader :error_writter
16
- attr_reader :span_kind
17
- attr_reader :span_name
12
+ DEFAULT_OPERATION_NAME_TEMPLATE = \
13
+ 'sidekiq_enqueue(%<sidekiq.class>s)'
14
+ DEFAULT_OPERATION_NAME_BUILDER = \
15
+ Common::OperationNameBuilder.new(
16
+ operation_name_template: DEFAULT_OPERATION_NAME_TEMPLATE,
17
+ )
18
18
 
19
+ attr_reader :tracer,
20
+ :tagger,
21
+ :error_writter,
22
+ :logger,
23
+ :span_kind,
24
+ :operation_name_builder
25
+
26
+ # rubocop:disable Metrics/ParameterLists
19
27
  def initialize(
20
28
  tracer: OpenTracing.global_tracer,
21
29
  tagger: JobTagger.new,
22
30
  error_writter: Common::ErrorWriter.new,
31
+ logger: nil,
23
32
  span_kind: DEFAULT_SPAN_KIND,
24
- span_name: DEFAULT_SPAN_NAME
33
+ operation_name_builder: DEFAULT_OPERATION_NAME_BUILDER
25
34
  )
26
35
  @tracer = tracer
27
36
  @tagger = tagger
28
37
  @error_writter = error_writter
38
+ @logger = logger
29
39
  @span_kind = span_kind
30
- @span_name = span_name
40
+ @operation_name_builder = operation_name_builder
31
41
  end
42
+ # rubocop:enable Metrics/ParameterLists
32
43
 
33
- def call(_worker_class, job, _queue, _redis_pool)
34
- scope = tracer.start_active_span(span_name, **build_span_args(job))
44
+ def call(_worker_class, job, _queue, _redis_pool, &block)
45
+ scope = safe_start_scope(job)
35
46
  inject(scope.span.context, job)
36
- log(scope.span, job) do
37
- yield
38
- end
47
+ log(scope.span, job, &block)
39
48
  ensure
40
- scope.close
49
+ safe_close_scope(scope)
41
50
  end
42
51
 
43
52
  private
44
53
 
54
+ def safe_start_scope(job)
55
+ tags = build_tags(job)
56
+ operation_name = operation_name_builder.build(tags)
57
+ tracer.start_active_span(operation_name, tags: tags)
58
+ rescue StandardError => e
59
+ logger&.error(e)
60
+ end
61
+
62
+ def safe_close_scope(scope)
63
+ return unless scope
64
+
65
+ scope.close
66
+ rescue StandardError => e
67
+ logger&.error(e)
68
+ end
69
+
45
70
  def log(span, job)
46
71
  tagger.write_args_log(span, job['jid'], job['args'])
47
72
 
@@ -51,10 +76,8 @@ module OpenTracing
51
76
  raise
52
77
  end
53
78
 
54
- def build_span_args(job)
55
- {
56
- tags: tagger.build_tags(job, span_kind),
57
- }
79
+ def build_tags(job)
80
+ tagger.build_tags(job, span_kind)
58
81
  end
59
82
 
60
83
  def inject(span_context, carrier)
@@ -12,8 +12,8 @@ module OpenTracing
12
12
 
13
13
  DEFAULT_COMPONENT = 'sidekiq'
14
14
 
15
- attr_accessor :component
16
- attr_accessor :log_args
15
+ attr_accessor :component,
16
+ :log_args
17
17
 
18
18
  # @param component [String] component name
19
19
  # @param log_args [TrueClass, FalseClass] enable attribute logging
@@ -30,11 +30,11 @@ module OpenTracing
30
30
  # build tags from job data and static attributes
31
31
  def build_tags(job, span_kind)
32
32
  {
33
- 'component' => component,
34
- 'span.kind' => span_kind,
35
- 'sidekiq.queue' => job['queue'],
36
- 'sidekiq.class' => job['class'],
37
- 'sidekiq.retry' => job['retry'],
33
+ component: component,
34
+ 'span.kind': span_kind,
35
+ 'sidekiq.queue': job['queue'],
36
+ 'sidekiq.class': job['class'],
37
+ 'sidekiq.retry': job['retry'],
38
38
  }
39
39
  end
40
40
 
@@ -9,41 +9,66 @@ module OpenTracing
9
9
  class ServerMiddleware
10
10
  extend Forwardable
11
11
 
12
- DEFAULT_SPAN_NAME = 'sidekiq_perform'
13
12
  DEFAULT_SPAN_KIND = 'consumer'
14
13
 
15
- attr_reader :tracer
16
- attr_reader :tagger
17
- attr_reader :error_writter
18
- attr_reader :span_kind
19
- attr_reader :span_name
14
+ DEFAULT_OPERATION_NAME_TEMPLATE = \
15
+ 'sidekiq_perform(%<sidekiq.class>s)'
16
+ DEFAULT_OPERATION_NAME_BUILDER = \
17
+ Common::OperationNameBuilder.new(
18
+ operation_name_template: DEFAULT_OPERATION_NAME_TEMPLATE,
19
+ )
20
20
 
21
+ attr_reader :tracer,
22
+ :tagger,
23
+ :error_writter,
24
+ :logger,
25
+ :span_kind,
26
+ :operation_name_builder
27
+
28
+ # rubocop:disable Metrics/ParameterLists
21
29
  def initialize(
22
30
  tracer: OpenTracing.global_tracer,
23
31
  tagger: JobTagger.new,
24
32
  error_writter: Common::ErrorWriter.new,
33
+ logger: nil,
25
34
  span_kind: DEFAULT_SPAN_KIND,
26
- span_name: DEFAULT_SPAN_NAME
35
+ operation_name_builder: DEFAULT_OPERATION_NAME_BUILDER
27
36
  )
28
37
  @tracer = tracer
29
38
  @tagger = tagger
30
39
  @error_writter = error_writter
40
+ @logger = logger
31
41
  @span_kind = span_kind
32
- @span_name = span_name
42
+ @operation_name_builder = operation_name_builder
33
43
  end
44
+ # rubocop:enable Metrics/ParameterLists
34
45
 
35
- def call(_worker, job, _queue)
36
- scope = tracer.start_active_span(span_name, **build_span_args(job))
46
+ def call(_worker, job, _queue, &block)
47
+ scope = safe_start_scope(job)
37
48
 
38
- log(scope.span, job) do
39
- yield
40
- end
49
+ log(scope.span, job, &block)
41
50
  ensure
42
- scope.close
51
+ scope&.close
43
52
  end
44
53
 
45
54
  private
46
55
 
56
+ def safe_start_scope(job)
57
+ tags = tagger.build_tags(job, span_kind)
58
+ operation_name = operation_name_builder.build(tags)
59
+ tracer.start_active_span(operation_name, tags: tags, **build_span_args(job))
60
+ rescue StandardError => e
61
+ logger&.error(e)
62
+ end
63
+
64
+ def safe_close_scope(scope)
65
+ return unless socpe
66
+
67
+ scope.close
68
+ rescue StandardError => e
69
+ logger&.error(e)
70
+ end
71
+
47
72
  def log(span, job)
48
73
  tagger.write_args_log(span, job['jid'], job['args'])
49
74
 
@@ -56,12 +81,13 @@ module OpenTracing
56
81
  def build_span_args(job)
57
82
  {
58
83
  references: extract_references(job),
59
- tags: tagger.build_tags(job, span_kind),
60
84
  }
61
85
  end
62
86
 
63
87
  def extract_references(job)
64
88
  span_context = tracer.extract(OpenTracing::FORMAT_TEXT_MAP, job)
89
+ return unless span_context
90
+
65
91
  [OpenTracing::Reference.follows_from(span_context)]
66
92
  end
67
93
  end
@@ -15,16 +15,24 @@ module OpenTracing
15
15
  ::Thrift::MessageTypes::ONEWAY => 'ONEWAY',
16
16
  }.freeze
17
17
 
18
+ autoload :TracedProcessor,
19
+ "#{module_path}/traced_processor"
20
+ autoload :TracedProcessorConfig,
21
+ "#{module_path}/traced_processor_config"
22
+ autoload :TracedProcessorOperationNameBuilder,
23
+ "#{module_path}/traced_processor_operation_name_builder"
24
+ autoload :TracedProcessorTagsBuilder,
25
+ "#{module_path}/traced_processor_tags_builder"
18
26
  autoload :TracedProtocol,
19
- module_path + '/traced_protocol'
27
+ "#{module_path}/traced_protocol"
20
28
  autoload :TracedProtocolConfig,
21
- module_path + '/traced_protocol_config'
29
+ "#{module_path}/traced_protocol_config"
22
30
  autoload :TracedProtocolFactory,
23
- module_path + '/traced_protocol_factory'
31
+ "#{module_path}/traced_protocol_factory"
24
32
  autoload :TracedProtocolOperationNameBuilder,
25
- module_path + '/traced_protocol_operation_name_builder'
33
+ "#{module_path}/traced_protocol_operation_name_builder"
26
34
  autoload :TracedProtocolTagsBuilder,
27
- module_path + '/traced_protocol_tags_builder'
35
+ "#{module_path}/traced_protocol_tags_builder"
28
36
  end
29
37
  end
30
38
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenTracing
4
+ module Instrumentation
5
+ module Thrift
6
+ # Trace thrift processor
7
+ #
8
+ # Usage:
9
+ # processor =
10
+ # OrderService::Processor.new(orders_handler)
11
+ # traced_processor =
12
+ # OpenTracing::Instrumentation::Thrift::TracedProcessor.new(processor)
13
+ class TracedProcessor
14
+ extend Forwardable
15
+
16
+ # @private
17
+ class ReadCachedProtocol
18
+ include ::Thrift::ProtocolDecorator
19
+
20
+ def read_message_begin
21
+ @read_message_begin ||= @protocol.read_message_begin
22
+ end
23
+
24
+ def ==(other)
25
+ @protocol == other.protocol
26
+ end
27
+
28
+ protected
29
+
30
+ attr_reader :protocol
31
+ end
32
+
33
+ # @parama processor [Thrift::Processor] traced processor
34
+ # @param config [TracedProcessorConfig]
35
+ # @yieldparam [TracedProcessorConfig]
36
+ def initialize(processor, config: TracedProcessorConfig.new)
37
+ @processor = processor
38
+ yield config if block_given?
39
+ @config = config.dup
40
+ end
41
+
42
+ # @param iproto [Thrift::Protocol] input protocol
43
+ # @param oproto [Thrift::Protocol] output protocol
44
+ def process(iproto, oproto)
45
+ trace_process(iproto) do |cached_iproto|
46
+ processor.process(
47
+ wrap_protocol(cached_iproto),
48
+ wrap_protocol(oproto),
49
+ )
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ attr_reader :processor,
56
+ :config
57
+
58
+ def_delegators :config,
59
+ :tracer,
60
+ :trace_protocol,
61
+ :error_writer,
62
+ :operation_name_builder,
63
+ :tags_builder,
64
+ :logger
65
+
66
+ def trace_process(iproto)
67
+ cached_iproto = ReadCachedProtocol.new(iproto)
68
+
69
+ start_time = Time.now
70
+
71
+ name, type, seq_id = cached_iproto.read_message_begin
72
+
73
+ scope = safe_start_scope(iproto, name, type, seq_id, start_time)
74
+
75
+ yield cached_iproto
76
+ rescue StandardError => e
77
+ error_writer.write_error(scope.span, e) if scope&.span
78
+ raise e
79
+ ensure
80
+ safe_close_scope(scope)
81
+ end
82
+
83
+ def safe_start_scope(protocol, name, type, seq_id, start_time)
84
+ operation_name = operation_name_builder.build(name, type, seq_id)
85
+ tags = tags_builder.build_tags(protocol, name, type)
86
+ tracer.start_active_span(
87
+ operation_name,
88
+ start_time: start_time,
89
+ tags: tags,
90
+ )
91
+ rescue StandardError => e
92
+ logger&.error(e)
93
+ end
94
+
95
+ def safe_close_scope(scope)
96
+ scope&.close
97
+ rescue StandardError => e
98
+ logger&.error(e)
99
+ end
100
+
101
+ def wrap_protocol(protocol)
102
+ return protocol unless trace_protocol
103
+
104
+ TracedProtocol.new(protocol) do |config|
105
+ config.tracer = tracer
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end