atatus 1.7.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile +49 -13
  4. data/LICENSE +1 -1
  5. data/atatus.gemspec +3 -3
  6. data/lib/atatus/agent.rb +10 -7
  7. data/lib/atatus/central_config.rb +19 -8
  8. data/lib/atatus/collector/layer.rb +1 -1
  9. data/lib/atatus/{sql_summarizer.rb → config/log_level_map.rb} +22 -28
  10. data/lib/atatus/config/options.rb +2 -1
  11. data/lib/atatus/config/regexp_list.rb +1 -1
  12. data/lib/atatus/config/round_float.rb +31 -0
  13. data/lib/atatus/config/server_info.rb +50 -0
  14. data/lib/atatus/config/wildcard_pattern_list.rb +3 -1
  15. data/lib/atatus/config.rb +92 -71
  16. data/lib/atatus/context/request/socket.rb +1 -2
  17. data/lib/atatus/context/response.rb +1 -3
  18. data/lib/atatus/context.rb +3 -10
  19. data/lib/atatus/context_builder.rb +3 -3
  20. data/lib/atatus/error.rb +2 -1
  21. data/lib/atatus/error_builder.rb +1 -1
  22. data/lib/atatus/fields.rb +98 -0
  23. data/lib/atatus/graphql.rb +2 -0
  24. data/lib/atatus/grpc.rb +5 -7
  25. data/lib/atatus/instrumenter.rb +29 -25
  26. data/lib/atatus/metadata/cloud_info.rb +156 -0
  27. data/lib/atatus/metadata/service_info.rb +3 -3
  28. data/lib/atatus/metadata/system_info/container_info.rb +20 -8
  29. data/lib/atatus/metadata/system_info.rb +20 -5
  30. data/lib/atatus/metadata.rb +3 -1
  31. data/lib/atatus/metrics/cpu_mem_set.rb +10 -38
  32. data/lib/atatus/metrics/jvm_set.rb +88 -0
  33. data/lib/atatus/metrics/metric.rb +2 -0
  34. data/lib/atatus/metrics.rb +33 -16
  35. data/lib/atatus/middleware.rb +8 -3
  36. data/lib/atatus/naively_hashable.rb +1 -0
  37. data/lib/atatus/normalizers/rails/active_record.rb +25 -7
  38. data/lib/atatus/normalizers.rb +2 -2
  39. data/lib/atatus/opentracing.rb +5 -3
  40. data/lib/atatus/rails.rb +1 -1
  41. data/lib/atatus/span/context/db.rb +1 -1
  42. data/lib/atatus/span/context/destination.rb +58 -32
  43. data/lib/atatus/span/context/http.rb +2 -0
  44. data/lib/atatus/span/context/links.rb +32 -0
  45. data/lib/atatus/{sql.rb → span/context/message.rb} +16 -12
  46. data/lib/atatus/span/context/service.rb +55 -0
  47. data/lib/atatus/span/context.rb +28 -3
  48. data/lib/atatus/span.rb +35 -5
  49. data/lib/atatus/span_helpers.rb +12 -23
  50. data/lib/atatus/spies/action_dispatch.rb +10 -13
  51. data/lib/atatus/spies/azure_storage_table.rb +148 -0
  52. data/lib/atatus/spies/delayed_job.rb +19 -13
  53. data/lib/atatus/spies/dynamo_db.rb +56 -15
  54. data/lib/atatus/spies/elasticsearch.rb +54 -39
  55. data/lib/atatus/spies/faraday.rb +92 -58
  56. data/lib/atatus/spies/http.rb +33 -37
  57. data/lib/atatus/spies/json.rb +5 -9
  58. data/lib/atatus/spies/mongo.rb +26 -19
  59. data/lib/atatus/spies/net_http.rb +53 -51
  60. data/lib/atatus/spies/racecar.rb +77 -0
  61. data/lib/atatus/spies/rake.rb +27 -27
  62. data/lib/atatus/spies/redis.rb +11 -12
  63. data/lib/atatus/spies/resque.rb +18 -23
  64. data/lib/atatus/spies/s3.rb +132 -0
  65. data/lib/atatus/spies/sequel.rb +11 -2
  66. data/lib/atatus/spies/shoryuken.rb +4 -6
  67. data/lib/atatus/spies/sidekiq.rb +23 -31
  68. data/lib/atatus/spies/sinatra.rb +20 -28
  69. data/lib/atatus/spies/sneakers.rb +2 -0
  70. data/lib/atatus/spies/sns.rb +126 -0
  71. data/lib/atatus/spies/sqs.rb +231 -0
  72. data/lib/atatus/spies/sucker_punch.rb +20 -22
  73. data/lib/atatus/spies/tilt.rb +10 -13
  74. data/lib/atatus/spies.rb +20 -0
  75. data/lib/atatus/sql/signature.rb +4 -2
  76. data/lib/atatus/sql/tokenizer.rb +23 -7
  77. data/lib/atatus/stacktrace/frame.rb +1 -0
  78. data/lib/atatus/stacktrace_builder.rb +12 -16
  79. data/lib/atatus/subscriber.rb +1 -0
  80. data/lib/atatus/trace_context/traceparent.rb +5 -8
  81. data/lib/atatus/trace_context/tracestate.rb +16 -14
  82. data/lib/atatus/trace_context.rb +6 -16
  83. data/lib/atatus/transaction.rb +17 -4
  84. data/lib/atatus/transport/base.rb +1 -3
  85. data/lib/atatus/transport/connection/http.rb +11 -3
  86. data/lib/atatus/transport/connection/proxy_pipe.rb +1 -2
  87. data/lib/atatus/transport/connection.rb +3 -2
  88. data/lib/atatus/transport/filters/hash_sanitizer.rb +16 -34
  89. data/lib/atatus/transport/filters/secrets_filter.rb +35 -12
  90. data/lib/atatus/transport/serializers/context_serializer.rb +1 -2
  91. data/lib/atatus/transport/serializers/metadata_serializer.rb +54 -8
  92. data/lib/atatus/transport/serializers/metricset_serializer.rb +2 -2
  93. data/lib/atatus/transport/serializers/span_serializer.rb +55 -9
  94. data/lib/atatus/transport/serializers/transaction_serializer.rb +1 -0
  95. data/lib/atatus/transport/serializers.rb +9 -6
  96. data/lib/atatus/transport/user_agent.rb +16 -9
  97. data/lib/atatus/transport/worker.rb +2 -1
  98. data/lib/atatus/util/deep_dup.rb +65 -0
  99. data/lib/atatus/util/precision_validator.rb +46 -0
  100. data/lib/atatus/util.rb +2 -0
  101. data/lib/atatus/version.rb +1 -1
  102. data/lib/atatus.rb +32 -5
  103. metadata +40 -11
@@ -123,13 +123,15 @@ module Atatus
123
123
  end
124
124
 
125
125
  attr_accessor :trace_context
126
+
126
127
  def_delegators :trace_context, :trace_id, :id, :parent_id
127
128
 
128
129
  def self.from_header(header)
129
130
  return unless header
130
131
 
131
- trace_context = Atatus::TraceContext.parse(header)
132
- return unless trace_context
132
+ trace_context = TraceContext.new(
133
+ traceparent: TraceContext::Traceparent.parse(header)
134
+ )
133
135
 
134
136
  trace_context.traceparent.id = trace_context.parent_id
135
137
  trace_context.traceparent.parent_id = nil
@@ -345,7 +347,7 @@ module Atatus
345
347
  context = context_from_child_of(child_of) ||
346
348
  context_from_references(references) ||
347
349
  context_from_active_scope(ignore_active_scope)
348
- return context.child if context&.respond_to?(:child)
350
+ return context.child if context.respond_to?(:child)
349
351
 
350
352
  context
351
353
  end
data/lib/atatus/rails.rb CHANGED
@@ -51,7 +51,7 @@ module Atatus
51
51
  rescue StandardError => e
52
52
  if config.disable_start_message?
53
53
  config.logger.error format('Failed to start: %s', e.message)
54
- config.logger.error "Backtrace:\n" + e.backtrace.join("\n")
54
+ config.logger.debug "Backtrace:\n" + e.backtrace.join("\n")
55
55
  else
56
56
  puts format('Failed to start: %s', e.message)
57
57
  puts "Backtrace:\n" + e.backtrace.join("\n")
@@ -30,7 +30,7 @@ module Atatus
30
30
  rows_affected: nil
31
31
  )
32
32
  @instance = instance
33
- @statement = statement
33
+ @statement = statement&.encode('utf-8', invalid: :replace, undef: :replace)
34
34
  @type = type
35
35
  @user = user
36
36
  @rows_affected = rows_affected
@@ -14,7 +14,7 @@
14
14
  # KIND, either express or implied. See the License for the
15
15
  # specific language governing permissions and limitations
16
16
  # under the License.
17
-
17
+ #
18
18
  # frozen_string_literal: true
19
19
 
20
20
  module Atatus
@@ -22,47 +22,53 @@ module Atatus
22
22
  class Context
23
23
  # @api private
24
24
  class Destination
25
- def initialize(
26
- name: nil,
27
- resource: nil,
28
- type: nil,
29
- address: nil,
30
- port: nil
31
- )
32
- @name = name
33
- @resource = resource
34
- @type = type
35
- @address = address
36
- @port = port
25
+ include Fields
26
+
27
+ field :address
28
+ field :port
29
+ field :service
30
+ field :cloud
31
+
32
+ # @api private
33
+ class Service
34
+ include Fields
35
+
36
+ field :name, default: ''
37
+ field :type, default: ''
38
+ field :resource
39
+ end
40
+
41
+ # @api private
42
+ class Cloud
43
+ include Fields
44
+
45
+ field :region
37
46
  end
38
47
 
39
- attr_reader(
40
- :name,
41
- :resource,
42
- :type,
43
- :address,
44
- :port
45
- )
48
+ def initialize(service: nil, cloud: nil, **attrs)
49
+ super(**attrs)
50
+
51
+ self.service = build_service(service)
52
+ self.cloud = build_cloud(cloud)
53
+ end
46
54
 
47
- def self.from_uri(uri_or_str, type: 'external', port: nil)
55
+ def self.from_uri(uri_or_str, type: nil, **attrs)
48
56
  uri = normalize(uri_or_str)
49
57
 
58
+ service =
59
+ case type
60
+ when 'http' then http_service(uri)
61
+ else nil
62
+ end
63
+
50
64
  new(
51
- name: only_scheme_and_host(uri),
52
- resource: "#{uri.host}:#{uri.port}",
53
- type: type,
54
65
  address: uri.hostname,
55
- port: port || uri.port
66
+ port: uri.port,
67
+ service: service,
68
+ **attrs
56
69
  )
57
70
  end
58
71
 
59
- def self.only_scheme_and_host(uri_or_str)
60
- uri = normalize(uri_or_str)
61
- uri.path = ''
62
- uri.password = uri.query = uri.fragment = nil
63
- uri.to_s
64
- end
65
-
66
72
  class << self
67
73
  private
68
74
 
@@ -70,6 +76,26 @@ module Atatus
70
76
  return uri_or_str.dup if uri_or_str.is_a?(URI)
71
77
  URI(uri_or_str)
72
78
  end
79
+
80
+ def http_service(uri)
81
+ Service.new(resource: "#{uri.host}:#{uri.port}")
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def build_cloud(cloud = nil)
88
+ return Cloud.new unless cloud
89
+ return cloud if cloud.is_a?(Cloud)
90
+
91
+ Cloud.new(**cloud)
92
+ end
93
+
94
+ def build_service(service = nil)
95
+ return Service.new unless service
96
+ return service if service.is_a?(Service)
97
+
98
+ Service.new(**service)
73
99
  end
74
100
  end
75
101
  end
@@ -33,6 +33,8 @@ module Atatus
33
33
  private
34
34
 
35
35
  def sanitize_url(uri_or_str)
36
+ return unless uri_or_str
37
+
36
38
  uri = uri_or_str.is_a?(URI) ? uri_or_str.dup : URI(uri_or_str)
37
39
  uri.password = nil
38
40
  uri.to_s
@@ -0,0 +1,32 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Atatus
21
+ class Span
22
+ class Context
23
+ # @api private
24
+ class Links < Array
25
+ # @api private
26
+ class Link < Struct.new(:trace_id, :span_id)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
@@ -18,19 +18,23 @@
18
18
  # frozen_string_literal: true
19
19
 
20
20
  module Atatus
21
- # @api private
22
- module Sql
23
- # This method is only here as a shortcut while the agent ships with
24
- # both implementations ~mikker
25
- def self.summarizer
26
- @summarizer ||=
27
- if Atatus.agent&.config&.use_legacy_sql_parser
28
- require 'atatus/sql_summarizer'
29
- SqlSummarizer.new
30
- else
31
- require 'atatus/sql/signature'
32
- Sql::Signature::Summarizer.new
21
+ class Span
22
+ class Context
23
+ # @api private
24
+ class Message
25
+ def initialize(
26
+ queue_name: nil,
27
+ age_ms: nil
28
+ )
29
+ @queue_name = queue_name
30
+ @age_ms = age_ms
33
31
  end
32
+
33
+ attr_reader(
34
+ :queue_name,
35
+ :age_ms
36
+ )
37
+ end
34
38
  end
35
39
  end
36
40
  end
@@ -0,0 +1,55 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Atatus
21
+ class Span
22
+ class Context
23
+ # @api private
24
+ class Service
25
+ include Fields
26
+
27
+ field :target
28
+
29
+ # @api private
30
+ class Target
31
+ include Fields
32
+
33
+ field :name, default: ''
34
+ field :type, default: ''
35
+ end
36
+
37
+ def initialize(target: nil, **attrs)
38
+ super(**attrs)
39
+
40
+ self.target = build_target(target)
41
+ end
42
+
43
+ private
44
+
45
+ def build_target(target = nil)
46
+ return Target.new unless target
47
+ return target if target.is_a?(Target)
48
+
49
+ Target.new(**target)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -26,7 +26,10 @@ module Atatus
26
26
  destination: nil,
27
27
  http: nil,
28
28
  labels: {},
29
- sync: nil
29
+ sync: nil,
30
+ message: nil,
31
+ service: nil,
32
+ links: nil
30
33
  )
31
34
  @sync = sync
32
35
  @db = db && Db.new(**db)
@@ -36,16 +39,34 @@ module Atatus
36
39
  when Destination then destination
37
40
  when Hash then Destination.new(**destination)
38
41
  end
42
+ @message =
43
+ case message
44
+ when Message then message
45
+ when Hash then Message.new(**message)
46
+ end
39
47
  @labels = labels
48
+ @service =
49
+ case service
50
+ when Service then service
51
+ when Hash then Service.new(**service)
52
+ end
53
+ @links =
54
+ case links
55
+ when Links then links
56
+ when Array then Links.new(links)
57
+ end
40
58
  end
41
59
 
42
60
  attr_reader(
43
61
  :db,
44
- :destination,
45
62
  :http,
46
63
  :labels,
47
- :sync
64
+ :sync,
65
+ :message,
66
+ :links
48
67
  )
68
+
69
+ attr_accessor :destination, :service
49
70
  end
50
71
  end
51
72
  end
@@ -53,3 +74,7 @@ end
53
74
  require 'atatus/span/context/db'
54
75
  require 'atatus/span/context/http'
55
76
  require 'atatus/span/context/destination'
77
+ require 'atatus/span/context/message'
78
+ require 'atatus/span/context/service'
79
+ require 'atatus/span/context/links'
80
+
data/lib/atatus/span.rb CHANGED
@@ -25,8 +25,18 @@ module Atatus
25
25
  extend Forwardable
26
26
  include ChildDurations::Methods
27
27
 
28
- DEFAULT_TYPE = 'Custom'
29
- DEFAULT_SUBTYPE = 'Ruby'
28
+ # @api private
29
+ class Outcome
30
+ FAILURE = "failure"
31
+ SUCCESS = "success"
32
+ UNKNOWN = "unknown"
33
+
34
+ def self.from_http_status(code)
35
+ code.to_i >= 400 ? FAILURE : SUCCESS
36
+ end
37
+ end
38
+
39
+ DEFAULT_TYPE = 'custom'
30
40
 
31
41
  # rubocop:disable Metrics/ParameterLists
32
42
  def initialize(
@@ -40,7 +50,7 @@ module Atatus
40
50
  context: nil,
41
51
  stacktrace_builder: nil,
42
52
  sync: nil,
43
- sample_rate: nil
53
+ exit_span: false
44
54
  )
45
55
  @name = name
46
56
 
@@ -48,7 +58,7 @@ module Atatus
48
58
  @type, @subtype, @action = type.split('.')
49
59
  else
50
60
  @type = type || DEFAULT_TYPE
51
- @subtype = subtype || DEFAULT_SUBTYPE
61
+ @subtype = subtype
52
62
  @action = action
53
63
  end
54
64
 
@@ -60,6 +70,8 @@ module Atatus
60
70
 
61
71
  @context = context || Span::Context.new(sync: sync)
62
72
  @stacktrace_builder = stacktrace_builder
73
+
74
+ @exit_span = exit_span
63
75
  end
64
76
  # rubocop:enable Metrics/ParameterLists
65
77
 
@@ -67,8 +79,10 @@ module Atatus
67
79
 
68
80
  attr_accessor(
69
81
  :action,
82
+ :exit_span,
70
83
  :name,
71
84
  :original_backtrace,
85
+ :outcome,
72
86
  :subtype,
73
87
  :trace_context,
74
88
  :type
@@ -85,6 +99,8 @@ module Atatus
85
99
  :transaction_id
86
100
  )
87
101
 
102
+ alias :exit_span? :exit_span
103
+
88
104
  # life cycle
89
105
 
90
106
  def start(clock_start = Util.monotonic_micros)
@@ -98,6 +114,7 @@ module Atatus
98
114
  @duration ||= (clock_end - @clock_start)
99
115
  @parent.child_stopped
100
116
  @self_time = @duration - child_durations.duration
117
+
101
118
  self
102
119
  end
103
120
 
@@ -123,12 +140,25 @@ module Atatus
123
140
  started? && !stopped?
124
141
  end
125
142
 
126
- # relations
143
+ def set_destination(address: nil, port: nil, service: nil, cloud: nil)
144
+ context.destination = Span::Context::Destination.new(
145
+ address: address,
146
+ port: port,
147
+ service: service,
148
+ cloud: cloud
149
+ )
150
+ context.service = Span::Context::Service.new(
151
+ target: Span::Context::Service::Target.new(name: context.destination.service.name, type: context.destination.service.type )
152
+ )
153
+ end
127
154
 
128
155
  def inspect
129
156
  "<Atatus::Span id:#{trace_context&.id}" \
130
157
  " name:#{name.inspect}" \
131
158
  " type:#{type.inspect}" \
159
+ " subtype:#{subtype.inspect}" \
160
+ " action:#{action.inspect}" \
161
+ " exit_span:#{exit_span.inspect}" \
132
162
  '>'
133
163
  end
134
164
 
@@ -22,42 +22,31 @@ module Atatus
22
22
  module SpanHelpers
23
23
  # @api private
24
24
  module ClassMethods
25
- def span_class_method(method, name = nil, type = nil, subtype = nil)
26
- __span_method_on(singleton_class, method, name, type, subtype)
25
+ def span_class_method(method, name = nil, type = nil, **kwargs)
26
+ __span_method_on(singleton_class, method, name, type, **kwargs)
27
27
  end
28
28
 
29
- def span_method(method, name = nil, type = nil, subtype = nil)
30
- __span_method_on(self, method, name, type, subtype)
31
- end
32
-
33
- def instrument_class_method(method, name = nil, type = nil, subtype = nil)
34
- __span_method_on(singleton_class, method, name, type, subtype)
35
- end
36
-
37
- def instrument_method(method, name = nil, type = nil, subtype = nil)
38
- __span_method_on(self, method, name, type, subtype)
29
+ def span_method(method, name = nil, type = nil, **kwargs)
30
+ __span_method_on(self, method, name, type, **kwargs)
39
31
  end
40
32
 
41
33
  private
42
34
 
43
- def __span_method_on(klass, method, name = nil, type = nil, subtype = nil)
35
+ def __span_method_on(klass, method, name = nil, type = nil, **kwargs)
44
36
  name ||= method.to_s
45
37
  type ||= Span::DEFAULT_TYPE
46
- subtype ||= Span::DEFAULT_SUBTYPE
47
-
48
- klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
49
- alias :"__without_apm_#{method}" :"#{method}"
50
38
 
51
- def #{method}(*args, &block)
39
+ klass.prepend(Module.new do
40
+ ruby2_keywords(define_method(method) do |*args, &block|
52
41
  unless Atatus.current_transaction
53
- return __without_apm_#{method}(*args, &block)
42
+ return super(*args, &block)
54
43
  end
55
44
 
56
- Atatus.with_span "#{name}", "#{type}", subtype: "#{subtype}" do
57
- __without_apm_#{method}(*args, &block)
45
+ Atatus.with_span name.to_s, type.to_s, **kwargs do
46
+ super(*args, &block)
58
47
  end
59
- end
60
- RUBY
48
+ end)
49
+ end)
61
50
  end
62
51
  end
63
52
 
@@ -22,22 +22,19 @@ module Atatus
22
22
  module Spies
23
23
  # @api private
24
24
  class ActionDispatchSpy
25
- def install
26
- if defined?(::ActionDispatch) && defined?(::ActionDispatch::ShowExceptions)
27
-
28
- ::ActionDispatch::ShowExceptions.class_eval do
29
- alias render_exception_without_apm render_exception
30
-
31
- def render_exception(env, exception)
32
- context = Atatus.build_context(rack_env: env, for_type: :error)
33
- Atatus.report(exception, context: context, handled: false)
34
-
35
- render_exception_without_apm env, exception
36
- end
37
- end
25
+ # @api private
26
+ module Ext
27
+ def render_exception(env, exception)
28
+ context = Atatus.build_context(rack_env: env, for_type: :error)
29
+ Atatus.report(exception, context: context, handled: false)
38
30
 
31
+ super(env, exception)
39
32
  end
40
33
  end
34
+
35
+ def install
36
+ ::ActionDispatch::ShowExceptions.prepend(Ext)
37
+ end
41
38
  end
42
39
 
43
40
  register(