opentracing-instrumentation 0.1.15 → 0.2.1

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.BUNDLER_VERSION +1 -1
  3. data/.drone.jsonnet +3 -3
  4. data/.gitlab-ci.yml +12 -11
  5. data/.rubocop.yml +7 -0
  6. data/.ruby-version +1 -1
  7. data/CHANGELOG.md +7 -0
  8. data/GEM_VERSION +1 -1
  9. data/Gemfile +7 -7
  10. data/Gemfile.lock +80 -60
  11. data/bin/check_gemfile_lock +18 -0
  12. data/lib/opentracing/instrumentation/bunny.rb +11 -11
  13. data/lib/opentracing/instrumentation/bunny/regexp_routing_key_sanitazer.rb +1 -1
  14. data/lib/opentracing/instrumentation/common.rb +2 -0
  15. data/lib/opentracing/instrumentation/common/error_writer.rb +2 -2
  16. data/lib/opentracing/instrumentation/common/operation_name_builder.rb +23 -0
  17. data/lib/opentracing/instrumentation/faraday/response_logger.rb +4 -4
  18. data/lib/opentracing/instrumentation/faraday/trace_middleware.rb +1 -1
  19. data/lib/opentracing/instrumentation/hutch.rb +6 -6
  20. data/lib/opentracing/instrumentation/mongo.rb +2 -0
  21. data/lib/opentracing/instrumentation/mongo/query_sanitazer.rb +48 -5
  22. data/lib/opentracing/instrumentation/mongo/sample_safety_argument_checker.rb +30 -0
  23. data/lib/opentracing/instrumentation/mongo/trace_subscriber.rb +5 -5
  24. data/lib/opentracing/instrumentation/rack/http_tagger.rb +3 -3
  25. data/lib/opentracing/instrumentation/rack/trace_middleware.rb +5 -5
  26. data/lib/opentracing/instrumentation/redis/config.rb +5 -5
  27. data/lib/opentracing/instrumentation/redis/tracing_driver_wrapper.rb +4 -4
  28. data/lib/opentracing/instrumentation/sidekiq/client_middleware.rb +41 -18
  29. data/lib/opentracing/instrumentation/sidekiq/job_tagger.rb +7 -7
  30. data/lib/opentracing/instrumentation/sidekiq/server_middleware.rb +41 -15
  31. data/lib/opentracing/instrumentation/thrift.rb +9 -9
  32. data/lib/opentracing/instrumentation/thrift/traced_processor.rb +2 -2
  33. data/lib/opentracing/instrumentation/thrift/traced_processor_config.rb +1 -1
  34. data/lib/opentracing/instrumentation/thrift/traced_processor_tags_builder.rb +1 -0
  35. data/lib/opentracing/instrumentation/thrift/traced_protocol.rb +3 -3
  36. data/lib/opentracing/instrumentation/thrift/traced_protocol_factory.rb +1 -0
  37. data/lib/opentracing/instrumentation/thrift/traced_protocol_tags_builder.rb +1 -1
  38. data/opentracing-instrumentation.gemspec +11 -7
  39. metadata +42 -23
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenTracing
4
+ module Instrumentation
5
+ module Common
6
+ # Build operation name by template and tags
7
+ class OperationNameBuilder
8
+ def initialize(operation_name_template:)
9
+ @operation_name_template = operation_name_template
10
+ end
11
+
12
+ # build operation name with tags
13
+ def build(tags)
14
+ format(operation_name_template, **tags)
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :operation_name_template
20
+ end
21
+ end
22
+ end
23
+ end
@@ -20,10 +20,10 @@ module OpenTracing
20
20
  content_type: 'Content-Type',
21
21
  }.freeze
22
22
 
23
- attr_reader :request_tag_headers
24
- attr_reader :request_log_headers
25
- attr_reader :response_tag_headers
26
- attr_reader :response_log_headers
23
+ attr_reader :request_tag_headers,
24
+ :request_log_headers,
25
+ :response_tag_headers,
26
+ :response_log_headers
27
27
 
28
28
  def initialize(
29
29
  request_log_headers: DEFAULT_REQUEST_LOG_HEADERS,
@@ -193,7 +193,7 @@ module OpenTracing
193
193
  event: 'error',
194
194
  message: error.message,
195
195
  'error.kind': error.class.to_s,
196
- 'stack': error.backtrace,
196
+ stack: error.backtrace,
197
197
  )
198
198
  end
199
199
  end
@@ -12,17 +12,17 @@ module OpenTracing
12
12
  module_path = 'opentracing/instrumentation/hutch'
13
13
 
14
14
  autoload :ConsumeOperationNameBuilder,
15
- module_path + '/consume_operation_name_builder'
15
+ "#{module_path}/consume_operation_name_builder"
16
16
  autoload :ConsumeTagsBuilder,
17
- module_path + '/consume_tags_builder'
17
+ "#{module_path}/consume_tags_builder"
18
18
  autoload :ConsumeTracer,
19
- module_path + '/consume_tracer'
19
+ "#{module_path}/consume_tracer"
20
20
  autoload :ConsumeTracerBuilder,
21
- module_path + '/consume_tracer_builder'
21
+ "#{module_path}/consume_tracer_builder"
22
22
  autoload :ConsumeTracerConfig,
23
- module_path + '/consume_tracer_config'
23
+ "#{module_path}/consume_tracer_config"
24
24
  autoload :GlobalPropertiesBuilder,
25
- module_path + '/global_properties_builder'
25
+ "#{module_path}/global_properties_builder"
26
26
  end
27
27
  end
28
28
  end
@@ -9,6 +9,8 @@ module OpenTracing
9
9
  'opentracing/instrumentation/mongo/operation_name_builder'
10
10
  autoload :TraceSubscriber, 'opentracing/instrumentation/mongo/trace_subscriber'
11
11
  autoload :QuerySanitazer, 'opentracing/instrumentation/mongo/query_sanitazer'
12
+ autoload :SampleSafetyArgumentChecker,
13
+ 'opentracing/instrumentation/mongo/sample_safety_argument_checker'
12
14
  end
13
15
  end
14
16
  end
@@ -19,10 +19,15 @@ module OpenTracing
19
19
  DEFAULT_EXCLUDE_KEYS = %w[lsid].freeze
20
20
 
21
21
  def initialize(
22
+ safety_argument_checker: SampleSafetyArgumentChecker.new,
22
23
  safe_classes: DEFAULT_SAFE_CLASSES,
24
+ max_array_size: 4,
23
25
  exclude_keys: DEFAULT_EXCLUDE_KEYS
24
26
  )
27
+ super()
28
+ @safety_argument_checker = safety_argument_checker
25
29
  @safe_classes = safe_classes
30
+ @max_array_size = max_array_size
26
31
  @exclude_keys = exclude_keys
27
32
  end
28
33
 
@@ -36,8 +41,10 @@ module OpenTracing
36
41
 
37
42
  private
38
43
 
39
- attr_reader :safe_classes
40
- attr_reader :exclude_keys
44
+ attr_reader :safe_classes,
45
+ :exclude_keys,
46
+ :max_array_size,
47
+ :safety_argument_checker
41
48
 
42
49
  OBJECT_ID_PLACEHOLDER = '$oid'
43
50
  STRING_PLACEHOLDER = '$string'
@@ -54,30 +61,66 @@ module OpenTracing
54
61
  end
55
62
  end
56
63
 
64
+ # rubocop:disable Metrics/MethodLength
57
65
  def sanitaze_simple(value)
58
66
  case value
59
67
  when BSON::ObjectId
60
68
  OBJECT_ID_PLACEHOLDER
61
69
  when String
62
70
  STRING_PLACEHOLDER
71
+ when ArrayItemPlaceholder
72
+ value.to_s
63
73
  when *safe_classes
64
74
  value
65
75
  else
66
76
  PLACEHOLDER
67
77
  end
68
78
  end
79
+ # rubocop:enable Metrics/MethodLength
69
80
 
70
81
  def sanitaze_hash(hash)
71
- hash.transform_values do |value|
72
- sanitaze_value(value)
82
+ hash.map do |(key, value)|
83
+ # TODO: pass command name.
84
+ # TODO: recursive build path to key
85
+ safe_value =
86
+ if safety_argument_checker.argument_safe?(nil, key, value)
87
+ value
88
+ else
89
+ sanitaze_value(value)
90
+ end
91
+
92
+ [key, safe_value]
93
+ end.to_h
94
+ end
95
+
96
+ # Placehoder for skipped array items
97
+ class ArrayItemPlaceholder
98
+ def initialize(skipped_items)
99
+ @skipped_items = skipped_items
100
+ end
101
+
102
+ def to_s
103
+ "SKIPPED #{@skipped_items} ITEMS"
73
104
  end
74
105
  end
75
106
 
76
107
  def sanitaze_array(array)
77
- array.map do |value|
108
+ if max_array_size&.positive? && array.size > max_array_size
109
+ array_with_placeholder(array)
110
+ else
111
+ array
112
+ end.map do |value|
78
113
  sanitaze_value(value)
79
114
  end
80
115
  end
116
+
117
+ def array_with_placeholder(array)
118
+ prefix_size = (max_array_size / 2).ceil
119
+ suffix_size = max_array_size - prefix_size
120
+ array[0...prefix_size] \
121
+ + [ArrayItemPlaceholder.new(array.size - max_array_size)] \
122
+ + array[-suffix_size..-1]
123
+ end
81
124
  end
82
125
  end
83
126
  end
@@ -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)
@@ -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