d13n 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
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,239 @@
1
+
2
+ module D13n::Configuration
3
+ class Manager
4
+ def [](key)
5
+ @cache[key]
6
+ end
7
+
8
+ def has_key?(key)
9
+ @cache.has_key?(key)
10
+ end
11
+
12
+ def keys
13
+ @cache.keys
14
+ end
15
+
16
+ def key(value)
17
+ @cache.key(value)
18
+ end
19
+
20
+ def alias_key_for(value)
21
+ alias_for(key(value))
22
+ end
23
+
24
+ def alias_for(key)
25
+ @alias_cache[key]
26
+ end
27
+
28
+ def initialize
29
+ reset_to_defaults
30
+ @callbacks = Hash.new { |hash, key| hash[key] = [] }
31
+ end
32
+
33
+ def remove_config_type(sym)
34
+ source = case sym
35
+ when :environment then @environment_source
36
+ when :server then @server_source
37
+ when :manual then @manual_source
38
+ when :yaml then @yaml_source
39
+ when :default then @default_source
40
+ end
41
+
42
+ remove_config(source)
43
+ end
44
+
45
+ def remove_config(source)
46
+ case source
47
+ when EnvironmentSource then @environment_source = nil
48
+ when ServerSource then @server_source = nil
49
+ when ManualSource then @manual_source = nil
50
+ when YamlSource then @yaml_source = nil
51
+ when DefaultSource then @default_source = nil
52
+ end
53
+
54
+ reset_cache
55
+ reset_alias
56
+ invoke_callbacks(:remove, source)
57
+ log_config(:remove, source)
58
+ end
59
+
60
+ def replace_or_add_config(source)
61
+ source.freeze
62
+
63
+ invoke_callbacks(:add, source)
64
+ case source
65
+ when EnvironmentSource then @environment_source = source
66
+ when ServerSource then @server_source = source
67
+ when ManualSource then @manual_source = source
68
+ when YamlSource then @yaml_source = source
69
+ when DefaultSource then @default_source = source
70
+ else
71
+ D13n.logger.warn("Invalid config format; config will be ignored: #{source}")
72
+ end
73
+
74
+ reset_cache
75
+ reset_alias
76
+ log_config(:add, source)
77
+ end
78
+
79
+ def source(key)
80
+ config_stack.each do |config|
81
+ if config.respond_to?(key.to_sym) || config.has_key?(key.to_sym)
82
+ return config
83
+ end
84
+ end
85
+ end
86
+
87
+ def fetch(key)
88
+ config_stack.each do |config|
89
+ next unless config
90
+ accessor = key.to_sym
91
+
92
+ if config.has_key?(accessor)
93
+ evaluated = evaluate_procs(config[accessor])
94
+ begin
95
+ return apply_transformations(accessor, evaluated)
96
+ rescue
97
+ next
98
+ end
99
+ end
100
+ end
101
+ nil
102
+ end
103
+
104
+ def apply_transformations(key, value)
105
+ if transform = transform_from_default(key)
106
+ begin
107
+ transform.call(value)
108
+ rescue => e
109
+ D13n.logger.error("Error applying transformation for #{key}, pre-transform value was: #{value}.", e)
110
+ raise e
111
+ end
112
+ else
113
+ value
114
+ end
115
+ end
116
+
117
+ def transform_from_default(key)
118
+ D13n::Configuration::DefaultSource.transform_for(key)
119
+ end
120
+
121
+ def evaluate_procs(value)
122
+ if value.respond_to?(:call)
123
+ instance_eval(&value)
124
+ else
125
+ value
126
+ end
127
+ end
128
+
129
+ # Generally only useful during initial construction and tests
130
+ def reset_to_defaults
131
+ @environment_source = EnvironmentSource.new
132
+ @server_source = nil
133
+ @manual_source = nil
134
+ @yaml_source = nil
135
+ @default_source = DefaultSource.new
136
+ reset_cache
137
+ reset_alias
138
+ end
139
+
140
+ def reset_cache
141
+ @cache = Hash.new {|hash,key| hash[key] = self.fetch(key) }
142
+ end
143
+
144
+ def reset_alias
145
+ @alias_cache = @default_source.default_alias
146
+ end
147
+
148
+ def log_config(direction, source)
149
+ D13n.logger.debug do
150
+ "Updating config (#{direction}) from #{source.class}. Results: #{flattened.inspect}"
151
+ end
152
+ end
153
+
154
+ def register_callback(key, &proc)
155
+ @callbacks[key] << proc
156
+ proc.call(@cache[key])
157
+ end
158
+
159
+ def invoke_callbacks(direction, source)
160
+ return unless source
161
+ source.keys.each do |key|
162
+
163
+ if @cache[key] != source[key]
164
+ @callbacks[key].each do |proc|
165
+ if direction == :add
166
+ proc.call(source[key])
167
+ else
168
+ proc.call(@cache[key])
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ def flattened
176
+ config_stack.reverse.inject({}) do |flat,layer|
177
+ thawed_layer = layer.to_hash.dup
178
+ thawed_layer.each do |k,v|
179
+ begin
180
+ thawed_layer[k] = instance_eval(&v) if v.respond_to?(:call)
181
+ rescue => e
182
+ D13n.logger.debug("#{e.class.name} : #{e.message} - when accessing config key #{k}")
183
+ thawed_layer[k] = nil
184
+ end
185
+ thawed_layer.delete(:config)
186
+ end
187
+ flat.merge(thawed_layer.to_hash)
188
+ end
189
+ end
190
+
191
+ def apply_mask(hash)
192
+ MASK_DEFAULTS. \
193
+ select {|_, proc| proc.call}. \
194
+ each {|key, _| hash.delete(key) }
195
+ hash
196
+ end
197
+
198
+ def to_hash
199
+ DottedHash.new(apply_mask(flattened)).to_hash
200
+ end
201
+
202
+ def to_collector_hash
203
+ DottedHash.new(apply_mask(flattened)).to_hash.delete_if do |k, v|
204
+ default = DEFAULTS[k]
205
+ if default
206
+ default[:exclude_from_reported_settings]
207
+ else
208
+ false
209
+ end
210
+ end
211
+ end
212
+
213
+ def app_name
214
+ D13n.config[:app_name]
215
+ end
216
+
217
+ private
218
+
219
+ def config_stack
220
+ stack = [@environment_source,
221
+ @server_source,
222
+ @manual_source,
223
+ @yaml_source,
224
+ @default_source]
225
+
226
+ stack.compact!
227
+ stack
228
+ end
229
+
230
+ end
231
+ end
232
+
233
+ require 'd13n/configuration/mask_defaults'
234
+ require 'd13n/configuration/dotted_hash'
235
+ require 'd13n/configuration/default_source'
236
+ require 'd13n/configuration/yaml_source'
237
+ require 'd13n/configuration/environment_source'
238
+ require 'd13n/configuration/server_source'
239
+ require 'd13n/configuration/manual_source'
@@ -0,0 +1,4 @@
1
+ module D13n::Configuration
2
+ class ManualSource < DottedHash
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module D13n
2
+ module Configuration
3
+ MASK_DEFAULTS = {
4
+ }
5
+ end
6
+ end
@@ -0,0 +1,83 @@
1
+ module D13n::Configuration
2
+ class ServerSource < DottedHash
3
+ SERVICE_PREFIXES = /^service/i
4
+ PROPERTY_PREFIXES = /^property/i
5
+ IDC_PREFIXES = /^idc/i
6
+ CLIENT_PREFIXES = /^client/i
7
+ JURISDICTION_PREFIXES = /^jurisdiction/i
8
+
9
+ attr_accessor :type_map
10
+
11
+ def initialize(connect_reply)
12
+ #filter_keys(connect_reply)
13
+ @type_map = {}
14
+
15
+ DEFAULTS.each do |config_setting, value|
16
+ self.type_map[config_setting] = value[:type]
17
+ end
18
+
19
+ super(connect_reply)
20
+ end
21
+
22
+ def set_keys_by_type()
23
+ self.keys.each do |key|
24
+ set_key_by_type(key)
25
+ end
26
+ end
27
+
28
+ def set_key_by_type(config_key)
29
+ value = self[config_key]
30
+ type = self.type_map[config_key]
31
+
32
+ if type == String
33
+ self[config_key] = value.to_s
34
+ elsif type == Integer
35
+ self[config_key] = value.to_i
36
+ elsif type == Float
37
+ self[config_key] = value.to_f
38
+ elsif type == Symbol
39
+ self[config_key] = value.to_sym
40
+ elsif type == Array
41
+ self[config_key] = value.split(/\s*,\s*/)
42
+ elsif type == D13n::Configuration::Boolean
43
+ if value =~ /false|off|no/i
44
+ self[config_key] = false
45
+ elsif value != nil
46
+ self[config_key] = true
47
+ end
48
+ else
49
+ D13n.logger.info("#{config_key} does not have a corresponding configuration setting (#{config_key} does not exist).")
50
+ self[config_key] = value
51
+ end
52
+ end
53
+
54
+ def self.build(connect_reply)
55
+ instance = new(connect_reply)
56
+ self.filter_keys(instance)
57
+ instance
58
+ end
59
+
60
+ def self.filter_keys(instance)
61
+ instance.delete_if do |key, _|
62
+ s_key = key.to_s
63
+ if s_key.match(SERVICE_PREFIXES) || s_key.match(PROPERTY_PREFIXES) || s_key.match(IDC_PREFIXES) || s_key.match(CLIENT_PREFIXES) || s_key.match(JURISDICTION_PREFIXES)
64
+ false
65
+ else
66
+ setting_spec = DEFAULTS[key.to_sym]
67
+ if setting_spec
68
+ if setting_spec[:allowed_from_server]
69
+ instance.set_key_by_type(key)
70
+ false # it's allowed, so don't delete it
71
+ else
72
+ D13n.logger.warn("Ignoring server-sent config for '#{key}' - this setting cannot be set from the server")
73
+ true # delete it
74
+ end
75
+ else
76
+ D13n.logger.debug("Ignoring unrecognized config key from server: '#{key}'")
77
+ true
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,66 @@
1
+ require 'yaml'
2
+ module D13n::Configuration
3
+ class YamlSource < DottedHash
4
+ attr_accessor :file_path, :failures
5
+
6
+ def initialize(path,env)
7
+ config = {}
8
+ @failures = []
9
+
10
+ begin
11
+ @file_path = validate_config_file(path)
12
+ return unless @file_path
13
+
14
+ D13n.logger.info("Reading configuration from #{path} (#{Dir.pwd})")
15
+ raw_file = File.read(@file_path)
16
+ erb_file = process_erb(raw_file)
17
+ config = process_yaml(erb_file, env, config, @file_path)
18
+ rescue ScriptError, StandardError => e
19
+ log_failure("Failed to read or parse configuration file at #{path}", e)
20
+ end
21
+
22
+ super(config, true)
23
+ end
24
+
25
+ protected
26
+
27
+ def validate_config_file(path)
28
+ expanded_path = File.expand_path(path)
29
+
30
+ if path.empty? || !File.exist?(expanded_path)
31
+ return
32
+ end
33
+
34
+ expanded_path
35
+ end
36
+
37
+ def process_erb(file)
38
+ begin
39
+ file.gsub!(/^\s*#.*$/, '#')
40
+
41
+ ERB.new(file).result(binding)
42
+ rescue Exception => e
43
+ log_failure("Failed ERB processing configuration file. This is typically caused by a Ruby error in <% %> templating blocks in your axle.yml file.", e)
44
+ ensure
45
+
46
+ end
47
+ end
48
+
49
+ def process_yaml(file, env, config, path)
50
+ if file
51
+ confighash = YAML.load(file)
52
+ unless confighash.key?(env)
53
+ log_failure("Config file at #{path} doesn't include a '#{env}' section!")
54
+ end
55
+ config = confighash[env] || {}
56
+ end
57
+
58
+ config
59
+ end
60
+
61
+ def log_failure(*messages)
62
+ D13n.logger.error(*messages)
63
+ @failures << messages
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,6 @@
1
+ require 'd13n/configuration/manager'
2
+
3
+ module D13n
4
+ module Configuration
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ class String
2
+ # By default, +camelize+ converts strings to UpperCamelCase.
3
+ #
4
+ # 'active_record'.camelize # => "ActiveRecord"
5
+ def camelize
6
+ string = self
7
+ string.split('_').map{ |e| e.capitalize }.join
8
+ end
9
+
10
+ def underscore
11
+ self.gsub(/::/, '/').
12
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
13
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
14
+ tr("-", "_").
15
+ downcase
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ module D13n
3
+ class Logger
4
+ module LogOnce
5
+ NUM_LOG_ONCE_KEYS = 1000
6
+
7
+ def log_once(level, key, *msgs)
8
+ return if @already_logged.include?(key)
9
+
10
+ if @already_logged.size >= NUM_LOG_ONCE_KEYS && key.kind_of?(String)
11
+ return
12
+ end
13
+
14
+ @already_logged[key] = true
15
+
16
+ self.send(level, *msgs)
17
+ end
18
+
19
+ def clear_already_logged
20
+ @already_logged = {}
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+ module D13n
3
+ class Logger
4
+ class MemoryLogger
5
+ include LogOnce
6
+ def initialize
7
+ @messages = []
8
+ end
9
+
10
+ def is_startup_logger?
11
+ true
12
+ end
13
+
14
+ attr_accessor :messages, :level, :log_formatter
15
+
16
+ def fatal(*msgs, &blk)
17
+ messages << [:fatal, msgs, blk]
18
+ end
19
+
20
+ def error(*msgs, &blk)
21
+ messages << [:error, msgs, blk]
22
+ end
23
+
24
+ def warn(*msgs, &blk)
25
+ messages << [:warn, msgs, blk]
26
+ end
27
+
28
+ def info(*msgs, &blk)
29
+ messages << [:info, msgs, blk]
30
+ end
31
+
32
+ def debug(*msgs, &blk)
33
+ messages << [:debug, msgs, blk]
34
+ end
35
+
36
+ def log_exception(level, e, backtrace_level=level)
37
+ messages << [:log_exception, [level, e, backtrace_level]]
38
+ end
39
+
40
+ def dump(logger)
41
+ messages.each do |(method, args, blk)|
42
+ logger.send(method, *args, &blk)
43
+ end
44
+ messages.clear
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ module D13n
2
+ class Logger
3
+ class NullLogger
4
+ include Singleton
5
+ def fatal(*args); end
6
+ def error(*args); end
7
+ def warn(*args); end
8
+ def info(*args); end
9
+ def debug(*args); end
10
+
11
+ def method_missing(method, *args, &blk)
12
+ nil
13
+ end
14
+ end
15
+ end
16
+ end