d13n 0.5.2
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.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.rspec +6 -0
- data/.rubocop.yml +5 -0
- data/.ruby-version +1 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +151 -0
- data/Guardfile +63 -0
- data/README.md +200 -0
- data/bin/d13n +11 -0
- data/d13n.gemspec +34 -0
- data/lib/d13n/application/class_methods.rb +56 -0
- data/lib/d13n/application.rb +3 -0
- data/lib/d13n/cli/command.rb +76 -0
- data/lib/d13n/cli/commands/scaffold.rb +345 -0
- data/lib/d13n/configuration/default_source.rb +200 -0
- data/lib/d13n/configuration/dotted_hash.rb +39 -0
- data/lib/d13n/configuration/environment_source.rb +89 -0
- data/lib/d13n/configuration/manager.rb +239 -0
- data/lib/d13n/configuration/manual_source.rb +4 -0
- data/lib/d13n/configuration/mask_defaults.rb +6 -0
- data/lib/d13n/configuration/server_source.rb +83 -0
- data/lib/d13n/configuration/yaml_source.rb +66 -0
- data/lib/d13n/configuration.rb +6 -0
- data/lib/d13n/ext/string.rb +17 -0
- data/lib/d13n/logger/log_once.rb +24 -0
- data/lib/d13n/logger/memory_logger.rb +48 -0
- data/lib/d13n/logger/null_logger.rb +16 -0
- data/lib/d13n/logger.rb +213 -0
- data/lib/d13n/metric/conductor.rb +123 -0
- data/lib/d13n/metric/helper.rb +62 -0
- data/lib/d13n/metric/http_clients/http_helper.rb +15 -0
- data/lib/d13n/metric/http_clients/net_http_wrappers.rb +54 -0
- data/lib/d13n/metric/http_clients.rb +4 -0
- data/lib/d13n/metric/instrumentation/app_exception.rb +70 -0
- data/lib/d13n/metric/instrumentation/controller_instrumentation.rb +91 -0
- data/lib/d13n/metric/instrumentation/em-websocket.rb +71 -0
- data/lib/d13n/metric/instrumentation/exception.rb +65 -0
- data/lib/d13n/metric/instrumentation/middleware_tracing.rb +82 -0
- data/lib/d13n/metric/instrumentation/net.rb +36 -0
- data/lib/d13n/metric/instrumentation/sinatra/stream_namer.rb +35 -0
- data/lib/d13n/metric/instrumentation/sinatra.rb +165 -0
- data/lib/d13n/metric/instrumentation/websocket_instrumentation.rb +42 -0
- data/lib/d13n/metric/instrumentation.rb +41 -0
- data/lib/d13n/metric/manager.rb +106 -0
- data/lib/d13n/metric/metrics/app_database_metric.rb +4 -0
- data/lib/d13n/metric/metrics/app_http_metric.rb +229 -0
- data/lib/d13n/metric/metrics/app_state_metric.rb +103 -0
- data/lib/d13n/metric/metrics/base.rb +14 -0
- data/lib/d13n/metric/metrics/biz_state_metric.rb +4 -0
- data/lib/d13n/metric/metrics.rb +6 -0
- data/lib/d13n/metric/stream/span_tracer_helpers.rb +72 -0
- data/lib/d13n/metric/stream/stream_tracer_helpers.rb +141 -0
- data/lib/d13n/metric/stream/traced_span_stack.rb +73 -0
- data/lib/d13n/metric/stream.rb +322 -0
- data/lib/d13n/metric/stream_state.rb +68 -0
- data/lib/d13n/metric.rb +11 -0
- data/lib/d13n/rack/d13n_middleware.rb +21 -0
- data/lib/d13n/rack/metric_middleware.rb +18 -0
- data/lib/d13n/service/background_job/sinatra.rb +24 -0
- data/lib/d13n/service/background_job.rb +1 -0
- data/lib/d13n/service/start.rb +75 -0
- data/lib/d13n/service.rb +91 -0
- data/lib/d13n/support/request_id.rb +29 -0
- data/lib/d13n/version.rb +14 -0
- data/lib/d13n.rb +92 -0
- data/templates/.rspec.template +6 -0
- data/templates/.ruby-version.template +1 -0
- data/templates/Gemfile.template +16 -0
- data/templates/Guardfile.template +64 -0
- data/templates/Jenkinsfile.template +85 -0
- data/templates/Makefile.template +178 -0
- data/templates/README.md.template +1 -0
- data/templates/Rakefile.template +6 -0
- data/templates/application.yml.template +14 -0
- data/templates/config.ru.template +4 -0
- data/templates/docker/.dockerignore.template +5 -0
- data/templates/docker/Dockerfile.application.development +15 -0
- data/templates/docker/Dockerfile.cache.development +18 -0
- data/templates/docker/Dockerfile.development +27 -0
- data/templates/docker/Dockerfile.release +16 -0
- data/templates/docker/docker-compose.yml.development +53 -0
- data/templates/docker/docker-compose.yml.release +37 -0
- data/templates/lib/api/service.rb.template +10 -0
- data/templates/lib/api/support.rb.template +38 -0
- data/templates/lib/api/version.rb.template +3 -0
- data/templates/lib/api.rb.template +4 -0
- data/templates/lib/application.rb.template +49 -0
- data/templates/lib/service.rb.template +4 -0
- data/templates/lib/version.rb.template +3 -0
- data/templates/scripts/test.sh.template +7 -0
- data/templates/spec/spec_helper.rb.template +56 -0
- data/templates/tasks/migration.rake.template +11 -0
- data/templates/tasks/spec.rake.template +21 -0
- metadata +199 -0
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'd13n/ext/string'
|
2
|
+
module D13n::Metric
|
3
|
+
class HTTPMetricError < MetricError; end
|
4
|
+
class ServiceNotFound < HTTPMetricError; end
|
5
|
+
class EndpointNotFound < HTTPMetricError; end
|
6
|
+
class AppHttpMetric < Base
|
7
|
+
|
8
|
+
module Namespace
|
9
|
+
def get_service_endpoint(request)
|
10
|
+
service = Helper.service_for(request.uri)
|
11
|
+
endpoint = Helper.endpoint_for(request.uri)
|
12
|
+
raise ServiceNotFound.new "No matched service for #{request.uri.to_s}" if service.nil?
|
13
|
+
raise EndpointNotFound.new "No matched endpoint for #{request.uri.to_s}" if endpoint.nil?
|
14
|
+
[service, endpoint]
|
15
|
+
end
|
16
|
+
|
17
|
+
def service_metric(request,type)
|
18
|
+
service, endpoint = get_service_endpoint(request)
|
19
|
+
items = []
|
20
|
+
items << prefix
|
21
|
+
items << 'service'
|
22
|
+
items << service
|
23
|
+
items << type.to_s
|
24
|
+
items.join('.')
|
25
|
+
end
|
26
|
+
|
27
|
+
def endpoint_metric(request, type)
|
28
|
+
service, endpoint = get_service_endpoint(request)
|
29
|
+
items = []
|
30
|
+
items << prefix
|
31
|
+
items << 'endpoint'
|
32
|
+
items << service
|
33
|
+
items << endpoint
|
34
|
+
items << type.to_s
|
35
|
+
items.join('.')
|
36
|
+
end
|
37
|
+
|
38
|
+
def http_basic_tags(request)
|
39
|
+
service, endpoint = get_service_endpoint(request)
|
40
|
+
tags = []
|
41
|
+
tags << "idc:#{D13n.idc_name}"
|
42
|
+
tags << "env:#{D13n.idc_env}"
|
43
|
+
tags << "app:#{D13n.app_name}"
|
44
|
+
tags << "srv:#{service}"
|
45
|
+
tags << "endpoint:#{endpoint}"
|
46
|
+
tags
|
47
|
+
end
|
48
|
+
|
49
|
+
def http_status_tags(request, response)
|
50
|
+
tags = http_basic_tags(request)
|
51
|
+
tags << "status:#{response.code}"
|
52
|
+
tags
|
53
|
+
end
|
54
|
+
|
55
|
+
def http_error_tags(response)
|
56
|
+
tags = http_basic_tags
|
57
|
+
tags << "error:#{response.class.name.underscore}"
|
58
|
+
tags
|
59
|
+
end
|
60
|
+
|
61
|
+
def endpoint_status_metric(request,response)
|
62
|
+
"#{service_metric(request,:statue)}.#{response.code}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def service_error_metric(request,response)
|
66
|
+
"#{service_metric(request,:error)}.#{response.class.name.underscore}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module In
|
71
|
+
include Namespace
|
72
|
+
def process(*args, &block)
|
73
|
+
return yield unless Helper.http_in_tracable?
|
74
|
+
|
75
|
+
state = D13n::Metric::StreamState.st_get
|
76
|
+
state.request = metric_request(args)
|
77
|
+
|
78
|
+
trace_options = args.last.is_a?(Hash) ? args.last : {}
|
79
|
+
category = trace_options[:category] || :action
|
80
|
+
stream_options = create_stream_options(trace_options, category, state)
|
81
|
+
|
82
|
+
t0 = Time.now
|
83
|
+
begin
|
84
|
+
node = start(state, t0, request)
|
85
|
+
response = yield
|
86
|
+
ensure
|
87
|
+
finish(state, t0, node, request, response)
|
88
|
+
end
|
89
|
+
return response
|
90
|
+
end
|
91
|
+
|
92
|
+
def start(state, t0, request)
|
93
|
+
'start'
|
94
|
+
end
|
95
|
+
|
96
|
+
def finish(state, t0, node, request, response)
|
97
|
+
'finish'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
module Out
|
102
|
+
include Namespace
|
103
|
+
|
104
|
+
def process(request, collectable=true)
|
105
|
+
state = D13n::Metric::StreamState.st_get
|
106
|
+
|
107
|
+
return yield unless collectable && Helper.http_out_tracable?
|
108
|
+
|
109
|
+
t0 = Time.now
|
110
|
+
begin
|
111
|
+
node = start(state, t0, request)
|
112
|
+
response = yield
|
113
|
+
rescue ServiceNotFound => err
|
114
|
+
D13n.logger.error err.message
|
115
|
+
rescue Exception => err
|
116
|
+
D13n.logger.debug 'Unexpected exception raise while processing HTTP request metric', err
|
117
|
+
ensure
|
118
|
+
finish(state, t0, node, request, response || err)
|
119
|
+
end
|
120
|
+
return response
|
121
|
+
end
|
122
|
+
|
123
|
+
def start(state, t0, request)
|
124
|
+
inject_request_headers(state, request)
|
125
|
+
stack = state.traced_span_stack
|
126
|
+
node = stack.push_frame(state, prefix , t0)
|
127
|
+
return node
|
128
|
+
rescue => e
|
129
|
+
D13n.logger.error 'Uncaught exception while start processing HTTP request metric', e
|
130
|
+
return nil
|
131
|
+
end
|
132
|
+
|
133
|
+
def inject_request_headers(state, request)
|
134
|
+
stream = state.current_stream
|
135
|
+
|
136
|
+
state.is_cross_app_caller = true
|
137
|
+
if stream
|
138
|
+
request[StreamState::D13N_STREAM_HEADER] = state.referring_stream_id || stream.uuid
|
139
|
+
end
|
140
|
+
request[StreamState::D13N_APP_HEADER] = D13n.app_name
|
141
|
+
end
|
142
|
+
|
143
|
+
def finish(state, t0, node, request, response)
|
144
|
+
unless t0
|
145
|
+
D13n.logger.error("HTTP request process finished metric without start time. This is probably a bug.")
|
146
|
+
return
|
147
|
+
end
|
148
|
+
|
149
|
+
unless request
|
150
|
+
D13n.logger.error("HTTP request process finished metric without request. This is probably a bug.")
|
151
|
+
end
|
152
|
+
|
153
|
+
t1 = Time.now
|
154
|
+
duration = t1.to_f - t0.to_f
|
155
|
+
|
156
|
+
begin
|
157
|
+
scoped_metric = get_service_endpoint(request).join('.')
|
158
|
+
node.name = scoped_metric if node
|
159
|
+
if response
|
160
|
+
collect_error_count(request, response) if response.is_a? Exception
|
161
|
+
if response.is_a? Net::HTTPResponse
|
162
|
+
collect_status_count(request, response)
|
163
|
+
collect_request_timing(request, duration)
|
164
|
+
end
|
165
|
+
else
|
166
|
+
collect_request_count(request)
|
167
|
+
end
|
168
|
+
ensure
|
169
|
+
if node
|
170
|
+
stack = state.traced_span_stack
|
171
|
+
stack.pop_frame(state, node, scoped_metric, t1)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
rescue ServiceNotFound, EndpointNotFound => e
|
175
|
+
D13n.logger.debug "service or endpoind not found while collect HTTP metric:", e.message
|
176
|
+
rescue HTTPMetricError => e
|
177
|
+
D13n.logger.debug "while collect HTTP metric", e.message
|
178
|
+
rescue => e
|
179
|
+
D13n.logger.error "Uncaught exception while finishing an HTTP request metric", e
|
180
|
+
end
|
181
|
+
|
182
|
+
def collect_request_count(request, count=1, rate=1.0)
|
183
|
+
@collector.increment(metric_name('count'), count, sample_rate: rate, tags: http_basic_tags(request))
|
184
|
+
end
|
185
|
+
|
186
|
+
def collect_status_count(request, response, count=1, rate=1.0)
|
187
|
+
@collector.increment(metric_name('count'), count, sample_rate: rate, tags: http_status_tags(request, response))
|
188
|
+
end
|
189
|
+
|
190
|
+
def collect_error_count(request, response, count=1, rate=1.0)
|
191
|
+
@collector.increment(metric_name('count'), count, sample_rate: rate, tags: http_error_tags(request, response))
|
192
|
+
end
|
193
|
+
|
194
|
+
def collect_request_timing(request, timing, rate=1.0)
|
195
|
+
@collector.measure(metric_name('timing'), timing, sample_rate: rate, tags: http_basic_tags(request))
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.instance(collector, opts)
|
200
|
+
direction = opts[:direction]
|
201
|
+
check_direction(direction)
|
202
|
+
@instance = new(collector, opts)
|
203
|
+
@instance.extend PROCESSOR[direction]
|
204
|
+
end
|
205
|
+
|
206
|
+
PROCESSOR = {
|
207
|
+
'in' => In,
|
208
|
+
'out' => Out
|
209
|
+
}
|
210
|
+
|
211
|
+
def initialize(collector, opts)
|
212
|
+
@collector = collector
|
213
|
+
@opts = opts
|
214
|
+
@direction = @opts[:direction]
|
215
|
+
end
|
216
|
+
|
217
|
+
def prefix
|
218
|
+
"app.http.#{@direction[0]}"
|
219
|
+
end
|
220
|
+
|
221
|
+
def metric_name(type)
|
222
|
+
"#{prefix}.#{type}"
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.check_direction(direction)
|
226
|
+
raise InstrumentNameError.new "Wrong request direction #{direction}!" unless PROCESSOR.keys.include?(direction)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module D13n::Metric
|
2
|
+
class AppStateMetric < Base
|
3
|
+
module Namespace
|
4
|
+
def gem_metric_tags(gem_info)
|
5
|
+
tags = []
|
6
|
+
tags << "idc:#{Helper.idc_name}"
|
7
|
+
tags << "env:#{Helper.idc_env}"
|
8
|
+
tags << "app:#{Helper.app_name}"
|
9
|
+
tags << "gem:#{gem_info[0]}"
|
10
|
+
tags << "version:#{gem_info[1]}"
|
11
|
+
tags
|
12
|
+
end
|
13
|
+
|
14
|
+
def exception_metric_tags(exception, opts)
|
15
|
+
tags = []
|
16
|
+
tags << "idc:#{Helper.idc_name}"
|
17
|
+
tags << "env:#{Helper.idc_env}"
|
18
|
+
tags << "app:#{Helper.app_name}"
|
19
|
+
tags << "name:#{exception.class.name}"
|
20
|
+
tags << "at:#{opts.fetch(:at, 'runtime')}"
|
21
|
+
tags << "src:#{opts.fetch(:src, 'app')}"
|
22
|
+
tags << "uuid:#{opts.fetch(:uuid, 'unknown')}"
|
23
|
+
tags << "stream_id:#{opts[:referring_stream_id] || opts.fetch(:uuid, 'unknown')}"
|
24
|
+
tags
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module GemProcessor
|
29
|
+
include Namespace
|
30
|
+
|
31
|
+
def process
|
32
|
+
load_gem_spec.each do |g|
|
33
|
+
collect_gem_gauge(g)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def load_gem_spec
|
38
|
+
Gem.loaded_specs.inject({}) {
|
39
|
+
|m, (n,s)| m.merge(n => s.version)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def collect_gem_gauge(named_gem,gauge=1, rate=1.0)
|
44
|
+
@collector.gauge(metric_name('gauge'), gauge, sample_rate:rate, tags: gem_metric_tags(named_gem))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module ExceptionProcessor
|
49
|
+
include Namespace
|
50
|
+
|
51
|
+
def process
|
52
|
+
return yield unless Helper.exception_tracable?
|
53
|
+
|
54
|
+
begin
|
55
|
+
exception = yield
|
56
|
+
ensure
|
57
|
+
finish(exception)
|
58
|
+
end
|
59
|
+
return exception
|
60
|
+
end
|
61
|
+
|
62
|
+
def finish(exception)
|
63
|
+
metric_data = D13n::Metric::StreamState.default_metric_data
|
64
|
+
@opts.merge!(metric_data)
|
65
|
+
collect_exception_count(exception, @opts)
|
66
|
+
end
|
67
|
+
|
68
|
+
def collect_exception_count(exception, opts, count=1, rate=1.0)
|
69
|
+
@collector.increment(metric_name('count'), count, sample_rate: rate, tags: exception_metric_tags(exception,opts))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
PROCESSOR = {
|
74
|
+
'gem' => GemProcessor,
|
75
|
+
'exception' => ExceptionProcessor
|
76
|
+
}
|
77
|
+
|
78
|
+
def self.check_type(type)
|
79
|
+
raise InstrumentNameError.new "Wrong request process type #{type}!" unless PROCESSOR.has_key?(type)
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.instance(collector, opts)
|
83
|
+
type = opts[:type]
|
84
|
+
check_type(type)
|
85
|
+
@instance = new(collector, opts)
|
86
|
+
@instance.extend PROCESSOR[type]
|
87
|
+
end
|
88
|
+
|
89
|
+
def initialize(collector, opts)
|
90
|
+
@collector = collector
|
91
|
+
@opts = opts
|
92
|
+
@type = @opts[:type]
|
93
|
+
end
|
94
|
+
|
95
|
+
def metric_name(type)
|
96
|
+
"#{prefix}.#{type}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def prefix
|
100
|
+
"app.state.#{@type}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'd13n/metric/stream/stream_tracer_helpers'
|
2
|
+
module D13n::Metric
|
3
|
+
class Stream
|
4
|
+
module SpanTracerHelpers
|
5
|
+
MAX_ALLOWED_METRIC_DURATION = 1_000_000_000
|
6
|
+
include StreamTracerHelpers::Namer
|
7
|
+
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
def collect_span_duration_timing(collector, state, name, timing, metric_data, options, rate=1.0)
|
12
|
+
collector.measure(metric_name("timing"), timing, sample_rate: rate, tags: stream_duration_tags(metric_data))
|
13
|
+
end
|
14
|
+
|
15
|
+
def collect_span_exclusive_timing(collector, state, name, timing, metric_data, options, rate=1.0)
|
16
|
+
collector.measure(metric_name("timing"), timing, sample_rate: rate, tags: stream_exclusive_tags(metric_data))
|
17
|
+
end
|
18
|
+
|
19
|
+
def collect_span_request_count(collector, state, name, metric_data, options, count = 1, rate = 1.0)
|
20
|
+
collector.increment(metric_name("count"), count, sample_rate: rate, tags: stream_request_tags(metric_data))
|
21
|
+
end
|
22
|
+
|
23
|
+
def collect_span_metrics(state, first_name, duration, exclusive, metric_data, options)
|
24
|
+
collector = D13n::Metric::Manager.instance
|
25
|
+
collect_span_duration_timing(collector, state, first_name, duration, metric_data, options)
|
26
|
+
collect_span_exclusive_timing(collector, state, first_name, exclusive, metric_data, options)
|
27
|
+
collect_span_request_count(collector, state, first_name, metric_data, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def trace_header(state, t0)
|
31
|
+
stack = state.traced_span_stack
|
32
|
+
stack.push_frame(state, :span_tracer, t0)
|
33
|
+
end
|
34
|
+
|
35
|
+
def trace_footer(state, t0, first_name, expected_frame, options, t1=Time.now.to_f)
|
36
|
+
if expected_frame
|
37
|
+
stack = state.traced_span_stack
|
38
|
+
frame = stack.pop_frame(state, expected_frame, first_name, t1)
|
39
|
+
duration, exclusive = get_timings(t0, t1, frame)
|
40
|
+
metric_data = {:exclusive => exclusive}
|
41
|
+
get_metric_data(state, t0, t1, metric_data)
|
42
|
+
|
43
|
+
if duration < MAX_ALLOWED_METRIC_DURATION
|
44
|
+
if duration < 0
|
45
|
+
D13n.logger.warn("metric_duration_negative:#{first_name} Metric #{first_name} has negative duration: #{duration} s")
|
46
|
+
end
|
47
|
+
|
48
|
+
if exclusive < 0
|
49
|
+
D13n.logger.warn("metric_exclusive_negative: #{first_name} Metric #{first_name} has negative exclusive time: duration = #{duration} s, child_time = #{frame.children_time}")
|
50
|
+
end
|
51
|
+
|
52
|
+
collect_span_metrics(state, first_name, duration, exclusive, metric_data, options)
|
53
|
+
else
|
54
|
+
D13n.logger.warn("too_huge_metric:#{first_name}, Ignoring metric #{first_name} with unacceptably large duration: #{duration} s")
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_timings(t0, t1, frame)
|
61
|
+
duration = t1 - t0
|
62
|
+
exclusive = duration - frame.children_time
|
63
|
+
[duration, exclusive]
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_metric_data(state, t0, t1, metric_data)
|
67
|
+
stream = state.current_stream
|
68
|
+
stream.generate_default_metric_data(state, t0, t1, metric_data)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module D13n::Metric
|
2
|
+
class Stream
|
3
|
+
module StreamTracerHelpers
|
4
|
+
module Namer
|
5
|
+
def prefix
|
6
|
+
"app.http.i"
|
7
|
+
end
|
8
|
+
|
9
|
+
def metric_name(type)
|
10
|
+
"#{prefix}.#{type}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def stream_basic_tags(metric_data)
|
14
|
+
tags = []
|
15
|
+
tags << "idc:#{D13n.idc_name}"
|
16
|
+
tags << "env:#{D13n.idc_env}"
|
17
|
+
tags << "app:#{D13n.app_name}"
|
18
|
+
tags << "name:#{metric_data[:name]}"
|
19
|
+
tags << "uuid:#{metric_data[:uuid]}"
|
20
|
+
tags << "stream_id:#{metric_data[:referring_stream_id] || metric_data[:uuid]}"
|
21
|
+
tags << "type:#{metric_data[:referring_stream_id].nil? ? 'stream' : 'span'}"
|
22
|
+
tags
|
23
|
+
end
|
24
|
+
|
25
|
+
def stream_duration_tags(metric_data)
|
26
|
+
tags = stream_basic_tags(metric_data)
|
27
|
+
tags << "time:duration"
|
28
|
+
tags
|
29
|
+
end
|
30
|
+
|
31
|
+
def stream_exclusive_tags(metric_data)
|
32
|
+
tags = stream_basic_tags(metric_data)
|
33
|
+
tags << "time:exclusive"
|
34
|
+
tags
|
35
|
+
end
|
36
|
+
|
37
|
+
def stream_request_tags(metric_data)
|
38
|
+
tags = stream_basic_tags(metric_data)
|
39
|
+
tags
|
40
|
+
end
|
41
|
+
|
42
|
+
def stream_http_response_code_tags(metric_data)
|
43
|
+
tags = stream_basic_tags(metric_data)
|
44
|
+
tags << "response:code"
|
45
|
+
tags << "code:#{metric_data[:http_response_code]}"
|
46
|
+
tags
|
47
|
+
end
|
48
|
+
|
49
|
+
def stream_http_response_content_type_tags(metric_data)
|
50
|
+
tags = stream_basic_tags(metric_data)
|
51
|
+
tags << "response:type"
|
52
|
+
tags << "type:#{metric_data[:http_response_content_type]}"
|
53
|
+
tags
|
54
|
+
end
|
55
|
+
|
56
|
+
def stream_http_request_content_length_tags(metric_data)
|
57
|
+
tags = stream_basic_tags(metric_data)
|
58
|
+
tags << "request:length"
|
59
|
+
tags
|
60
|
+
end
|
61
|
+
|
62
|
+
def stream_http_response_content_length_tags(metric_data)
|
63
|
+
tags = stream_basic_tags(metric_data)
|
64
|
+
tags << "response:length"
|
65
|
+
tags
|
66
|
+
end
|
67
|
+
|
68
|
+
def stream_error_tags(metric_data, error)
|
69
|
+
tags = stream_basic_tags(metric_data)
|
70
|
+
tags << "error:#{error.is_a?(Class) ? error.name : error.class.name}"
|
71
|
+
tags
|
72
|
+
end
|
73
|
+
|
74
|
+
def stream_apdex_tags(metric_data)
|
75
|
+
tags = stream_basic_tags(metric_data)
|
76
|
+
tags << "apdex_zone:#{metric_data[:apdex_perf_zone]}"
|
77
|
+
tags
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
include Namer
|
82
|
+
extend self
|
83
|
+
|
84
|
+
def collect_duration_metric(collector, state, timing, metric_data, rate=1.0)
|
85
|
+
collector.measure(metric_name("timing"), timing, sample_rate: rate, tags: stream_duration_tags(metric_data))
|
86
|
+
end
|
87
|
+
|
88
|
+
def collect_exclusive_metric(collector, state, timing, metric_data, rate=1.0)
|
89
|
+
collector.measure(metric_name("timing"), timing, sample_rate: rate, tags: stream_exclusive_tags(metric_data))
|
90
|
+
end
|
91
|
+
|
92
|
+
def collect_apdex_metric(collector, state, metric_data, count=1,rate=1.0)
|
93
|
+
collector.increment(metric_name("count"), count, sample_rate: rate, tags: stream_apdex_tags(metric_data))
|
94
|
+
end
|
95
|
+
|
96
|
+
def collect_repsonse_code_metric(collector, state, metric_data, count=1, rate=1.0)
|
97
|
+
collector.increment(metric_name("count"), count, sample_rate: rate, tags: stream_http_response_code_tags(metric_data))
|
98
|
+
end
|
99
|
+
|
100
|
+
def collect_response_content_type_metric(collector, state, metric_data, count=1, rate=1.0)
|
101
|
+
collector.increment(metric_name("count"), count, sample_rate: rate, tags: stream_http_response_content_type_tags(metric_data))
|
102
|
+
end
|
103
|
+
|
104
|
+
def collect_response_content_length_metric(collector, state, gauge, metric_data, rate=1.0)
|
105
|
+
collector.gauge(metric_name("gauge"), gauge.to_i, sample_rate: rate, tags: stream_http_response_content_length_tags(metric_data))
|
106
|
+
end
|
107
|
+
|
108
|
+
def collect_request_content_length_metric(collector, state, gauge, metric_data, rate=1.0)
|
109
|
+
collector.gauge(metric_name("gauge"), gauge.to_i, sample_rate: rate, tags: stream_http_request_content_length_tags(metric_data))
|
110
|
+
end
|
111
|
+
|
112
|
+
def collect_response_metric(collector, state, metric_data)
|
113
|
+
collect_repsonse_code_metric(collector, state, metric_data)
|
114
|
+
collect_response_content_type_metric(collector, state, metric_data)
|
115
|
+
collect_response_content_length_metric(collector, state, metric_data[:http_response_content_length], metric_data)
|
116
|
+
collect_request_content_length_metric(collector, state, metric_data[:http_request_content_length], metric_data) unless metric_data[:http_request_content_length].to_i == 0
|
117
|
+
end
|
118
|
+
|
119
|
+
def collect_error_metric(collector, state, error, metric_data, count=1, rate=1.0 )
|
120
|
+
collector.increment(metric_name('count'), count, sample_rate: rate, tags: stream_error_tags(metric_data, error))
|
121
|
+
end
|
122
|
+
|
123
|
+
def collect_errors_metric(collector, state, metric_data)
|
124
|
+
errors = metric_data[:errors]
|
125
|
+
|
126
|
+
errors.each do |error|
|
127
|
+
collect_error_metric(collector, state, error, metric_data)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def collect_metrics(state, metric_data)
|
132
|
+
collector = D13n::Metric::Manager.instance
|
133
|
+
collect_duration_metric(collector, state, metric_data[:duration], metric_data)
|
134
|
+
collect_exclusive_metric(collector, state, metric_data[:exclusive], metric_data)
|
135
|
+
collect_apdex_metric(collector, state, metric_data)
|
136
|
+
collect_response_metric(collector, state, metric_data)
|
137
|
+
collect_errors_metric(collector, state, metric_data) if metric_data[:error]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module D13n::Metric
|
2
|
+
class Stream
|
3
|
+
class UnexpectedStackError < D13n::Error;end
|
4
|
+
class StackFrame
|
5
|
+
attr_reader :tag
|
6
|
+
attr_accessor :name, :start_time, :children_time, :end_time
|
7
|
+
def initialize(tag, start_time)
|
8
|
+
@tag = tag
|
9
|
+
@start_time = start_time
|
10
|
+
@children_time = 0
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TracedSpanStack
|
15
|
+
def initialize
|
16
|
+
@stack = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def push_frame(state, tag, time = Time.now.to_f)
|
20
|
+
frame = StackFrame.new(tag, time)
|
21
|
+
@stack.push frame
|
22
|
+
frame
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop_frame(state, expected_frame, name, time, deduct_call_time_from_parent=true)
|
26
|
+
frame = fetch_matching_frame(expected_frame)
|
27
|
+
frame.end_time = time
|
28
|
+
frame.name = name
|
29
|
+
|
30
|
+
note_children_time(frame, time, deduct_call_time_from_parent)
|
31
|
+
|
32
|
+
frame
|
33
|
+
end
|
34
|
+
|
35
|
+
def fetch_matching_frame(expected_frame)
|
36
|
+
while frame = @stack.pop
|
37
|
+
if frame == expected_frame
|
38
|
+
return frame
|
39
|
+
else
|
40
|
+
D13n.logger.info("Unexpected frame in traced method stack: #{frame.inspect} expected to be #{expected_frame.inspect}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
raise UnexpectedStackError.new "Frame not found in stack: #{expected_frame.inspect}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def note_children_time(frame, time, deduct_call_time_from_parent)
|
47
|
+
if !@stack.empty?
|
48
|
+
if deduct_call_time_from_parent
|
49
|
+
@stack.last.children_time += (time - frame.start_time)
|
50
|
+
else
|
51
|
+
@stack.last.children_time += frame.children_time
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def empty?
|
57
|
+
@stack.empty?
|
58
|
+
end
|
59
|
+
|
60
|
+
def clear
|
61
|
+
@stack.clear
|
62
|
+
end
|
63
|
+
|
64
|
+
def last
|
65
|
+
@stack.last
|
66
|
+
end
|
67
|
+
|
68
|
+
def size
|
69
|
+
@stack.size
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|