prefab-cloud-ruby 0.24.5 → 0.24.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/VERSION +1 -1
  4. data/compile_protos.sh +7 -0
  5. data/lib/prefab/client.rb +17 -4
  6. data/lib/prefab/config_client.rb +8 -9
  7. data/lib/prefab/config_value_unwrapper.rb +20 -9
  8. data/lib/prefab/context.rb +39 -7
  9. data/lib/prefab/context_shape_aggregator.rb +1 -1
  10. data/lib/prefab/criteria_evaluator.rb +24 -16
  11. data/lib/prefab/evaluated_keys_aggregator.rb +1 -1
  12. data/lib/prefab/evaluation.rb +48 -0
  13. data/lib/prefab/evaluation_summary_aggregator.rb +85 -0
  14. data/lib/prefab/example_contexts_aggregator.rb +76 -0
  15. data/lib/prefab/exponential_backoff.rb +5 -0
  16. data/lib/prefab/log_path_aggregator.rb +1 -1
  17. data/lib/prefab/logger_client.rb +12 -13
  18. data/lib/prefab/options.rb +27 -14
  19. data/lib/prefab/periodic_sync.rb +30 -13
  20. data/lib/prefab/rate_limit_cache.rb +41 -0
  21. data/lib/prefab/resolved_config_presenter.rb +2 -4
  22. data/lib/prefab/weighted_value_resolver.rb +1 -1
  23. data/lib/prefab-cloud-ruby.rb +5 -2
  24. data/lib/prefab_pb.rb +11 -1
  25. data/prefab-cloud-ruby.gemspec +14 -5
  26. data/test/support/common_helpers.rb +105 -0
  27. data/test/support/mock_base_client.rb +44 -0
  28. data/test/support/mock_config_client.rb +19 -0
  29. data/test/support/mock_config_loader.rb +1 -0
  30. data/test/test_client.rb +257 -2
  31. data/test/test_config_resolver.rb +25 -24
  32. data/test/test_config_value_unwrapper.rb +22 -32
  33. data/test/test_context_shape_aggregator.rb +0 -1
  34. data/test/test_criteria_evaluator.rb +179 -133
  35. data/test/test_evaluation_summary_aggregator.rb +162 -0
  36. data/test/test_example_contexts_aggregator.rb +238 -0
  37. data/test/test_helper.rb +5 -131
  38. data/test/test_local_config_parser.rb +2 -2
  39. data/test/test_logger.rb +5 -5
  40. data/test/test_options.rb +8 -0
  41. data/test/test_rate_limit_cache.rb +44 -0
  42. data/test/test_weighted_value_resolver.rb +13 -7
  43. metadata +13 -4
  44. data/lib/prefab/evaluated_configs_aggregator.rb +0 -60
  45. data/test/test_evaluated_configs_aggregator.rb +0 -254
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf743673dab06e2777321f7fb867417478a383864dd6b982860abbb21375450b
4
- data.tar.gz: 47a0ba475095d9e773fafc684efc43bc4ac05bc9ec318b70ee321cf2c6b59428
3
+ metadata.gz: 36d1b27d1c03aef56882735b73835b65b508b5eef821f65e89ab5ba77f54a8ab
4
+ data.tar.gz: 00a336ac664ab495ce1c5fff4b5ab6972169a095087887958c3a0881016ba273
5
5
  SHA512:
6
- metadata.gz: 5ce8f48e9c4584a34deead09528e1b90cd33a3e80994433d999abb32ccfd31eae7883eedf18b99d8351c55cf00e1e1dc7ef6f0b5a7d45819b300f573ff068533
7
- data.tar.gz: 416c9f5271b62cef7469db992dde3238c982d15f442f22d3c273c5dfe07935caa1777c26684c98b5ed3c92a67cb41bb10fb9b00d188d4cecaa34507b425fdbb4
6
+ metadata.gz: b0dc48a30fd50f53e9709e138afd408bfc2e91e6badb473c1d141db56c7cdfa507aef81db0f06674b8d640dec2a7ac147654def0cdd7e7bcebdd3b0eb2a79854
7
+ data.tar.gz: a3bd2f91776a25d646f1ab28d54d395bd24283e16dbca2f0bc7a1d1f77c9bb063488e9f62e00030a8acc84b2ecb8b07791bf84c1893e091f40edbb75e55870ca
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.24.6 - 2023-07-31
4
+
5
+ - Logger Client compatibility (#129)
6
+ - Replace EvaluatedConfigs with ExampleContexts (#128)
7
+ - Add ConfigEvaluationSummaries (opt-in for now) (#123)
8
+
3
9
  ## 0.24.5 - 2023-07-10
4
10
 
5
11
  - Report Client Version (#121)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.24.5
1
+ 0.24.6
data/compile_protos.sh CHANGED
@@ -1,7 +1,14 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
+ set -e
4
+
3
5
  gem install grpc-tools
4
6
 
7
+ (
8
+ cd ../prefab-cloud
9
+ git pull --rebase
10
+ )
11
+
5
12
  grpc_tools_ruby_protoc -I ../prefab-cloud/ --ruby_out=lib --grpc_out=lib prefab.proto
6
13
 
7
14
  gsed -i 's/^module Prefab$/module PrefabProto/g' lib/prefab_pb.rb
data/lib/prefab/client.rb CHANGED
@@ -80,11 +80,24 @@ module Prefab
80
80
  sync_interval: @options.collect_sync_interval)
81
81
  end
82
82
 
83
- def evaluated_configs_aggregator
84
- return nil if @options.collect_max_evaluations <= 0
83
+ def example_contexts_aggregator
84
+ return nil if @options.collect_max_example_contexts <= 0
85
85
 
86
- @evaluated_configs_aggregator ||= EvaluatedConfigsAggregator.new(client: self, max_configs: @options.collect_max_evaluations,
87
- sync_interval: @options.collect_sync_interval)
86
+ @example_contexts_aggregator ||= ExampleContextsAggregator.new(
87
+ client: self,
88
+ max_contexts: @options.collect_max_example_contexts,
89
+ sync_interval: @options.collect_sync_interval
90
+ )
91
+ end
92
+
93
+ def evaluation_summary_aggregator
94
+ return nil if @options.collect_max_evaluation_summaries <= 0
95
+
96
+ @evaluation_summary_aggregator ||= EvaluationSummaryAggregator.new(
97
+ client: self,
98
+ max_keys: @options.collect_max_evaluation_summaries,
99
+ sync_interval: @options.collect_sync_interval
100
+ )
88
101
  end
89
102
 
90
103
  def set_rails_loggers
@@ -58,18 +58,17 @@ module Prefab
58
58
  def get(key, default = NO_DEFAULT_PROVIDED, properties = NO_DEFAULT_PROVIDED)
59
59
  context = @config_resolver.make_context(properties)
60
60
 
61
- value = _get(key, context)
61
+ if properties != NO_DEFAULT_PROVIDED && @base_client.example_contexts_aggregator
62
+ @base_client.example_contexts_aggregator.record(context)
63
+ end
64
+
65
+ evaluation = _get(key, context)
62
66
 
63
67
  @base_client.context_shape_aggregator&.push(context)
64
68
  @base_client.evaluated_keys_aggregator&.push(key)
65
69
 
66
- if value
67
- # NOTE: we don't &.push here because some of the args aren't already available
68
- if @base_client.evaluated_configs_aggregator && key != Prefab::LoggerClient::BASE_KEY && !key.start_with?(LOGGING_KEY_PREFIX)
69
- @base_client.evaluated_configs_aggregator.push([raw(key), value, context])
70
- end
71
-
72
- Prefab::ConfigValueUnwrapper.unwrap(value, key, context)
70
+ if evaluation
71
+ evaluation.report_and_return(@base_client.evaluation_summary_aggregator)
73
72
  else
74
73
  handle_default(key, default)
75
74
  end
@@ -183,7 +182,7 @@ module Prefab
183
182
 
184
183
  @base_client.log_internal ::Logger::INFO, "Unlocked Config via #{source}"
185
184
  @initialization_lock.release_write_lock
186
- @base_client.log.set_config_client(self)
185
+ @base_client.log.config_client = self
187
186
  @base_client.log_internal ::Logger::INFO, to_s
188
187
  end
189
188
 
@@ -2,24 +2,35 @@
2
2
 
3
3
  module Prefab
4
4
  class ConfigValueUnwrapper
5
- def self.unwrap(config_value, config_key, context)
6
- return nil unless config_value
5
+ attr_reader :value, :weighted_value_index
7
6
 
8
- case config_value.type
7
+ def initialize(value, weighted_value_index = nil)
8
+ @value = value
9
+ @weighted_value_index = weighted_value_index
10
+ end
11
+
12
+ def unwrap
13
+ case value.type
9
14
  when :int, :string, :double, :bool, :log_level
10
- config_value.public_send(config_value.type)
15
+ value.public_send(value.type)
11
16
  when :string_list
12
- config_value.string_list.values
13
- when :weighted_values
14
- value = Prefab::WeightedValueResolver.new(
17
+ value.string_list.values
18
+ else
19
+ raise "Unknown type: #{config_value.type}"
20
+ end
21
+ end
22
+
23
+ def self.deepest_value(config_value, config_key, context)
24
+ if config_value&.type == :weighted_values
25
+ value, index = Prefab::WeightedValueResolver.new(
15
26
  config_value.weighted_values.weighted_values,
16
27
  config_key,
17
28
  context.get(config_value.weighted_values.hash_by_property_name)
18
29
  ).resolve
19
30
 
20
- unwrap(value.value, config_key, context)
31
+ new(deepest_value(value.value, config_key, context).value, index)
21
32
  else
22
- raise "Unknown type: #{config_value.type}"
33
+ new(config_value)
23
34
  end
24
35
  end
25
36
  end
@@ -25,10 +25,23 @@ module Prefab
25
25
  def to_h
26
26
  @hash
27
27
  end
28
+
29
+ def key
30
+ "#{@name}:#{get('key')}"
31
+ end
32
+
33
+ def to_proto
34
+ PrefabProto::Context.new(
35
+ type: name,
36
+ values: to_h.transform_values do |value|
37
+ ConfigValueWrapper.wrap(value)
38
+ end
39
+ )
40
+ end
28
41
  end
29
42
 
30
43
  THREAD_KEY = :prefab_context
31
- attr_reader :contexts
44
+ attr_reader :contexts, :seen_at
32
45
 
33
46
  class << self
34
47
  def current=(context)
@@ -58,6 +71,7 @@ module Prefab
58
71
 
59
72
  def initialize(context = {})
60
73
  @contexts = {}
74
+ @seen_at = Time.now.utc.to_i
61
75
 
62
76
  if context.is_a?(NamedContext)
63
77
  @contexts[context.name] = context
@@ -113,15 +127,33 @@ module Prefab
113
127
 
114
128
  PrefabProto::ContextSet.new(
115
129
  contexts: contexts.map do |name, context|
116
- PrefabProto::Context.new(
117
- type: name,
118
- values: context.to_h.transform_values do |value|
119
- ConfigValueWrapper.wrap(value)
120
- end
121
- )
130
+ context.to_proto
122
131
  end.concat([PrefabProto::Context.new(type: 'prefab',
123
132
  values: prefab_context)])
124
133
  )
125
134
  end
135
+
136
+ def slim_proto
137
+ PrefabProto::ContextSet.new(
138
+ contexts: contexts.map do |_, context|
139
+ context.to_proto
140
+ end
141
+ )
142
+ end
143
+
144
+ def grouped_key
145
+ contexts.map do |_, context|
146
+ context.key
147
+ end.sort.join('|')
148
+ end
149
+
150
+ include Comparable
151
+ def <=>(other)
152
+ if other.is_a?(Prefab::Context)
153
+ to_h <=> other.to_h
154
+ else
155
+ super
156
+ end
157
+ end
126
158
  end
127
159
  end
@@ -42,7 +42,7 @@ module Prefab
42
42
  private
43
43
 
44
44
  def flush(to_ship, _)
45
- @pool.post do
45
+ pool.post do
46
46
  log_internal "Uploading context shapes for #{to_ship.values.size}"
47
47
 
48
48
  shapes = PrefabProto::ContextShapes.new(
@@ -4,6 +4,8 @@
4
4
  # We're intentionally keeping the UPCASED method names to match the protobuf
5
5
  # and avoid wasting CPU cycles lowercasing things
6
6
  module Prefab
7
+ # This class evaluates a config's criteria. `evaluate` returns the value of
8
+ # the first match based on the provided properties.
7
9
  class CriteriaEvaluator
8
10
  NAMESPACE_KEY = 'NAMESPACE'
9
11
  NO_MATCHING_ROWS = [].freeze
@@ -17,15 +19,8 @@ module Prefab
17
19
  end
18
20
 
19
21
  def evaluate(properties)
20
- matching_environment_row_values.each do |conditional_value|
21
- return conditional_value.value if all_criteria_match?(conditional_value, properties)
22
- end
23
-
24
- default_row_values.each do |conditional_value|
25
- return conditional_value.value if all_criteria_match?(conditional_value, properties)
26
- end
27
-
28
- nil
22
+ evaluate_for_env(@project_env_id, properties) ||
23
+ evaluate_for_env(0, properties)
29
24
  end
30
25
 
31
26
  def all_criteria_match?(conditional_value, props)
@@ -83,12 +78,24 @@ module Prefab
83
78
 
84
79
  private
85
80
 
86
- def matching_environment_row_values
87
- @config.rows.find { |row| row.project_env_id == @project_env_id }&.values || NO_MATCHING_ROWS
88
- end
81
+ def evaluate_for_env(env_id, properties)
82
+ @config.rows.each_with_index do |row, index|
83
+ next unless row.project_env_id == env_id
84
+
85
+ row.values.each_with_index do |conditional_value, value_index|
86
+ next unless all_criteria_match?(conditional_value, properties)
87
+
88
+ return Prefab::Evaluation.new(
89
+ config: @config,
90
+ value: conditional_value.value,
91
+ value_index: value_index,
92
+ config_row_index: index,
93
+ context: properties
94
+ )
95
+ end
96
+ end
89
97
 
90
- def default_row_values
91
- @config.rows.find { |row| row.project_env_id != @project_env_id }&.values || NO_MATCHING_ROWS
98
+ nil
92
99
  end
93
100
 
94
101
  def in_segment?(criterion, properties)
@@ -96,11 +103,12 @@ module Prefab
96
103
 
97
104
  @base_client.log.info("Segment #{criterion.value_to_match.string} not found") unless segment
98
105
 
99
- segment&.bool
106
+ segment&.report_and_return(@base_client.evaluation_summary_aggregator)
100
107
  end
101
108
 
102
109
  def matches?(criterion, value, properties)
103
- criterion_value_or_values = Prefab::ConfigValueUnwrapper.unwrap(criterion.value_to_match, @config.key, properties)
110
+ criterion_value_or_values = Prefab::ConfigValueUnwrapper.deepest_value(criterion.value_to_match, @config.key,
111
+ properties).unwrap
104
112
 
105
113
  case criterion_value_or_values
106
114
  when Google::Protobuf::RepeatedField
@@ -27,7 +27,7 @@ module Prefab
27
27
  private
28
28
 
29
29
  def flush(to_ship, _)
30
- @pool.post do
30
+ pool.post do
31
31
  log_internal "Uploading evaluated keys for #{to_ship.size}"
32
32
 
33
33
  keys = PrefabProto::EvaluatedKeys.new(keys: to_ship.to_a, namespace: @client.namespace)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prefab
4
+ # Records the result of evaluating a config's criteria and forensics for reporting
5
+ class Evaluation
6
+ attr_reader :value
7
+
8
+ def initialize(config:, value:, value_index:, config_row_index:, context:)
9
+ @config = config
10
+ @value = value
11
+ @value_index = value_index
12
+ @config_row_index = config_row_index
13
+ @context = context
14
+ end
15
+
16
+ def unwrapped_value
17
+ deepest_value.unwrap
18
+ end
19
+
20
+ def report_and_return(evaluation_summary_aggregator)
21
+ report(evaluation_summary_aggregator)
22
+
23
+ unwrapped_value
24
+ end
25
+
26
+ private
27
+
28
+ def report(evaluation_summary_aggregator)
29
+ return if @config.config_type == :LOG_LEVEL
30
+
31
+ evaluation_summary_aggregator&.record(
32
+ config_key: @config.key,
33
+ config_type: @config.config_type,
34
+ counter: {
35
+ config_id: @config.id,
36
+ config_row_index: @config_row_index,
37
+ conditional_value_index: @value_index,
38
+ selected_value: deepest_value.value,
39
+ weighted_value_index: deepest_value.weighted_value_index,
40
+ selected_index: nil # TODO
41
+ })
42
+ end
43
+
44
+ def deepest_value
45
+ @deepest_value ||= Prefab::ConfigValueUnwrapper.deepest_value(@value, @config.key, @context)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'periodic_sync'
4
+
5
+ module Prefab
6
+ # This class aggregates the number of times each config is evaluated, and
7
+ # details about how the config is evaluated This data is reported to the
8
+ # server at a regular interval defined by `sync_interval`.
9
+ class EvaluationSummaryAggregator
10
+ include Prefab::PeriodicSync
11
+
12
+ attr_reader :data
13
+
14
+ def initialize(client:, max_keys:, sync_interval:)
15
+ @client = client
16
+ @max_keys = max_keys
17
+ @name = 'evaluation_summary_aggregator'
18
+
19
+ @data = Concurrent::Hash.new
20
+
21
+ start_periodic_sync(sync_interval)
22
+ end
23
+
24
+ def record(config_key:, config_type:, counter:)
25
+ return if @data.size >= @max_keys
26
+
27
+ key = [config_key, config_type]
28
+ @data[key] ||= Concurrent::Hash.new
29
+
30
+ @data[key][counter] ||= 0
31
+ @data[key][counter] += 1
32
+ end
33
+
34
+ private
35
+
36
+ def counter_proto(counter, count)
37
+ PrefabProto::ConfigEvaluationCounter.new(
38
+ config_id: counter[:config_id],
39
+ selected_index: counter[:selected_index],
40
+ config_row_index: counter[:config_row_index],
41
+ conditional_value_index: counter[:conditional_value_index],
42
+ weighted_value_index: counter[:weighted_value_index],
43
+ selected_value: counter[:selected_value],
44
+ count: count
45
+ )
46
+ end
47
+
48
+ def flush(to_ship, start_at_was)
49
+ pool.post do
50
+ log_internal "Flushing #{to_ship.size} summaries"
51
+
52
+ summaries_proto = PrefabProto::ConfigEvaluationSummaries.new(
53
+ start: start_at_was,
54
+ end: Prefab::TimeHelpers.now_in_ms,
55
+ summaries: summaries(to_ship)
56
+ )
57
+
58
+ result = @client.post('/api/v1/telemetry', events(summaries_proto))
59
+
60
+ log_internal "Uploaded #{to_ship.size} summaries: #{result.status}"
61
+ end
62
+ end
63
+
64
+ def events(summaries)
65
+ event = PrefabProto::TelemetryEvent.new(summaries: summaries)
66
+
67
+ PrefabProto::TelemetryEvents.new(
68
+ instance_hash: @client.instance_hash,
69
+ events: [event]
70
+ )
71
+ end
72
+
73
+ def summaries(data)
74
+ data.map do |(config_key, config_type), counters|
75
+ counter_protos = counters.map { |counter, count| counter_proto(counter, count) }
76
+
77
+ PrefabProto::ConfigEvaluationSummary.new(
78
+ key: config_key,
79
+ type: config_type,
80
+ counters: counter_protos
81
+ )
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'periodic_sync'
4
+
5
+ module Prefab
6
+ # This class aggregates example contexts. It dedupes based on the
7
+ # concatenation of the keys of the contexts.
8
+ #
9
+ # It shouldn't send the same context more than once per hour.
10
+ class ExampleContextsAggregator
11
+ include Prefab::PeriodicSync
12
+
13
+ attr_reader :data, :cache
14
+
15
+ ONE_HOUR = 60 * 60
16
+
17
+ def initialize(client:, max_contexts:, sync_interval:)
18
+ @client = client
19
+ @max_contexts = max_contexts
20
+ @name = 'example_contexts_aggregator'
21
+
22
+ @data = Concurrent::Array.new
23
+ @cache = Prefab::RateLimitCache.new(ONE_HOUR)
24
+
25
+ start_periodic_sync(sync_interval)
26
+ end
27
+
28
+ def record(contexts)
29
+ key = contexts.grouped_key
30
+
31
+ return unless @data.size < @max_contexts && !@cache.fresh?(key)
32
+
33
+ @cache.set(key)
34
+
35
+ @data.push(contexts)
36
+ end
37
+
38
+ private
39
+
40
+ def on_prepare_data
41
+ @cache.prune
42
+ end
43
+
44
+ def flush(to_ship, _)
45
+ pool.post do
46
+ log_internal "Flushing #{to_ship.size} examples"
47
+
48
+ result = @client.post('/api/v1/telemetry', events(to_ship))
49
+
50
+ log_internal "Uploaded #{to_ship.size} examples: #{result.status}"
51
+ end
52
+ end
53
+
54
+ def example_contexts(to_ship)
55
+ to_ship.map do |contexts|
56
+ PrefabProto::ExampleContext.new(
57
+ timestamp: contexts.seen_at * 1000,
58
+ contextSet: contexts.slim_proto
59
+ )
60
+ end
61
+ end
62
+
63
+ def events(to_ship)
64
+ event = PrefabProto::TelemetryEvent.new(
65
+ example_contexts: PrefabProto::ExampleContexts.new(
66
+ examples: example_contexts(to_ship)
67
+ )
68
+ )
69
+
70
+ PrefabProto::TelemetryEvents.new(
71
+ instance_hash: @client.instance_hash,
72
+ events: [event]
73
+ )
74
+ end
75
+ end
76
+ end
@@ -1,4 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Prefab
4
+ # This class implements exponential backoff with a maximum delay.
5
+ #
6
+ # This is the default sync interval for aggregators.
2
7
  class ExponentialBackoff
3
8
  def initialize(max_delay:, initial_delay: 2, multiplier: 2)
4
9
  @initial_delay = initial_delay
@@ -37,7 +37,7 @@ module Prefab
37
37
  private
38
38
 
39
39
  def flush(to_ship, start_at_was)
40
- @pool.post do
40
+ pool.post do
41
41
  log_internal "Uploading stats for #{to_ship.size} paths"
42
42
 
43
43
  aggregate = Hash.new { |h, k| h[k] = PrefabProto::Logger.new }
@@ -15,7 +15,7 @@ module Prefab
15
15
  PrefabProto::LogLevel::WARN => ::Logger::WARN,
16
16
  PrefabProto::LogLevel::ERROR => ::Logger::ERROR,
17
17
  PrefabProto::LogLevel::FATAL => ::Logger::FATAL
18
- }
18
+ }.freeze
19
19
 
20
20
  def initialize(logdev, log_path_aggregator: nil, formatter: nil, prefix: nil)
21
21
  super(logdev)
@@ -27,7 +27,7 @@ module Prefab
27
27
  @log_path_aggregator = log_path_aggregator
28
28
  end
29
29
 
30
- def add(severity, message = nil, progname = nil, loc, &block)
30
+ def add_internal(severity, message, progname, loc, &block)
31
31
  path_loc = get_loc_path(loc)
32
32
  path = @prefix + path_loc
33
33
 
@@ -36,7 +36,7 @@ module Prefab
36
36
  log(message, path, progname, severity, &block)
37
37
  end
38
38
 
39
- def log_internal(message, path = nil, progname, severity, &block)
39
+ def log_internal(message, path, progname, severity, &block)
40
40
  path = if path
41
41
  "#{INTERNAL_PREFIX}.#{path}"
42
42
  else
@@ -51,9 +51,8 @@ module Prefab
51
51
 
52
52
  return true if @logdev.nil? || severity < level_of(path) || @silences[local_log_id]
53
53
 
54
- if progname.nil?
55
- progname = @progname
56
- end
54
+ progname = @progname if progname.nil?
55
+
57
56
  if message.nil?
58
57
  if block_given?
59
58
  message = yield
@@ -70,23 +69,23 @@ module Prefab
70
69
  end
71
70
 
72
71
  def debug(progname = nil, &block)
73
- add(DEBUG, nil, progname, caller_locations(1, 1)[0], &block)
72
+ add_internal(DEBUG, nil, progname, caller_locations(1, 1)[0], &block)
74
73
  end
75
74
 
76
75
  def info(progname = nil, &block)
77
- add(INFO, nil, progname, caller_locations(1, 1)[0], &block)
76
+ add_internal(INFO, nil, progname, caller_locations(1, 1)[0], &block)
78
77
  end
79
78
 
80
79
  def warn(progname = nil, &block)
81
- add(WARN, nil, progname, caller_locations(1, 1)[0], &block)
80
+ add_internal(WARN, nil, progname, caller_locations(1, 1)[0], &block)
82
81
  end
83
82
 
84
83
  def error(progname = nil, &block)
85
- add(ERROR, nil, progname, caller_locations(1, 1)[0], &block)
84
+ add_internal(ERROR, nil, progname, caller_locations(1, 1)[0], &block)
86
85
  end
87
86
 
88
87
  def fatal(progname = nil, &block)
89
- add(FATAL, nil, progname, caller_locations(1, 1)[0], &block)
88
+ add_internal(FATAL, nil, progname, caller_locations(1, 1)[0], &block)
90
89
  end
91
90
 
92
91
  def debug?
@@ -113,7 +112,7 @@ module Prefab
113
112
  DEBUG
114
113
  end
115
114
 
116
- def set_config_client(config_client)
115
+ def config_client=(config_client)
117
116
  @config_client = config_client
118
117
  end
119
118
 
@@ -169,7 +168,7 @@ module Prefab
169
168
  path
170
169
  end
171
170
 
172
- def format_message(severity, datetime, progname, msg, path)
171
+ def format_message(severity, datetime, progname, msg, path = nil)
173
172
  formatter = (@formatter || @default_formatter)
174
173
 
175
174
  if formatter.arity == 5