atatus 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +57 -0
- data/LICENSE +65 -0
- data/LICENSE-THIRD-PARTY +205 -0
- data/README.md +13 -0
- data/Rakefile +19 -0
- data/atatus.gemspec +36 -0
- data/atatus.yml +2 -0
- data/bench/.gitignore +2 -0
- data/bench/app.rb +53 -0
- data/bench/benchmark.rb +36 -0
- data/bench/report.rb +55 -0
- data/bench/rubyprof.rb +39 -0
- data/bench/stackprof.rb +23 -0
- data/bin/build_docs +5 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bin/with_framework +7 -0
- data/lib/atatus.rb +325 -0
- data/lib/atatus/agent.rb +260 -0
- data/lib/atatus/central_config.rb +141 -0
- data/lib/atatus/central_config/cache_control.rb +34 -0
- data/lib/atatus/collector/base.rb +329 -0
- data/lib/atatus/collector/builder.rb +317 -0
- data/lib/atatus/collector/transport.rb +72 -0
- data/lib/atatus/config.rb +248 -0
- data/lib/atatus/config/bytes.rb +25 -0
- data/lib/atatus/config/duration.rb +23 -0
- data/lib/atatus/config/options.rb +134 -0
- data/lib/atatus/config/regexp_list.rb +13 -0
- data/lib/atatus/context.rb +33 -0
- data/lib/atatus/context/request.rb +11 -0
- data/lib/atatus/context/request/socket.rb +19 -0
- data/lib/atatus/context/request/url.rb +42 -0
- data/lib/atatus/context/response.rb +22 -0
- data/lib/atatus/context/user.rb +42 -0
- data/lib/atatus/context_builder.rb +97 -0
- data/lib/atatus/deprecations.rb +22 -0
- data/lib/atatus/error.rb +22 -0
- data/lib/atatus/error/exception.rb +46 -0
- data/lib/atatus/error/log.rb +24 -0
- data/lib/atatus/error_builder.rb +76 -0
- data/lib/atatus/instrumenter.rb +224 -0
- data/lib/atatus/internal_error.rb +6 -0
- data/lib/atatus/logging.rb +55 -0
- data/lib/atatus/metadata.rb +19 -0
- data/lib/atatus/metadata/process_info.rb +18 -0
- data/lib/atatus/metadata/service_info.rb +61 -0
- data/lib/atatus/metadata/system_info.rb +35 -0
- data/lib/atatus/metadata/system_info/container_info.rb +121 -0
- data/lib/atatus/metadata/system_info/hw_info.rb +118 -0
- data/lib/atatus/metadata/system_info/os_info.rb +31 -0
- data/lib/atatus/metrics.rb +98 -0
- data/lib/atatus/metrics/cpu_mem.rb +240 -0
- data/lib/atatus/metrics/vm.rb +60 -0
- data/lib/atatus/metricset.rb +19 -0
- data/lib/atatus/middleware.rb +76 -0
- data/lib/atatus/naively_hashable.rb +21 -0
- data/lib/atatus/normalizers.rb +68 -0
- data/lib/atatus/normalizers/action_controller.rb +27 -0
- data/lib/atatus/normalizers/action_mailer.rb +26 -0
- data/lib/atatus/normalizers/action_view.rb +77 -0
- data/lib/atatus/normalizers/active_record.rb +45 -0
- data/lib/atatus/opentracing.rb +346 -0
- data/lib/atatus/rails.rb +61 -0
- data/lib/atatus/railtie.rb +30 -0
- data/lib/atatus/span.rb +125 -0
- data/lib/atatus/span/context.rb +40 -0
- data/lib/atatus/span_helpers.rb +44 -0
- data/lib/atatus/spies.rb +86 -0
- data/lib/atatus/spies/action_dispatch.rb +28 -0
- data/lib/atatus/spies/delayed_job.rb +68 -0
- data/lib/atatus/spies/elasticsearch.rb +36 -0
- data/lib/atatus/spies/faraday.rb +70 -0
- data/lib/atatus/spies/http.rb +44 -0
- data/lib/atatus/spies/json.rb +22 -0
- data/lib/atatus/spies/mongo.rb +87 -0
- data/lib/atatus/spies/net_http.rb +70 -0
- data/lib/atatus/spies/rake.rb +45 -0
- data/lib/atatus/spies/redis.rb +27 -0
- data/lib/atatus/spies/sequel.rb +47 -0
- data/lib/atatus/spies/sidekiq.rb +89 -0
- data/lib/atatus/spies/sinatra.rb +41 -0
- data/lib/atatus/spies/tilt.rb +27 -0
- data/lib/atatus/sql_summarizer.rb +35 -0
- data/lib/atatus/stacktrace.rb +16 -0
- data/lib/atatus/stacktrace/frame.rb +52 -0
- data/lib/atatus/stacktrace_builder.rb +104 -0
- data/lib/atatus/subscriber.rb +77 -0
- data/lib/atatus/trace_context.rb +85 -0
- data/lib/atatus/transaction.rb +100 -0
- data/lib/atatus/transport/base.rb +174 -0
- data/lib/atatus/transport/connection.rb +156 -0
- data/lib/atatus/transport/connection/http.rb +116 -0
- data/lib/atatus/transport/connection/proxy_pipe.rb +75 -0
- data/lib/atatus/transport/filters.rb +43 -0
- data/lib/atatus/transport/filters/secrets_filter.rb +74 -0
- data/lib/atatus/transport/serializers.rb +93 -0
- data/lib/atatus/transport/serializers/context_serializer.rb +85 -0
- data/lib/atatus/transport/serializers/error_serializer.rb +77 -0
- data/lib/atatus/transport/serializers/metadata_serializer.rb +70 -0
- data/lib/atatus/transport/serializers/metricset_serializer.rb +28 -0
- data/lib/atatus/transport/serializers/span_serializer.rb +80 -0
- data/lib/atatus/transport/serializers/transaction_serializer.rb +37 -0
- data/lib/atatus/transport/worker.rb +73 -0
- data/lib/atatus/util.rb +42 -0
- data/lib/atatus/util/inflector.rb +93 -0
- data/lib/atatus/util/lru_cache.rb +48 -0
- data/lib/atatus/util/prefixed_logger.rb +18 -0
- data/lib/atatus/util/throttle.rb +35 -0
- data/lib/atatus/version.rb +5 -0
- data/vendor/.gitkeep +0 -0
- metadata +190 -0
@@ -0,0 +1,240 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atatus
|
4
|
+
module Metrics
|
5
|
+
# @api private
|
6
|
+
class CpuMem
|
7
|
+
include Logging
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
class Sample
|
11
|
+
# rubocop:disable Metrics/ParameterLists
|
12
|
+
def initialize(
|
13
|
+
system_cpu_total:,
|
14
|
+
system_cpu_usage:,
|
15
|
+
system_memory_total:,
|
16
|
+
system_memory_free:,
|
17
|
+
process_cpu_usage:,
|
18
|
+
process_memory_size:,
|
19
|
+
process_memory_rss:,
|
20
|
+
page_size:
|
21
|
+
)
|
22
|
+
@system_cpu_total = system_cpu_total
|
23
|
+
@system_cpu_usage = system_cpu_usage
|
24
|
+
@system_memory_total = system_memory_total
|
25
|
+
@system_memory_free = system_memory_free
|
26
|
+
@process_cpu_usage = process_cpu_usage
|
27
|
+
@process_memory_size = process_memory_size
|
28
|
+
@process_memory_rss = process_memory_rss
|
29
|
+
@page_size = page_size
|
30
|
+
end
|
31
|
+
# rubocop:enable Metrics/ParameterLists
|
32
|
+
|
33
|
+
attr_accessor :system_cpu_total, :system_cpu_usage,
|
34
|
+
:system_memory_total, :system_memory_free, :process_cpu_usage,
|
35
|
+
:process_memory_size, :process_memory_rss, :page_size
|
36
|
+
|
37
|
+
def delta(previous)
|
38
|
+
dup.tap do |sample|
|
39
|
+
sample.system_cpu_total =
|
40
|
+
system_cpu_total - previous.system_cpu_total
|
41
|
+
sample.system_cpu_usage =
|
42
|
+
system_cpu_usage - previous.system_cpu_usage
|
43
|
+
sample.process_cpu_usage =
|
44
|
+
process_cpu_usage - previous.process_cpu_usage
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(config)
|
50
|
+
@config = config
|
51
|
+
@sampler = sampler_for_platform(Metrics.platform)
|
52
|
+
end
|
53
|
+
|
54
|
+
attr_reader :config, :sampler
|
55
|
+
|
56
|
+
def sample
|
57
|
+
@sampler.sample
|
58
|
+
end
|
59
|
+
|
60
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
61
|
+
def collect
|
62
|
+
return unless sampler
|
63
|
+
|
64
|
+
current = sample
|
65
|
+
|
66
|
+
unless @previous
|
67
|
+
@previous = current
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
delta = current.delta(@previous)
|
72
|
+
|
73
|
+
cpu_usage_pct = delta.system_cpu_usage.to_f / delta.system_cpu_total
|
74
|
+
cpu_process_pct = delta.process_cpu_usage.to_f / delta.system_cpu_total
|
75
|
+
|
76
|
+
@previous = current
|
77
|
+
|
78
|
+
{
|
79
|
+
'system.cpu.total.norm.pct': cpu_usage_pct,
|
80
|
+
'system.memory.actual.free': current.system_memory_free,
|
81
|
+
'system.memory.total': current.system_memory_total,
|
82
|
+
'system.process.cpu.total.norm.pct': cpu_process_pct,
|
83
|
+
'system.process.memory.size': current.process_memory_size,
|
84
|
+
'system.process.memory.rss.bytes':
|
85
|
+
current.process_memory_rss * current.page_size
|
86
|
+
}
|
87
|
+
end
|
88
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def sampler_for_platform(platform)
|
93
|
+
case platform
|
94
|
+
when :linux then Linux.new
|
95
|
+
else
|
96
|
+
warn "Unsupported platform '#{platform}' - Disabling metrics"
|
97
|
+
@disabled = true
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @api private
|
103
|
+
class Linux
|
104
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
105
|
+
def sample
|
106
|
+
proc_stat = ProcStat.new.read!
|
107
|
+
proc_self_stat = ProcSelfStat.new.read!
|
108
|
+
meminfo = Meminfo.new.read!
|
109
|
+
|
110
|
+
Sample.new(
|
111
|
+
system_cpu_total: proc_stat.total,
|
112
|
+
system_cpu_usage: proc_stat.usage,
|
113
|
+
system_memory_total: meminfo.total,
|
114
|
+
system_memory_free: meminfo.available,
|
115
|
+
process_cpu_usage: proc_self_stat.total,
|
116
|
+
process_memory_size: proc_self_stat.vsize,
|
117
|
+
process_memory_rss: proc_self_stat.rss,
|
118
|
+
page_size: meminfo.page_size
|
119
|
+
)
|
120
|
+
end
|
121
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
122
|
+
|
123
|
+
# @api private
|
124
|
+
class ProcStat
|
125
|
+
attr_reader :total, :usage
|
126
|
+
|
127
|
+
CPU_FIELDS = %i[
|
128
|
+
user
|
129
|
+
nice
|
130
|
+
system
|
131
|
+
idle
|
132
|
+
iowait
|
133
|
+
irq
|
134
|
+
softirq
|
135
|
+
steal
|
136
|
+
guest
|
137
|
+
guest_nice
|
138
|
+
].freeze
|
139
|
+
|
140
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
141
|
+
def read!
|
142
|
+
stat =
|
143
|
+
IO.readlines('/proc/stat')
|
144
|
+
.lazy
|
145
|
+
.find { |sp| sp.start_with?('cpu ') }
|
146
|
+
.split
|
147
|
+
.map(&:to_i)[1..-1]
|
148
|
+
|
149
|
+
values =
|
150
|
+
CPU_FIELDS.each_with_index.each_with_object({}) do |(key, i), v|
|
151
|
+
v[key] = stat[i] || 0
|
152
|
+
end
|
153
|
+
|
154
|
+
@total =
|
155
|
+
values[:user] +
|
156
|
+
values[:nice] +
|
157
|
+
values[:system] +
|
158
|
+
values[:idle] +
|
159
|
+
values[:iowait] +
|
160
|
+
values[:irq] +
|
161
|
+
values[:softirq] +
|
162
|
+
values[:steal]
|
163
|
+
|
164
|
+
@usage = @total - (values[:idle] + values[:iowait])
|
165
|
+
|
166
|
+
self
|
167
|
+
end
|
168
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
169
|
+
end
|
170
|
+
|
171
|
+
UTIME_POS = 13
|
172
|
+
STIME_POS = 14
|
173
|
+
VSIZE_POS = 22
|
174
|
+
RSS_POS = 23
|
175
|
+
|
176
|
+
# @api private
|
177
|
+
class ProcSelfStat
|
178
|
+
attr_reader :total, :vsize, :rss
|
179
|
+
|
180
|
+
def read!
|
181
|
+
stat =
|
182
|
+
IO.readlines('/proc/self/stat')
|
183
|
+
.lazy
|
184
|
+
.first
|
185
|
+
.split
|
186
|
+
.map(&:to_i)
|
187
|
+
|
188
|
+
@total = stat[UTIME_POS] + stat[STIME_POS]
|
189
|
+
@vsize = stat[VSIZE_POS]
|
190
|
+
@rss = stat[RSS_POS]
|
191
|
+
|
192
|
+
self
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# @api private
|
197
|
+
class Meminfo
|
198
|
+
attr_reader :total, :available, :page_size
|
199
|
+
|
200
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
201
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
202
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
203
|
+
def read!
|
204
|
+
# rubocop:disable Style/RescueModifier
|
205
|
+
@page_size = `getconf PAGESIZE`.chomp.to_i rescue 4096
|
206
|
+
# rubocop:enable Style/RescueModifier
|
207
|
+
|
208
|
+
info =
|
209
|
+
IO.readlines('/proc/meminfo')
|
210
|
+
.lazy
|
211
|
+
.each_with_object({}) do |line, hsh|
|
212
|
+
if line.start_with?('MemTotal:')
|
213
|
+
hsh[:total] = line.split[1].to_i * 1024
|
214
|
+
elsif line.start_with?('MemAvailable:')
|
215
|
+
hsh[:available] = line.split[1].to_i * 1024
|
216
|
+
elsif line.start_with?('MemFree:')
|
217
|
+
hsh[:free] = line.split[1].to_i * 1024
|
218
|
+
elsif line.start_with?('Buffers:')
|
219
|
+
hsh[:buffers] = line.split[1].to_i * 1024
|
220
|
+
elsif line.start_with?('Cached:')
|
221
|
+
hsh[:cached] = line.split[1].to_i * 1024
|
222
|
+
end
|
223
|
+
|
224
|
+
break hsh if hsh[:total] && hsh[:available]
|
225
|
+
end
|
226
|
+
|
227
|
+
@total = info[:total]
|
228
|
+
@available =
|
229
|
+
info[:available] || info[:free] + info[:buffers] + info[:cached]
|
230
|
+
|
231
|
+
self
|
232
|
+
end
|
233
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
234
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
235
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atatus
|
4
|
+
module Metrics
|
5
|
+
# @api private
|
6
|
+
class VM
|
7
|
+
include Logging
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
@total_time = 0
|
12
|
+
@disabled = false
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :config
|
16
|
+
attr_writer :disabled
|
17
|
+
|
18
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
19
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
20
|
+
def collect
|
21
|
+
return if disabled?
|
22
|
+
|
23
|
+
stat = GC.stat
|
24
|
+
thread_count = Thread.list.count
|
25
|
+
|
26
|
+
sample = {
|
27
|
+
'ruby.gc.count': stat[:count],
|
28
|
+
'ruby.threads': thread_count
|
29
|
+
}
|
30
|
+
|
31
|
+
(live_slots = stat[:heap_live_slots]) &&
|
32
|
+
sample[:'ruby.heap.slots.live'] = live_slots
|
33
|
+
(heap_slots = stat[:heap_free_slots]) &&
|
34
|
+
sample[:'ruby.heap.slots.free'] = heap_slots
|
35
|
+
(allocated = stat[:total_allocated_objects]) &&
|
36
|
+
sample[:'ruby.heap.allocations.total'] = allocated
|
37
|
+
|
38
|
+
return sample unless GC::Profiler.enabled?
|
39
|
+
|
40
|
+
@total_time += GC::Profiler.total_time
|
41
|
+
GC::Profiler.clear
|
42
|
+
sample[:'ruby.gc.time'] = @total_time
|
43
|
+
|
44
|
+
sample
|
45
|
+
rescue TypeError => e
|
46
|
+
error 'VM metrics encountered error: %s', e
|
47
|
+
debug('Backtrace:') { e.backtrace.join("\n") }
|
48
|
+
|
49
|
+
@disabled = true
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
53
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
54
|
+
|
55
|
+
def disabled?
|
56
|
+
@disabled
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atatus
|
4
|
+
# @api private
|
5
|
+
class Metricset
|
6
|
+
def initialize(timestamp: Util.micros, labels: nil, **samples)
|
7
|
+
@timestamp = timestamp
|
8
|
+
@labels = labels
|
9
|
+
@samples = samples
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :timestamp
|
13
|
+
attr_reader :samples, :labels
|
14
|
+
|
15
|
+
def empty?
|
16
|
+
samples.empty?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Atatus
|
5
|
+
# @api private
|
6
|
+
class Middleware
|
7
|
+
include Logging
|
8
|
+
|
9
|
+
def initialize(app)
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
14
|
+
def call(env)
|
15
|
+
begin
|
16
|
+
if running? && !path_ignored?(env)
|
17
|
+
transaction = start_transaction(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
resp = @app.call env
|
21
|
+
rescue InternalError
|
22
|
+
raise # Don't report Atatus errors
|
23
|
+
rescue ::Exception => e
|
24
|
+
context = Atatus.build_context(rack_env: env, for_type: :error)
|
25
|
+
Atatus.report(e, context: context, handled: false)
|
26
|
+
raise
|
27
|
+
ensure
|
28
|
+
if resp && transaction
|
29
|
+
status, headers, _body = resp
|
30
|
+
transaction.add_response(status, headers: headers.dup)
|
31
|
+
end
|
32
|
+
|
33
|
+
Atatus.end_transaction http_result(status)
|
34
|
+
end
|
35
|
+
|
36
|
+
resp
|
37
|
+
end
|
38
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def http_result(status)
|
43
|
+
status && "HTTP #{status.to_s[0]}xx"
|
44
|
+
end
|
45
|
+
|
46
|
+
def path_ignored?(env)
|
47
|
+
config.ignore_url_patterns.any? do |r|
|
48
|
+
env['PATH_INFO'].match r
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def start_transaction(env)
|
53
|
+
context = Atatus.build_context(rack_env: env, for_type: :transaction)
|
54
|
+
|
55
|
+
Atatus.start_transaction 'Rack', 'request',
|
56
|
+
context: context,
|
57
|
+
trace_context: trace_context(env)
|
58
|
+
end
|
59
|
+
|
60
|
+
def trace_context(env)
|
61
|
+
return unless (header = env['HTTP_ATATUS_APM_TRACEPARENT'])
|
62
|
+
TraceContext.parse(header)
|
63
|
+
rescue TraceContext::InvalidTraceparentHeader
|
64
|
+
warn "Couldn't parse invalid traceparent header: #{header.inspect}"
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def running?
|
69
|
+
Atatus.running?
|
70
|
+
end
|
71
|
+
|
72
|
+
def config
|
73
|
+
@config ||= Atatus.agent.config
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atatus
|
4
|
+
# @api private
|
5
|
+
module NaivelyHashable
|
6
|
+
def naively_hashable?
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_h
|
11
|
+
instance_variables.each_with_object({}) do |name, h|
|
12
|
+
key = name.to_s.delete('@').to_sym
|
13
|
+
value = instance_variable_get(name)
|
14
|
+
is_hashable =
|
15
|
+
value.respond_to?(:naively_hashable?) && value.naively_hashable?
|
16
|
+
|
17
|
+
h[key] = is_hashable ? value.to_h : value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Atatus # :nodoc:
|
4
|
+
# @api private
|
5
|
+
module Normalizers
|
6
|
+
# @api privagte
|
7
|
+
class Normalizer
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.register(name)
|
13
|
+
Normalizers.register(name, self)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.register(name, klass)
|
18
|
+
@registered ||= {}
|
19
|
+
@registered[name] = klass
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.build(config)
|
23
|
+
normalizers = @registered.each_with_object({}) do |(name, klass), built|
|
24
|
+
built[name] = klass.new(config)
|
25
|
+
end
|
26
|
+
|
27
|
+
Collection.new(normalizers)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @api private
|
31
|
+
class Collection
|
32
|
+
# @api private
|
33
|
+
class SkipNormalizer
|
34
|
+
def initialize; end
|
35
|
+
|
36
|
+
def normalize(*_args)
|
37
|
+
:skip
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(normalizers)
|
42
|
+
@normalizers = normalizers
|
43
|
+
@default = SkipNormalizer.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def for(name)
|
47
|
+
@normalizers.fetch(name) { @default }
|
48
|
+
end
|
49
|
+
|
50
|
+
def keys
|
51
|
+
@normalizers.keys
|
52
|
+
end
|
53
|
+
|
54
|
+
def normalize(transaction, name, payload)
|
55
|
+
self.for(name).normalize(transaction, name, payload)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
%w[
|
61
|
+
action_controller
|
62
|
+
action_mailer
|
63
|
+
action_view
|
64
|
+
active_record
|
65
|
+
].each do |lib|
|
66
|
+
require "atatus/normalizers/#{lib}"
|
67
|
+
end
|
68
|
+
end
|