opentracing-instrumentation 0.1.15 → 0.2.1

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