atatus 1.7.0 → 2.0.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -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 +91 -70
  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(