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,345 @@
1
+ require 'fileutils'
2
+ require 'erb'
3
+ require 'd13n/version'
4
+ module D13n::Cli
5
+ class Scaffold < Command
6
+ def self.command; "scaffold"; end
7
+
8
+ attr_accessor :application, :project, :ruby_version, :application_base
9
+
10
+ def initialize(args)
11
+ @bare = false
12
+ @application = nil
13
+ @ruby_version = '2.3.3'
14
+ super(args)
15
+ end
16
+
17
+ def run
18
+ check_options
19
+ generate_scaffold
20
+ end
21
+
22
+ def check_options
23
+ if @application.nil?
24
+ puts 'application name required'
25
+ exit 1
26
+ elsif @project.nil?
27
+ puts 'project name required'
28
+ exit 1
29
+ end
30
+ end
31
+
32
+ def generate_scaffold
33
+ @template_home = File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', '..', '..', 'templates')
34
+
35
+ unless @bare
36
+ puts "Setting up application [#{application_base}] directories..."
37
+ Dir.mkdir(@application) unless File.directory?(@application)
38
+ Dir.chdir(@application)
39
+ end
40
+
41
+ @current_home = Dir.pwd
42
+
43
+ unless @bare
44
+ application_scaffold
45
+ end
46
+
47
+ rake_scaffold
48
+
49
+ migration_scaffold
50
+
51
+ gem_scaffold
52
+
53
+ makefile_scaffold
54
+
55
+ application_yml_scaffold
56
+
57
+ docker_scaffold
58
+
59
+ docker_script_scaffold
60
+
61
+ jekinsfile_scaffold
62
+
63
+ ruby_version_scaffold
64
+
65
+ spec_scaffold
66
+
67
+ end
68
+
69
+ private
70
+
71
+ def application_base
72
+ @application_base = @application.split('_').map {|w| w.capitalize}.join
73
+ end
74
+
75
+ def application_const
76
+ @application_const ||= "#{application_base}::Service"
77
+ end
78
+
79
+ def template_erb(src, dst, src_sub_path=nil, dst_sub_path=nil)
80
+ src_file = if src_sub_path.nil?
81
+ File.join(@template_home,src)
82
+ else
83
+ File.join(@template_home, src_sub_path, src)
84
+ end
85
+ dst_file = if dst_sub_path.nil?
86
+ File.join(@current_home,dst)
87
+ else
88
+ File.join(@current_home, dst_sub_path, dst)
89
+ end
90
+ File.open(src_file) do |tfh|
91
+ erb = ERB.new(tfh.read)
92
+ File.open(dst_file, 'w') do |ofh|
93
+ ofh.print erb.result(binding)
94
+ end
95
+ end
96
+ end
97
+
98
+ def application_scaffold
99
+ puts "Generating application[#{application_base}] lib folder ..."
100
+ Dir.mkdir('lib')
101
+ application_source_path = File.join("lib","#{application}")
102
+ Dir.mkdir(application_source_path)
103
+
104
+ puts "Generating #{application_base} namespace file ..."
105
+ template_erb('application.rb.template', "#{application}.rb", 'lib', 'lib')
106
+
107
+ puts "Generating #{application_base} service file ..."
108
+ template_erb('service.rb.template','service.rb','lib',application_source_path)
109
+ template_erb('version.rb.template','version.rb','lib',application_source_path)
110
+
111
+ application_api
112
+
113
+ application_rack
114
+
115
+ application_readme
116
+
117
+ application_guard
118
+ end
119
+
120
+ def application_api
121
+ puts "Generating application[#{application_base}] api folder ..."
122
+ api_root = File.join('lib',application,'api')
123
+ Dir.mkdir(api_root)
124
+
125
+ application_source_path = File.join("lib","#{application}")
126
+ template_erb('api.rb.template','api.rb','lib', application_source_path)
127
+
128
+ api_template_root = File.join('lib', 'api')
129
+ puts api_template_root
130
+ puts "Generating #{application_base} api files ..."
131
+ template_erb('service.rb.template','service.rb',api_template_root, api_root)
132
+ template_erb('support.rb.template','support.rb',api_template_root, api_root)
133
+ template_erb('version.rb.template','version.rb',api_template_root, api_root)
134
+ end
135
+
136
+ def application_rack
137
+ puts "Generating application[#{application_base}] rack file ..."
138
+ template_erb('config.ru.template','config.ru')
139
+ end
140
+
141
+ def application_readme
142
+ puts "Generating application[#{application_base}] README.md file ..."
143
+ template_erb('README.md.template','README.md')
144
+ end
145
+
146
+ def application_guard
147
+ puts "Generating application[#{application_base}] README.md file ..."
148
+ template_erb('Guardfile.template','Guardfile')
149
+ end
150
+
151
+ def migration_scaffold
152
+ puts "Generating database migration folders ..."
153
+ @migration_root = 'db'
154
+ Dir.mkdir(@migration_root) unless File.directory?(@migration_root)
155
+
156
+ @migration_sub_dir = ['migrations', 'seeds']
157
+ @migration_sub_dir.each do |dir|
158
+ root_dir = "#{@migration_root}/#{dir}"
159
+ Dir.mkdir(root_dir) unless File.directory?(root_dir)
160
+ end
161
+
162
+ puts "Generating Rake migration file ..."
163
+
164
+ File.open(File.join(@template_home, @rake_task_root, 'migration.rake.template')) do |tfh|
165
+ erb = ERB.new(tfh.read)
166
+ File.open(File.join(@current_home, @rake_task_root, "migration.rake"), 'w') do |ofh|
167
+ ofh.print erb.result(binding)
168
+ end
169
+ end
170
+ end
171
+
172
+ def gem_scaffold
173
+ puts "Generating Gemfile ..."
174
+
175
+ File.open(File.join(@template_home, 'Gemfile.template')) do |tfh|
176
+ erb = ERB.new(tfh.read)
177
+ File.open(File.join(@current_home, "Gemfile"), 'w') do |ofh|
178
+ ofh.print erb.result(binding)
179
+ end
180
+ end
181
+ end
182
+
183
+ def makefile_scaffold
184
+ puts "Generating Makefile ..."
185
+ File.open(File.join(@template_home, 'Makefile.template')) do |tfh|
186
+ erb = ERB.new(tfh.read)
187
+ File.open(File.join(@current_home, "Makefile"), 'w') do |ofh|
188
+ ofh.print erb.result(binding)
189
+ end
190
+ end
191
+ end
192
+
193
+ def application_yml_scaffold
194
+ puts "Generating #{application}.yml ..."
195
+ File.open(File.join(@template_home, 'application.yml.template')) do |tfh|
196
+ erb = ERB.new(tfh.read)
197
+ File.open(File.join(@current_home, "#{application}.yml"), 'w') do |ofh|
198
+ ofh.print erb.result(binding)
199
+ end
200
+ end
201
+ end
202
+
203
+ def docker_scaffold
204
+ puts "Generating docker folder ..."
205
+ @docker_root = 'docker'
206
+ Dir.mkdir(@docker_root) unless File.directory?(@docker_root)
207
+
208
+ @docker_development_files = ['docker-compose.yml','Dockerfile.cache','Dockerfile']
209
+ @docker_release_files = ['docker-compose.yml', 'Dockerfile']
210
+
211
+ docker_stage(@docker_root, 'development', @docker_development_files)
212
+ docker_stage(@docker_root, 'release', @docker_release_files)
213
+ end
214
+
215
+ def docker_stage(root, stage, files)
216
+ puts "Generating docker #{stage} folder ..."
217
+ root_dir = "#{root}/#{stage}"
218
+ Dir.mkdir(root_dir) unless File.directory?(root_dir)
219
+
220
+ puts "Generating #{stage} docker files ..."
221
+ stage_dir = "#{root}/#{stage}"
222
+ files.each do |file|
223
+ File.open(File.join(@template_home, "docker", "#{file}.#{stage}")) do |tfh|
224
+ erb = ERB.new(tfh.read)
225
+ File.open(File.join(@current_home, stage_dir, file), 'w') do |ofh|
226
+ ofh.print erb.result(binding)
227
+ end
228
+ end
229
+ end
230
+ end
231
+
232
+ def docker_script_scaffold
233
+ @docker_script_root = 'scripts'
234
+ Dir.mkdir(@docker_script_root) unless File.directory?(@docker_script_root)
235
+
236
+ puts "Generating docker scripts ..."
237
+ File.open(File.join(@template_home, "#{@docker_script_root}/", "test.sh.template")) do |tfh|
238
+ erb = ERB.new(tfh.read)
239
+ File.open(File.join(@current_home, "#{@docker_script_root}/", "test.sh"), 'w') do |ofh|
240
+ ofh.print erb.result(binding)
241
+ end
242
+
243
+ FileUtils.chmod 0755,File.join(@current_home, "#{@docker_script_root}/", "test.sh")
244
+ end
245
+ end
246
+
247
+ def jekinsfile_scaffold
248
+ puts "Generating Jekinsfile ..."
249
+
250
+ File.open(File.join(@template_home, "Jenkinsfile.template")) do |tfh|
251
+ erb = ERB.new(tfh.read)
252
+ File.open(File.join(@current_home, "Jenkinsfile"), 'w') do |ofh|
253
+ ofh.print erb.result(binding)
254
+ end
255
+ end
256
+ end
257
+
258
+ def ruby_version_scaffold
259
+ puts "Generating Ruby Version file ..."
260
+
261
+ File.open(File.join(@template_home, ".ruby-version.template")) do |tfh|
262
+ erb = ERB.new(tfh.read)
263
+ File.open(File.join(@current_home, ".ruby-version"), 'w') do |ofh|
264
+ ofh.print erb.result(binding)
265
+ end
266
+ end
267
+ end
268
+
269
+ def spec_scaffold
270
+ puts "Generating RSpec configuraion file ..."
271
+
272
+ File.open(File.join(@template_home, ".rspec.template")) do |tfh|
273
+ erb = ERB.new(tfh.read)
274
+ File.open(File.join(@current_home, ".rspec"), 'w') do |ofh|
275
+ ofh.print erb.result(binding)
276
+ end
277
+ end
278
+
279
+ puts "Generating Spec folders ..."
280
+
281
+ @spec_root = 'spec'
282
+
283
+ Dir.mkdir(@spec_root) unless File.directory?(@spec_root)
284
+
285
+ ['unit', 'functional', 'factories'].each do |folder|
286
+ spec_sub_dir = File.join(@spec_root, folder)
287
+ Dir.mkdir(spec_sub_dir) unless File.directory?(spec_sub_dir)
288
+ end
289
+
290
+ puts "Generating Rspec Helper file ..."
291
+
292
+ File.open(File.join(@template_home, "spec", "spec_helper.rb.template")) do |tfh|
293
+ erb = ERB.new(tfh.read)
294
+ File.open(File.join(@current_home, "spec", "spec_helper.rb"), 'w') do |ofh|
295
+ ofh.print erb.result(binding)
296
+ end
297
+ end
298
+
299
+ puts 'Generating Rspec rake task file ...'
300
+
301
+ File.open(File.join(@template_home, @rake_task_root, "spec.rake.template")) do |tfh|
302
+ erb = ERB.new(tfh.read)
303
+ File.open(File.join(@current_home, @rake_task_root, "spec.rake"), 'w') do |ofh|
304
+ ofh.print erb.result(binding)
305
+ end
306
+ end
307
+ end
308
+
309
+ def rake_scaffold
310
+ puts "Generating Rake file ..."
311
+
312
+ File.open(File.join(@template_home, "Rakefile.template")) do |tfh|
313
+ erb = ERB.new(tfh.read)
314
+ File.open(File.join(@current_home, "Rakefile"), 'w') do |ofh|
315
+ ofh.print erb.result(binding)
316
+ end
317
+ end
318
+
319
+ puts "Generating Rake Task folder ..."
320
+
321
+ @rake_task_root = 'tasks'
322
+
323
+ Dir.mkdir(@rake_task_root) unless File.directory?(@rake_task_root)
324
+ end
325
+
326
+ def options
327
+ OptionParser.new %Q{Usage: #{$0} #{self.class.command} [OPTIONS] ["description"] }, 40 do |opts|
328
+ opts.separator ''
329
+ opts.separator 'Specific options:'
330
+
331
+ opts.on('-a APP', '--app','Specify an application to scaffold') do |app|
332
+ @application = app.downcase
333
+ end
334
+
335
+ opts.on('-p PROJECT', '--project','Specify project of application to scaffold') do |project|
336
+ @project = project.downcase
337
+ end
338
+
339
+ opts.on('-b', '--bare', 'Scaffold a bare folder') do |bare|
340
+ @bare = true
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end
@@ -0,0 +1,200 @@
1
+ require 'forwardable'
2
+
3
+ module D13n::Configuration
4
+ def self.value_of(key)
5
+ Proc.new {
6
+ D13n.config[key]
7
+ }
8
+ end
9
+
10
+ class Boolean
11
+ def self.===(o)
12
+ TrueClass === o or FalseClass === o
13
+ end
14
+ end
15
+
16
+ class DefaultSource
17
+ attr_reader :defaults, :alias
18
+
19
+ extend Forwardable
20
+ def_delegators :@defaults, :has_key?, :each, :merge, :delete, :keys, :[], :to_hash
21
+
22
+
23
+ def initialize
24
+ frozen_default
25
+ @defaults = default_values
26
+ @alias = default_alias
27
+ end
28
+
29
+ def frozen_default
30
+ D13n::Configuration::DEFAULTS.freeze
31
+ end
32
+
33
+ def default_values
34
+ result = {}
35
+ D13n::Configuration::DEFAULTS.each do |key, value|
36
+ result[key] = value[:default]
37
+ end
38
+ result
39
+ end
40
+
41
+ def default_alias
42
+ result = {}
43
+ D13n::Configuration::DEFAULTS.each do |key,value|
44
+ result[key] = (value[:alias] || key).to_s
45
+ end
46
+ result
47
+ end
48
+
49
+ def self.defaults
50
+ D13n::Configuration::DEFAULTS
51
+ end
52
+
53
+ def self.defaults=(default_config)
54
+ D13n::Configuration::DEFAULTS.merge!(default_config)
55
+ end
56
+
57
+ def self.config_search_paths
58
+ Proc.new {
59
+ paths = [
60
+ File.join("config", "#{D13n.app_name}.yml"),
61
+ File.join("#{D13n.app_name}.yml")
62
+ ]
63
+
64
+ if D13n.service.instance.root
65
+ paths << File.join(D13n.service.instance.root, "config", "#{D13n.app_name}.yml")
66
+ paths << File.join(D13n.service.instance.root, "#{D13n.app_name}.yml")
67
+ end
68
+
69
+ if ENV["HOME"]
70
+ paths << File.join(ENV["HOME"], ".#{D13n.app_name}", "#{D13n.app_name}.yml")
71
+ paths << File.join(ENV["HOME"], "#{D13n.app_name}.yml")
72
+ end
73
+ paths
74
+ }
75
+ end
76
+
77
+ def self.config_path
78
+ Proc.new {
79
+ found_path = D13n.config[:config_search_paths].detect do |file|
80
+ File.expand_path(file) if File.exist? file
81
+ end
82
+ found_path || ""
83
+ }
84
+ end
85
+
86
+ def self.transform_for(key)
87
+ default_settings = D13n::Configuration::DEFAULTS[key]
88
+ default_settings[:transform] if default_settings
89
+ end
90
+
91
+ def self.convert_to_list(value)
92
+ case value
93
+ when String
94
+ value.split(/\s*,\s*/)
95
+ when Array
96
+ value
97
+ else
98
+ raise ArgumentError.new("Config value '#{value}' couldn't be turned into a list.")
99
+ end
100
+ end
101
+ end
102
+
103
+ DEFAULTS = {
104
+ :app_name => {
105
+ :default => Proc.new{"#{D13n.app_name}"},
106
+ :public => true,
107
+ :type => String,
108
+ :allowed_from_server => false,
109
+ :description => 'Define Application Name'
110
+ },
111
+ :port => {
112
+ :default => 3000,
113
+ :public => true,
114
+ :type => Integer,
115
+ :description => 'Define service port'
116
+ },
117
+ :host => {
118
+ :default => '0.0.0.0',
119
+ :public => true,
120
+ :type => String,
121
+ :description => 'Define service host'
122
+ },
123
+ #
124
+ # Log config
125
+ #
126
+ :log_level => {
127
+ :default => 'info',
128
+ :public => true,
129
+ :type => String,
130
+ :description => 'Sets the level of detail of log messages. Possible log levels, in increasing verbosity, are: <code>error</code>, <code>warn</code>, <code>info</code> or <code>debug</code>.'
131
+ },
132
+ :log_file_path => {
133
+ :default => 'stdout',
134
+ :public => true,
135
+ :type => String,
136
+ :description => 'Defines a path to the log file, excluding the filename.'
137
+ },
138
+ :log_file_name => {
139
+ :default => Proc.new{"#{D13n.app_name}.log"},
140
+ :public => true,
141
+ :type => String,
142
+ :description => 'Defines a name for the log file.'
143
+ },
144
+ #
145
+ # YAML file Config
146
+ #
147
+ :config_path => {
148
+ :default => DefaultSource.config_path,
149
+ :public => true,
150
+ :type => String,
151
+ :description => 'Path to <b>application.yml</b>. If undefined, the agent checks the following directories (in order): <b>config/application.yml</b>, <b>application.yml</b>, <b>$HOME/.d13n/application.yml</b> and <b>$HOME/application.yml</b>.'
152
+ },
153
+ :config_search_paths => {
154
+ :default => DefaultSource.config_search_paths,
155
+ :public => false,
156
+ :type => Array,
157
+ :allowed_from_server => false,
158
+ :description => "An array of candidate locations for the service\'s configuration file."
159
+ },
160
+ :'metric.channel.type' => {
161
+ :default => 'logger',
162
+ :public => true,
163
+ :type => String,
164
+ :allowed_from_server => true,
165
+ :description => 'Metric Channel Type.'
166
+ },
167
+ :'metric.app.http.in.apdex_t' => {
168
+ :default => 300,
169
+ :public => true,
170
+ :type => Integer,
171
+ :allowed_from_server => true,
172
+ :description => 'Metric HTTP IN Apdex Config Value.'
173
+ },
174
+ :'metric.app.http.in.tracable' => {
175
+ :default => true,
176
+ :public => true,
177
+ :type => D13n::Configuration::Boolean,
178
+ :description => 'Metric HTTP IN trace enable switch'
179
+ },
180
+ :'metric.app.http.in.sinatra.enable' => {
181
+ :default => true,
182
+ :public => true,
183
+ :type => D13n::Configuration::Boolean,
184
+ :description => 'enable http in trace for sinatra'
185
+ },
186
+ :'metric.app.http.in.sinatra.auto_middleware.enable' => {
187
+ :default => true,
188
+ :public => true,
189
+ :type => D13n::Configuration::Boolean,
190
+ :description => 'enable sinatra auto load middleware'
191
+ },
192
+ :'metric.app.http.out.tracable' => {
193
+ :default => true,
194
+ :public => true,
195
+ :type => D13n::Configuration::Boolean,
196
+ :allowed_from_server => true,
197
+ :description => "Metric HTTP OUT trace enable switch"
198
+ }
199
+ }
200
+ end
@@ -0,0 +1,39 @@
1
+ module D13n::Configuration
2
+ class DottedHash < ::Hash
3
+ def initialize(hash, keep_nesting=false)
4
+ self.merge!(hash) if keep_nesting
5
+
6
+ self.merge!(dot_flattened(hash))
7
+ DottedHash.symbolize(self)
8
+ end
9
+
10
+ def inspect
11
+ "#<#{self.class.name}:#{object_id} #{super}>"
12
+ end
13
+
14
+ def to_hash
15
+ {}.replace(self)
16
+ end
17
+
18
+ def self.symbolize(hash)
19
+ hash.keys.each do |key|
20
+ hash[key.to_sym] = hash.delete(key)
21
+ end
22
+ end
23
+
24
+ protected
25
+ # turns {'a' => {'b' => 'c'}} into {'a.b' => 'c'}
26
+ def dot_flattened(nested_hash, names=[], result={})
27
+ nested_hash.each do |key, val|
28
+ next if val == nil
29
+ if val.respond_to?(:has_key?)
30
+ dot_flattened(val, names + [key], result)
31
+ else
32
+ result[(names + [key]).join('.')] = val
33
+ end
34
+ end
35
+ result
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,89 @@
1
+ module D13n::Configuration
2
+ class EnvironmentSource < DottedHash
3
+ SUPPORTED_PREFIXES = Proc.new {/^#{D13n.app_name}_/i}
4
+ SPECIAL_CASE_KEYS = [
5
+ "#{D13n.app_prefix}_LOG" # read by set_log_file
6
+ ]
7
+
8
+ attr_accessor :type_map
9
+
10
+ def initialize
11
+ set_log_file
12
+ set_config_file
13
+
14
+ @type_map = {}
15
+
16
+ DEFAULTS.each do |config_setting, value|
17
+ self.type_map[config_setting] = value[:type]
18
+ end
19
+
20
+ set_values_from_app_environment_variables
21
+ end
22
+
23
+ def set_log_file
24
+ env_log = "#{D13n.app_prefix}_LOG"
25
+ if ENV[env_log]
26
+ if ENV[env_log].upcase == 'STDOUT'
27
+ self[:log_file_path] = self[:log_file_name] = 'STDOUT'
28
+ else
29
+ self[:log_file_path] = File.dirname(ENV[env_log])
30
+ self[:log_file_name] = File.basename(ENV[env_log])
31
+ end
32
+ end
33
+ end
34
+
35
+ def set_config_file
36
+ env_config = "#{D13n.app_prefix}_CONFIG"
37
+ self[:config_path] = ENV[env_config] if ENV[env_config]
38
+ end
39
+
40
+ def set_values_from_app_environment_variables
41
+ app_env_var_keys = collect_app_environment_variable_keys
42
+
43
+ app_env_var_keys.each do |key|
44
+ next if SPECIAL_CASE_KEYS.include?(key.upcase)
45
+ set_value_from_app_environment_variable(key)
46
+ end
47
+ end
48
+
49
+ def set_value_from_app_environment_variable(key)
50
+ config_key = convert_environment_key_to_config_key(key)
51
+ set_key_by_type(config_key, key)
52
+ end
53
+
54
+ def set_key_by_type(config_key, environment_key)
55
+ value = ENV[environment_key]
56
+ type = self.type_map[config_key]
57
+
58
+ if type == String
59
+ self[config_key] = value
60
+ elsif type == Integer
61
+ self[config_key] = value.to_i
62
+ elsif type == Float
63
+ self[config_key] = value.to_f
64
+ elsif type == Symbol
65
+ self[config_key] = value.to_sym
66
+ elsif type == Array
67
+ self[config_key] = value.split(/\s*,\s*/)
68
+ elsif type == D13n::Configuration::Boolean
69
+ if value =~ /false|off|no/i
70
+ self[config_key] = false
71
+ elsif value != nil
72
+ self[config_key] = true
73
+ end
74
+ else
75
+ D13n.logger.info("#{environment_key} does not have a corresponding configuration setting (#{config_key} does not exist).")
76
+ self[config_key] = value
77
+ end
78
+ end
79
+
80
+ def convert_environment_key_to_config_key(key)
81
+ stripped_key = key.gsub(SUPPORTED_PREFIXES.call, '').downcase.to_sym
82
+ end
83
+
84
+
85
+ def collect_app_environment_variable_keys
86
+ ENV.keys.select { |key| key.match(SUPPORTED_PREFIXES.call) }
87
+ end
88
+ end
89
+ end