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.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.rspec +6 -0
  4. data/.rubocop.yml +5 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +22 -0
  7. data/Gemfile.lock +151 -0
  8. data/Guardfile +63 -0
  9. data/README.md +200 -0
  10. data/bin/d13n +11 -0
  11. data/d13n.gemspec +34 -0
  12. data/lib/d13n/application/class_methods.rb +56 -0
  13. data/lib/d13n/application.rb +3 -0
  14. data/lib/d13n/cli/command.rb +76 -0
  15. data/lib/d13n/cli/commands/scaffold.rb +345 -0
  16. data/lib/d13n/configuration/default_source.rb +200 -0
  17. data/lib/d13n/configuration/dotted_hash.rb +39 -0
  18. data/lib/d13n/configuration/environment_source.rb +89 -0
  19. data/lib/d13n/configuration/manager.rb +239 -0
  20. data/lib/d13n/configuration/manual_source.rb +4 -0
  21. data/lib/d13n/configuration/mask_defaults.rb +6 -0
  22. data/lib/d13n/configuration/server_source.rb +83 -0
  23. data/lib/d13n/configuration/yaml_source.rb +66 -0
  24. data/lib/d13n/configuration.rb +6 -0
  25. data/lib/d13n/ext/string.rb +17 -0
  26. data/lib/d13n/logger/log_once.rb +24 -0
  27. data/lib/d13n/logger/memory_logger.rb +48 -0
  28. data/lib/d13n/logger/null_logger.rb +16 -0
  29. data/lib/d13n/logger.rb +213 -0
  30. data/lib/d13n/metric/conductor.rb +123 -0
  31. data/lib/d13n/metric/helper.rb +62 -0
  32. data/lib/d13n/metric/http_clients/http_helper.rb +15 -0
  33. data/lib/d13n/metric/http_clients/net_http_wrappers.rb +54 -0
  34. data/lib/d13n/metric/http_clients.rb +4 -0
  35. data/lib/d13n/metric/instrumentation/app_exception.rb +70 -0
  36. data/lib/d13n/metric/instrumentation/controller_instrumentation.rb +91 -0
  37. data/lib/d13n/metric/instrumentation/em-websocket.rb +71 -0
  38. data/lib/d13n/metric/instrumentation/exception.rb +65 -0
  39. data/lib/d13n/metric/instrumentation/middleware_tracing.rb +82 -0
  40. data/lib/d13n/metric/instrumentation/net.rb +36 -0
  41. data/lib/d13n/metric/instrumentation/sinatra/stream_namer.rb +35 -0
  42. data/lib/d13n/metric/instrumentation/sinatra.rb +165 -0
  43. data/lib/d13n/metric/instrumentation/websocket_instrumentation.rb +42 -0
  44. data/lib/d13n/metric/instrumentation.rb +41 -0
  45. data/lib/d13n/metric/manager.rb +106 -0
  46. data/lib/d13n/metric/metrics/app_database_metric.rb +4 -0
  47. data/lib/d13n/metric/metrics/app_http_metric.rb +229 -0
  48. data/lib/d13n/metric/metrics/app_state_metric.rb +103 -0
  49. data/lib/d13n/metric/metrics/base.rb +14 -0
  50. data/lib/d13n/metric/metrics/biz_state_metric.rb +4 -0
  51. data/lib/d13n/metric/metrics.rb +6 -0
  52. data/lib/d13n/metric/stream/span_tracer_helpers.rb +72 -0
  53. data/lib/d13n/metric/stream/stream_tracer_helpers.rb +141 -0
  54. data/lib/d13n/metric/stream/traced_span_stack.rb +73 -0
  55. data/lib/d13n/metric/stream.rb +322 -0
  56. data/lib/d13n/metric/stream_state.rb +68 -0
  57. data/lib/d13n/metric.rb +11 -0
  58. data/lib/d13n/rack/d13n_middleware.rb +21 -0
  59. data/lib/d13n/rack/metric_middleware.rb +18 -0
  60. data/lib/d13n/service/background_job/sinatra.rb +24 -0
  61. data/lib/d13n/service/background_job.rb +1 -0
  62. data/lib/d13n/service/start.rb +75 -0
  63. data/lib/d13n/service.rb +91 -0
  64. data/lib/d13n/support/request_id.rb +29 -0
  65. data/lib/d13n/version.rb +14 -0
  66. data/lib/d13n.rb +92 -0
  67. data/templates/.rspec.template +6 -0
  68. data/templates/.ruby-version.template +1 -0
  69. data/templates/Gemfile.template +16 -0
  70. data/templates/Guardfile.template +64 -0
  71. data/templates/Jenkinsfile.template +85 -0
  72. data/templates/Makefile.template +178 -0
  73. data/templates/README.md.template +1 -0
  74. data/templates/Rakefile.template +6 -0
  75. data/templates/application.yml.template +14 -0
  76. data/templates/config.ru.template +4 -0
  77. data/templates/docker/.dockerignore.template +5 -0
  78. data/templates/docker/Dockerfile.application.development +15 -0
  79. data/templates/docker/Dockerfile.cache.development +18 -0
  80. data/templates/docker/Dockerfile.development +27 -0
  81. data/templates/docker/Dockerfile.release +16 -0
  82. data/templates/docker/docker-compose.yml.development +53 -0
  83. data/templates/docker/docker-compose.yml.release +37 -0
  84. data/templates/lib/api/service.rb.template +10 -0
  85. data/templates/lib/api/support.rb.template +38 -0
  86. data/templates/lib/api/version.rb.template +3 -0
  87. data/templates/lib/api.rb.template +4 -0
  88. data/templates/lib/application.rb.template +49 -0
  89. data/templates/lib/service.rb.template +4 -0
  90. data/templates/lib/version.rb.template +3 -0
  91. data/templates/scripts/test.sh.template +7 -0
  92. data/templates/spec/spec_helper.rb.template +56 -0
  93. data/templates/tasks/migration.rake.template +11 -0
  94. data/templates/tasks/spec.rake.template +21 -0
  95. 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
@@ -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
@@ -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
@@ -0,0 +1,14 @@
1
+ module D13n
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 5
5
+ TINY = 2
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+
9
+ CODENAME = 'd13n'
10
+ end
11
+
12
+ NAME = 'd13n'.freeze
13
+ RELEASE = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
14
+ end