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,322 @@
|
|
1
|
+
require 'd13n/metric/stream_state'
|
2
|
+
require 'd13n/metric/instrumentation/controller_instrumentation'
|
3
|
+
require 'd13n/metric/stream/stream_tracer_helpers'
|
4
|
+
require 'd13n/metric/stream/span_tracer_helpers'
|
5
|
+
require 'securerandom'
|
6
|
+
|
7
|
+
module D13n::Metric
|
8
|
+
class Stream
|
9
|
+
|
10
|
+
SINATRA_PREFIX = 'controller.sinatra'.freeze
|
11
|
+
MIDDLEWARE_PREFIX = 'controller.middleware'.freeze
|
12
|
+
|
13
|
+
WEB_TRANSACTION_CATEGORIES = [:controller, :uri, :rack, :sinatra, :websocket].freeze
|
14
|
+
|
15
|
+
APDEX_S = 'S'.freeze
|
16
|
+
APDEX_T = 'T'.freeze
|
17
|
+
APDEX_F = 'F'.freeze
|
18
|
+
|
19
|
+
attr_accessor :state, :started_at, :uuid
|
20
|
+
attr_accessor :http_response_code,
|
21
|
+
:request_content_length,
|
22
|
+
:response_content_type,
|
23
|
+
:response_content_length, :frame_stack
|
24
|
+
|
25
|
+
def self.st_current
|
26
|
+
StreamState.st_get.current_stream
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.set_default_stream_name(name, category = nil, node_name = nil)
|
30
|
+
stream = st_current
|
31
|
+
name = stream.make_stream_name(name, category)
|
32
|
+
stream.name_last_frame(node_name || name)
|
33
|
+
stream.set_default_stream_name(name, category)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.start(state, category, options)
|
37
|
+
category ||= :controller
|
38
|
+
stream = state.current_stream
|
39
|
+
|
40
|
+
if stream
|
41
|
+
stream.create_nested_stream(state, category, options)
|
42
|
+
else
|
43
|
+
stream = start_new_stream(state, category, options)
|
44
|
+
end
|
45
|
+
stream
|
46
|
+
rescue => e
|
47
|
+
D13n.logger.error("Exception during Stream.start", e)
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.start_new_stream(state, category, options)
|
52
|
+
stream = new(category, options)
|
53
|
+
state.reset(stream)
|
54
|
+
stream.state = state
|
55
|
+
stream.start(state)
|
56
|
+
stream
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.stop(state, ended_time=Time.now.to_f)
|
60
|
+
stream = state.current_stream
|
61
|
+
if stream.nil?
|
62
|
+
D13n.logger.error("Failed during Stream.stop because there is no current stream")
|
63
|
+
return
|
64
|
+
end
|
65
|
+
|
66
|
+
nested_frame = stream.frame_stack.pop
|
67
|
+
if stream.frame_stack.empty?
|
68
|
+
stream.stop(state, ended_time, nested_frame)
|
69
|
+
state.reset
|
70
|
+
else
|
71
|
+
nested_name = nested_stream_name(nested_frame.name)
|
72
|
+
begin
|
73
|
+
D13n::Metric::Stream::SpanTracerHelpers.trace_footer(state, nested_frame.start_time.to_f, nested_name, nested_frame, {})
|
74
|
+
rescue => e
|
75
|
+
D13n.logger.debug "Error in trace_footer #{e}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
#:stream_stopped
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.notice_error(exception, options={})
|
83
|
+
state = D13n::Metric::StreamState.st_get
|
84
|
+
stream = state.current_stream
|
85
|
+
if stream
|
86
|
+
stream.notice_error(exception, options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.apdex_bucket(duration, failed, apdex_t)
|
91
|
+
|
92
|
+
case
|
93
|
+
when failed
|
94
|
+
:apdex_f
|
95
|
+
when duration <= apdex_t
|
96
|
+
:apdex_s
|
97
|
+
when duration <= (4 * apdex_t)
|
98
|
+
:apdex_t
|
99
|
+
else
|
100
|
+
:apdex_f
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.nested_stream_name(name)
|
105
|
+
name
|
106
|
+
end
|
107
|
+
|
108
|
+
def initialize(category, options)
|
109
|
+
@frame_stack = []
|
110
|
+
|
111
|
+
@category = category
|
112
|
+
@started_at = Time.now.to_f
|
113
|
+
|
114
|
+
@default_name = options[:stream_name]
|
115
|
+
|
116
|
+
@apdex_started_at = options[:apdex_started_at] || @started_at
|
117
|
+
|
118
|
+
@ignore_apdex = false
|
119
|
+
@ignore_this_stream = false
|
120
|
+
|
121
|
+
@uuid = nil
|
122
|
+
@exceptions = {}
|
123
|
+
@request_content_length = 0
|
124
|
+
@response_content_type = nil
|
125
|
+
@response_content_length = 0
|
126
|
+
end
|
127
|
+
|
128
|
+
def start(state)
|
129
|
+
@frame_stack.push D13n::Metric::Stream::SpanTracerHelpers.trace_header(state, @started_at)
|
130
|
+
name_last_frame @default_name
|
131
|
+
end
|
132
|
+
|
133
|
+
def stop(state, ended_time, outermost_frame)
|
134
|
+
trace_options = {}
|
135
|
+
if @has_children
|
136
|
+
name = self.class.nested_stream_name(outermost_frame.name)
|
137
|
+
else
|
138
|
+
name = @frozen_name
|
139
|
+
end
|
140
|
+
|
141
|
+
D13n::Metric::Stream::SpanTracerHelpers.trace_footer(state, @started_at.to_f, name, outermost_frame, trace_options, ended_time.to_f)
|
142
|
+
duration = ended_time - @started_at
|
143
|
+
exclusive = duration - outermost_frame.children_time
|
144
|
+
commit!(state, exclusive, ended_time) unless @ignore_this_stream
|
145
|
+
end
|
146
|
+
|
147
|
+
def commit!(state, exclusive, ended_time)
|
148
|
+
@metric_data = {:exclusive => exclusive}
|
149
|
+
collect_metric_data(state, @metric_data, ended_time)
|
150
|
+
collect_metrics(state, @metric_data)
|
151
|
+
end
|
152
|
+
|
153
|
+
def apdex_t
|
154
|
+
stream_specific_apdex_t || D13n.config[:'metric.app.http.in.apdex_t']
|
155
|
+
end
|
156
|
+
|
157
|
+
def stream_specific_apdex_t
|
158
|
+
key = "metric.app.http.in.apdex_t.#{@frozen_name}".to_sym
|
159
|
+
D13n.config[key]
|
160
|
+
end
|
161
|
+
|
162
|
+
def collect_metrics(state, metric_data)
|
163
|
+
StreamTracerHelpers.collect_metrics(state, metric_data)
|
164
|
+
end
|
165
|
+
|
166
|
+
def collect_metric_data(state, metric_data, ended_time = Time.now.to_f)
|
167
|
+
total_duration = ended_time - @apdex_started_at
|
168
|
+
action_duration = ended_time - @started_at.to_f
|
169
|
+
|
170
|
+
# collect_apdex_metric(total_duration, action_duration, apdex_t)
|
171
|
+
generate_metric_data(state, metric_data, @started_at, ended_time)
|
172
|
+
end
|
173
|
+
|
174
|
+
# def collect_apdex_metric(total_duration, action_duration, current_apdex_t)
|
175
|
+
# apdex_bucket_global = apdex_bucket(total_duration, current_apdex_t)
|
176
|
+
# apdex_bucket_stream = apdex_bucket(action_duration, current_apdex_t)
|
177
|
+
# end
|
178
|
+
|
179
|
+
def default_metric_data
|
180
|
+
metric_data = {
|
181
|
+
:name => @frozen_name || @default_name,
|
182
|
+
:uuid => uuid,
|
183
|
+
:error => false
|
184
|
+
}
|
185
|
+
|
186
|
+
generate_error_data(metric_data)
|
187
|
+
metric_data[:referring_stream_id] = @state.referring_stream_id if @state.referring_stream_id
|
188
|
+
metric_data
|
189
|
+
end
|
190
|
+
|
191
|
+
def generate_error_data(metric_data)
|
192
|
+
if had_error?
|
193
|
+
metric_data.merge!({
|
194
|
+
:error => true,
|
195
|
+
:errors => @exceptions
|
196
|
+
})
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def generate_default_metric_data(state, started_at, ended_time, metric_data)
|
201
|
+
duration = ended_time - started_at
|
202
|
+
|
203
|
+
metric_data.merge!(default_metric_data)
|
204
|
+
metric_data.merge!({
|
205
|
+
:type => :request,
|
206
|
+
:started_at => started_at,
|
207
|
+
:duration => duration,
|
208
|
+
})
|
209
|
+
metric_data
|
210
|
+
end
|
211
|
+
|
212
|
+
def generate_metric_data(state, metric_data, started_at, ended_time)
|
213
|
+
duration = ended_time - started_at
|
214
|
+
metric_data ||= {}
|
215
|
+
generate_default_metric_data(state, started_at, ended_time, metric_data)
|
216
|
+
append_apdex_perf_zone(duration, metric_data)
|
217
|
+
append_web_response(@http_response_code, @response_content_type, @response_content_length, @request_content_length, metric_data) if recording_web_transaction?
|
218
|
+
metric_data
|
219
|
+
end
|
220
|
+
|
221
|
+
def had_error?
|
222
|
+
!@exceptions.empty?
|
223
|
+
end
|
224
|
+
|
225
|
+
def had_exception_affecting_apdex?
|
226
|
+
# all exceptions are affecting
|
227
|
+
had_error?
|
228
|
+
end
|
229
|
+
|
230
|
+
def apdex_bucket(duration, current_apdex_t)
|
231
|
+
self.class.apdex_bucket(duration, had_exception_affecting_apdex?, current_apdex_t)
|
232
|
+
end
|
233
|
+
|
234
|
+
def append_apdex_perf_zone(duration, metric_data)
|
235
|
+
bucket = apdex_bucket(duration, apdex_t)
|
236
|
+
|
237
|
+
return unless bucket
|
238
|
+
|
239
|
+
bucket_str = case bucket
|
240
|
+
when :apdex_s then APDEX_S
|
241
|
+
when :apdex_t then APDEX_T
|
242
|
+
when :apdex_f then APDEX_F
|
243
|
+
else nil
|
244
|
+
end
|
245
|
+
|
246
|
+
metric_data[:apdex_perf_zone] = bucket_str if bucket_str
|
247
|
+
end
|
248
|
+
|
249
|
+
def append_web_response(http_response_code,response_content_type,response_content_length,request_content_length,metric_data)
|
250
|
+
return if http_response_code.nil?
|
251
|
+
|
252
|
+
metric_data[:http_response_code] = http_response_code
|
253
|
+
metric_data[:http_response_content_type] = response_content_type
|
254
|
+
metric_data[:http_response_content_length] = response_content_length
|
255
|
+
metric_data[:http_request_content_length] = request_content_length
|
256
|
+
end
|
257
|
+
|
258
|
+
def make_stream_name(name, category=nil)
|
259
|
+
namer = Instrumentation::ControllerInstrumentation::StreamNamer
|
260
|
+
"#{namer.prefix_for_category(self, category)}.#{name}"
|
261
|
+
end
|
262
|
+
|
263
|
+
def set_default_stream_name(name, category)
|
264
|
+
@default_name = name
|
265
|
+
@category = category if category
|
266
|
+
end
|
267
|
+
|
268
|
+
def name_last_frame(name)
|
269
|
+
@frame_stack.last.name = name
|
270
|
+
end
|
271
|
+
|
272
|
+
def notice_error(exception, options={})
|
273
|
+
if @exceptions[exception]
|
274
|
+
@exceptions[exception].merge! options
|
275
|
+
else
|
276
|
+
@exceptions[exception] = options
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def create_nested_stream(state, category, options)
|
281
|
+
@has_children = true
|
282
|
+
|
283
|
+
@frame_stack.push D13n::Metric::Stream::SpanTracerHelpers.trace_header(state, Time.now.to_f)
|
284
|
+
name_last_frame(options[:stream_name])
|
285
|
+
|
286
|
+
set_default_stream_name(options[:stream_name], category)
|
287
|
+
end
|
288
|
+
|
289
|
+
def set_default_stream_name(name, category)
|
290
|
+
return if name_frozen?
|
291
|
+
@default_name = name
|
292
|
+
@category = category if category
|
293
|
+
end
|
294
|
+
|
295
|
+
def name_frozen?
|
296
|
+
@frozen_name ? true : false
|
297
|
+
end
|
298
|
+
|
299
|
+
def name_last_frame(name)
|
300
|
+
@frame_stack.last.name = name
|
301
|
+
end
|
302
|
+
|
303
|
+
def recording_web_transaction?
|
304
|
+
web_category?(@category)
|
305
|
+
end
|
306
|
+
|
307
|
+
def web_category?(category)
|
308
|
+
WEB_TRANSACTION_CATEGORIES.include?(category)
|
309
|
+
end
|
310
|
+
|
311
|
+
def get_id
|
312
|
+
uuid
|
313
|
+
end
|
314
|
+
|
315
|
+
def uuid
|
316
|
+
return @uuid if @uuid
|
317
|
+
request_info = StreamState.request_info
|
318
|
+
@uuid = (request_info.nil? || request_info["request_id"].nil?) ? SecureRandom.hex(16) : request_info["request_id"]
|
319
|
+
@uuid
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'd13n/metric/stream/traced_span_stack'
|
2
|
+
module D13n::Metric
|
3
|
+
class StateError < D13n::Error;end
|
4
|
+
class StreamState
|
5
|
+
|
6
|
+
D13N_STREAM_HEADER = 'X-D13n-Stream-ID'
|
7
|
+
D13N_APP_HEADER = 'X-D13n-App'
|
8
|
+
REQUEST_ID_HEADER = 'HTTP_X_REQUEST_ID'
|
9
|
+
|
10
|
+
def self.st_get
|
11
|
+
st_state_for(Thread.current)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.st_state_for(thread)
|
15
|
+
thread[:d13n_stream_state] ||= new
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.request_info
|
19
|
+
st_get.request_info
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.default_metric_data
|
23
|
+
state = st_get
|
24
|
+
stream = state.current_stream
|
25
|
+
if stream
|
26
|
+
stream.default_metric_data
|
27
|
+
else
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :traced_span_stack
|
33
|
+
attr_accessor :request_info
|
34
|
+
attr_accessor :tag_hash
|
35
|
+
attr_accessor :current_stream
|
36
|
+
attr_accessor :request
|
37
|
+
attr_accessor :referring_stream_id, :is_cross_app_caller
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
@traced_span_stack = D13n::Metric::Stream::TracedSpanStack.new
|
41
|
+
@current_stream = nil
|
42
|
+
@referring_stream_id = nil
|
43
|
+
@is_cross_app_caller = false
|
44
|
+
end
|
45
|
+
|
46
|
+
def reset(stream=nil)
|
47
|
+
@traced_span_stack.clear
|
48
|
+
@current_stream = stream
|
49
|
+
@is_cross_app_caller = false
|
50
|
+
end
|
51
|
+
|
52
|
+
def notify_rack_call(request)
|
53
|
+
notify_call(request)
|
54
|
+
end
|
55
|
+
|
56
|
+
def notify_call(request)
|
57
|
+
save_referring_stream_id(request)
|
58
|
+
end
|
59
|
+
|
60
|
+
def save_referring_stream_id(request)
|
61
|
+
@referring_stream_id = request[D13N_STREAM_HEADER] if request[D13N_STREAM_HEADER]
|
62
|
+
end
|
63
|
+
|
64
|
+
def clear_referring_stream_id()
|
65
|
+
@referring_stream_id = nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/d13n/metric.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module D13n::Metric
|
2
|
+
class MetricError < D13n::Error; end
|
3
|
+
end
|
4
|
+
require 'd13n/metric/stream'
|
5
|
+
require 'd13n/metric/stream_state'
|
6
|
+
require 'd13n/metric/http_clients'
|
7
|
+
require 'd13n/metric/manager'
|
8
|
+
|
9
|
+
module D13n::Metric
|
10
|
+
class MetricError < D13n::Error;end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'd13n/metric/instrumentation/controller_instrumentation'
|
2
|
+
module D13n
|
3
|
+
module Rack
|
4
|
+
class D13nMiddleware
|
5
|
+
attr_reader :stream_options, :category
|
6
|
+
def initialize(app, options={})
|
7
|
+
@app = app
|
8
|
+
@category = :middleware
|
9
|
+
@target = self
|
10
|
+
@stream_options = {
|
11
|
+
:stream_name => build_stream_name
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_stream_name
|
16
|
+
prefix = ::D13n::Metric::Instrumentation::ControllerInstrumentation::StreamNamer.prefix_for_category(nil, @category)
|
17
|
+
"#{prefix}.#{self.class.name}.call"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'd13n/metric/stream_state'
|
2
|
+
require 'd13n/metric/instrumentation/middleware_tracing'
|
3
|
+
require 'd13n/rack/d13n_middleware'
|
4
|
+
module D13n
|
5
|
+
module Rack
|
6
|
+
class MetricMiddleware < D13nMiddleware
|
7
|
+
include D13n::Metric::Instrumentation::MiddlewareTracing
|
8
|
+
|
9
|
+
def self.enabled?
|
10
|
+
D13n.config[:'metric.app.http.in.tracable']
|
11
|
+
end
|
12
|
+
|
13
|
+
def traced_call(env)
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Sinatra
|
2
|
+
class Base
|
3
|
+
class << self
|
4
|
+
alias_method :run_without_callback, :run!
|
5
|
+
|
6
|
+
def background_job(opts = {}, &block)
|
7
|
+
@background_jobs ||= []
|
8
|
+
@background_jobs << {opts: opts, blk: block}
|
9
|
+
end
|
10
|
+
|
11
|
+
def background_job_run!
|
12
|
+
return if @background_jobs.nil?
|
13
|
+
@background_jobs.each do |j|
|
14
|
+
j[:blk].call(j[:opts])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def run!(*args, &block)
|
19
|
+
background_job_run!
|
20
|
+
run_without_callback(*args, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'd13n/service/background_job/sinatra' if defined?(::Sinatra) && defined?(::Sinatra::Base)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'config_kit'
|
2
|
+
|
3
|
+
module D13n
|
4
|
+
class Service
|
5
|
+
module Start
|
6
|
+
def start_metric_manager
|
7
|
+
begin
|
8
|
+
channel = determine_metric_channel
|
9
|
+
Metric::Manager.start(channel)
|
10
|
+
rescue Exception => e
|
11
|
+
D13n.logger.error "Unknown Instrument Manager error. #{e.message}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_api_service
|
16
|
+
@started = true
|
17
|
+
Object.const_get("#{D13n.application.name}::Api::Service").run!(@service_conf)
|
18
|
+
end
|
19
|
+
|
20
|
+
def log_startup
|
21
|
+
log_environment
|
22
|
+
log_service_name
|
23
|
+
end
|
24
|
+
|
25
|
+
def log_environment
|
26
|
+
D13n.logger.info "Environment: #{D13n.service.instance.env}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def log_service_name
|
30
|
+
D13n.logger.info "Service: #{D13n.config.app_name}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def log_version_and_pid
|
34
|
+
D13n.logger.debug "#{D13n.config.app_name} Service #{D13n.service.app_class::VERSION}(D13n:#{D13n::VERSION::STRING}) Initialized: pid = #{$$}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def query_server_for_configuration
|
38
|
+
begin
|
39
|
+
#
|
40
|
+
# TODO: Config Kit may enhance configurator
|
41
|
+
#
|
42
|
+
ConfigKit.config.url = D13n.config[:ck_url] || D13n.config[:'service.config_kit.url']
|
43
|
+
config_data = ConfigKit::Manager.get(D13n.config.app_name)
|
44
|
+
rescue ConfigKit::Client::ConfigKitReadError => e
|
45
|
+
D13n.logger.error "Config Kit reads server error. #{e.message}"
|
46
|
+
raise ServiceStartError.new(e.message) if config_server_raise_on_failure?
|
47
|
+
rescue Exception => e
|
48
|
+
D13n.logger.error "Unknown Config Kit error. #{e.message}"
|
49
|
+
D13n.logger.debug e
|
50
|
+
raise ServiceStartError.new(e.message) if config_server_raise_on_failure?
|
51
|
+
end
|
52
|
+
#
|
53
|
+
# TODO: Empty to raise exception
|
54
|
+
#
|
55
|
+
return if config_data.nil? || config_data.empty?
|
56
|
+
|
57
|
+
D13n.logger.debug "Server provided config: #{config_data.inspect}"
|
58
|
+
|
59
|
+
server_config = D13n::Configuration::ServerSource.build(config_data)
|
60
|
+
D13n.config.replace_or_add_config(server_config)
|
61
|
+
end
|
62
|
+
|
63
|
+
def config_server_raise_on_failure?
|
64
|
+
D13n.config[:'config_server.raise_on_failure'] == true || D13n.config[:'config_server.raise_on_failure'] == 'true'
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def determine_metric_channel
|
70
|
+
D13n.config[:metric_channel_type] || D13n.config[:'metric.channel.type']
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/d13n/service.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'd13n/ext/string'
|
2
|
+
require 'd13n/service/start'
|
3
|
+
module D13n
|
4
|
+
class Service
|
5
|
+
class ServiceError < Error; end
|
6
|
+
class ServiceStartError < ServiceError; end
|
7
|
+
|
8
|
+
include Start
|
9
|
+
class << self
|
10
|
+
def instance
|
11
|
+
@instance ||= new
|
12
|
+
end
|
13
|
+
|
14
|
+
def run!(opts)
|
15
|
+
D13n.service.instance.init(opts)
|
16
|
+
D13n.service.instance.start
|
17
|
+
end
|
18
|
+
|
19
|
+
def app_class
|
20
|
+
@app_kls ||= Object.const_get(name.split("::").first)
|
21
|
+
end
|
22
|
+
|
23
|
+
def inherited(descendant)
|
24
|
+
raise ServiceError, "You cannot have more than one D13n::Service" if D13n.service && descendant == D13n::Service
|
25
|
+
descendant.app_class.extend Application::ClassMethods
|
26
|
+
D13n.service = descendant
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :service_conf, :env, :service_prefix, :started
|
31
|
+
def initialize()
|
32
|
+
@started=false
|
33
|
+
@service_prefix = D13n.service.app_class.name.underscore.upcase
|
34
|
+
end
|
35
|
+
|
36
|
+
def init(opts)
|
37
|
+
determine_service_conf(opts)
|
38
|
+
determine_env(opts)
|
39
|
+
config_service(opts)
|
40
|
+
determine_logger(opts)
|
41
|
+
end
|
42
|
+
|
43
|
+
def determine_logger(opts)
|
44
|
+
if D13n.logger.is_startup_logger?
|
45
|
+
D13n.logger = D13n::Logger.new(root,opts.delete(:logger))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def start
|
50
|
+
return if started?
|
51
|
+
log_startup
|
52
|
+
query_server_for_configuration
|
53
|
+
start_metric_manager
|
54
|
+
log_version_and_pid
|
55
|
+
start_api_service
|
56
|
+
end
|
57
|
+
|
58
|
+
def determine_service_conf(opts={})
|
59
|
+
@service_conf ||= {}
|
60
|
+
@service_conf[:port] = opts.fetch(:port, 3000)
|
61
|
+
@service_conf[:bind] = opts.fetch(:host, 'localhost')
|
62
|
+
end
|
63
|
+
|
64
|
+
def determine_env(opts={})
|
65
|
+
@env = opts.fetch(:env, default_env).to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
def config_service(opts)
|
69
|
+
config_file_path = D13n.config[:config_path]
|
70
|
+
D13n.config.replace_or_add_config(D13n::Configuration::YamlSource.new(config_file_path, env))
|
71
|
+
end
|
72
|
+
|
73
|
+
def started?
|
74
|
+
@started
|
75
|
+
end
|
76
|
+
|
77
|
+
def root
|
78
|
+
@root = ENV['SERVICE_ROOT'] || '.'
|
79
|
+
end
|
80
|
+
|
81
|
+
def settings
|
82
|
+
D13n.config.to_collecter_hash
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def default_env
|
88
|
+
ENV["#{D13n.app_prefix}_ENV"] || ENV['RACK_ENV'] || 'development'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class RequestId
|
5
|
+
X_REQUEST_ID = "X-Request-Id".freeze
|
6
|
+
|
7
|
+
def initialize(app, opts = {})
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env['HTTP_X_REQUEST_ID'] = make_request_id(env[X_REQUEST_ID]||env['HTTP_X_REQUEST_ID'])
|
13
|
+
@app.call(env).tap {|_status, headers, _body| headers[X_REQUEST_ID] = env['HTTP_X_REQUEST_ID'] }
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def make_request_id(request_id)
|
18
|
+
if request_id.nil?
|
19
|
+
internal_request_id
|
20
|
+
else
|
21
|
+
request_id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def internal_request_id
|
26
|
+
SecureRandom.hex(16)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/d13n/version.rb
ADDED