opentracing-instrumentation 0.1.14 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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