prefab-cloud-ruby 0.18.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9225ebaadf8be997d152b66cb58ff342d126bc5cfbe489511af4791d89dd5f7
4
- data.tar.gz: cbaf511c7aeaf0ef743b33c2ad00c40bd4d6c8ddba0a17ddff541afeb8e055d9
3
+ metadata.gz: d1d4612e27cae5a4e66065a16d8d70cb0b1c7120770eac8c7e09ce3ca0e48e82
4
+ data.tar.gz: 1d1f50b6b4605729b93d62194b17ed9a1fca739f435ec2a4e682482a293bffe6
5
5
  SHA512:
6
- metadata.gz: f00e343e6f3f7a7f11351409708979c4e02420eae8bf8d9520cdc58de464b682158b863bcab88b4583c469709c621f066bd8995e482963386b931c877bfd2b1f
7
- data.tar.gz: 5e51d64d2d5adc738e5f8438cd222ae3e4d9fc1f183a789d25486da7197b25c3263fff9a0fac9b33a9acffc169e035630e7a8cb8b3d3770e9e8b669d34b96f68
6
+ metadata.gz: ed5a04b2a16a79b0963d9af2dd71955141fdd06e7d73a4897adf74245435cf33239f78b08bbde797b7420b7e988fbb76e5e4333e6da5350f1037502949c469e7
7
+ data.tar.gz: 1b6f556bb94a31c272d5cd3c585860cacb4698be61830379c1a1a7e2d2fdcb461c02777e0c6fdb6a2cc939dcb070a27237506bd3c21d69ccd723ec50dccfbf2a
data/Gemfile CHANGED
@@ -19,4 +19,5 @@ end
19
19
 
20
20
  group :test do
21
21
  gem "minitest"
22
+ gem "minitest-focus"
22
23
  end
data/Gemfile.lock CHANGED
@@ -30,7 +30,7 @@ GEM
30
30
  faraday (>= 0.8, < 2)
31
31
  hashie (~> 3.5, >= 3.5.2)
32
32
  oauth2 (~> 1.0)
33
- google-protobuf (3.21.4)
33
+ google-protobuf (3.21.9)
34
34
  googleapis-common-protos-types (1.3.0)
35
35
  google-protobuf (~> 3.14)
36
36
  grpc (1.43.1)
@@ -70,10 +70,12 @@ GEM
70
70
  rake (~> 13.0)
71
71
  mini_portile2 (2.8.0)
72
72
  minitest (5.16.2)
73
+ minitest-focus (1.3.1)
74
+ minitest (>= 4, < 6)
73
75
  multi_json (1.15.0)
74
76
  multi_xml (0.6.0)
75
77
  multipart-post (2.1.1)
76
- nokogiri (1.13.6)
78
+ nokogiri (1.13.9)
77
79
  mini_portile2 (~> 2.8.0)
78
80
  racc (~> 1.4)
79
81
  oauth2 (1.4.7)
@@ -86,7 +88,7 @@ GEM
86
88
  public_suffix (4.0.6)
87
89
  racc (1.6.0)
88
90
  rack (2.2.4)
89
- rake (13.0.3)
91
+ rake (13.0.6)
90
92
  rchardet (1.8.0)
91
93
  rdoc (6.3.3)
92
94
  ruby2_keywords (0.0.4)
@@ -119,6 +121,7 @@ DEPENDENCIES
119
121
  juwelier (~> 2.4.9)
120
122
  ld-eventsource
121
123
  minitest
124
+ minitest-focus
122
125
  rdoc
123
126
  simplecov
124
127
  thin
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # prefab-cloud-ruby
2
- Ruby Client for Prefab RateLimits, FeatureFlags, Config as a Service: https://www.prefab.cloud
2
+ Ruby Client for Prefab FeatureFlags, Config as a Service: https://www.prefab.cloud
3
3
 
4
4
  ```ruby
5
5
  client = Prefab::Client.new
@@ -16,11 +16,9 @@ puts @feature_flags.feature_is_on? "MyFeature", "user:1123"
16
16
  ```
17
17
  See full documentation https://www.prefab.cloud/documentation/installation
18
18
 
19
-
20
19
  ## Supports
21
20
 
22
21
  * [FeatureFlags](https://www.prefab.cloud/documentation/feature_flags) as a Service
23
- * [RateLimits](https://www.prefab.cloud/documentation/basic_rate_limits)
24
22
  * Millions of individual limits sharing the same policies
25
23
  * WebUI for tweaking limits & feature flags
26
24
  * Infinite retention for [deduplication workflows](https://www.prefab.cloud/documentation/once_and_only_once)
@@ -44,15 +42,19 @@ end
44
42
 
45
43
  ## Logging & Debugging
46
44
  In classpath or ~/.prefab.overrides.config.yaml set
47
- ```log-level.prefab: debug```
45
+
46
+ ```
47
+ log-level:
48
+ cloud.prefab: debug
49
+ ```
48
50
 
49
51
  To debug issues before this config file has been read, set env var
50
52
  ```
51
- PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL = debug
53
+ PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL=debug
52
54
  ```
53
55
 
54
56
  ## Contributing to prefab-cloud-ruby
55
-
57
+
56
58
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
57
59
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
58
60
  * Fork the project.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.18.0
1
+ 0.20.0
data/lib/prefab/client.rb CHANGED
@@ -47,10 +47,11 @@ module Prefab
47
47
  end
48
48
 
49
49
  def log
50
- @logger_client ||= Prefab::LoggerClient.new(@options.logdev, formatter: @options.log_formatter)
50
+ @logger_client ||= Prefab::LoggerClient.new(@options.logdev, formatter: @options.log_formatter,
51
+ prefix: @options.log_prefix)
51
52
  end
52
53
 
53
- def log_internal(level, msg, path = "prefab")
54
+ def log_internal(level, msg, path = nil)
54
55
  log.log_internal msg, path, nil, level
55
56
  end
56
57
 
@@ -189,7 +189,7 @@ module Prefab
189
189
  if @config_loader.highwater_mark > starting_highwater_mark
190
190
  @base_client.log_internal Logger::INFO, "Found new checkpoint with highwater id #{@config_loader.highwater_mark} from #{source} in project #{project_id} environment: #{project_env_id} and namespace: '#{@namespace}'"
191
191
  else
192
- @base_client.log_internal Logger::DEBUG, "Checkpoint with highwater id #{@config_loader.highwater_mark} from #{source}. No changes.", "prefab.config_client.load_configs"
192
+ @base_client.log_internal Logger::DEBUG, "Checkpoint with highwater id #{@config_loader.highwater_mark} from #{source}. No changes.", "load_configs"
193
193
  end
194
194
  @base_client.stats.increment("prefab.config.checkpoint.load")
195
195
  @config_resolver.update
@@ -237,7 +237,7 @@ module Prefab
237
237
  @streaming_thread = SSE::Client.new(url,
238
238
  headers: headers,
239
239
  read_timeout: SSE_READ_TIMEOUT,
240
- logger: Prefab::InternalLogger.new("prefab.config.sse", @base_client.log)) do |client|
240
+ logger: Prefab::SseLogger.new(@base_client.log)) do |client|
241
241
  client.on_event do |event|
242
242
  configs = Prefab::Configs.decode(Base64.decode64(event.data))
243
243
  load_configs(configs, :sse)
@@ -18,7 +18,8 @@ module Prefab
18
18
  def to_s
19
19
  str = "\n"
20
20
  @lock.with_read_lock do
21
- @local_store.each do |k, v|
21
+ @local_store.keys.sort.each do |k|
22
+ v = @local_store[k]
22
23
  elements = [k.slice(0..49).ljust(50)]
23
24
  if v.nil?
24
25
  elements << "tombstone"
@@ -5,6 +5,7 @@ module Prefab
5
5
  SEP = "."
6
6
  BASE_KEY = "log-level"
7
7
  UNKNOWN_PATH = "unknown."
8
+ INTERNAL_PREFIX = "cloud.prefab.client"
8
9
 
9
10
  LOG_LEVEL_LOOKUPS = {
10
11
  Prefab::LogLevel::NOT_SET_LOG_LEVEL => Logger::DEBUG,
@@ -16,33 +17,39 @@ module Prefab
16
17
  Prefab::LogLevel::FATAL => Logger::FATAL
17
18
  }
18
19
 
19
- def initialize(logdev, formatter: nil)
20
+ def initialize(logdev, formatter: nil, prefix: nil)
20
21
  super(logdev)
21
22
  self.formatter = formatter
22
23
  @config_client = BootstrappingConfigClient.new
23
- @silences = Concurrent::Map.new(:initial_capacity => 2)
24
+ @silences = Concurrent::Map.new(initial_capacity: 2)
25
+ @prefix = prefix
24
26
  end
25
27
 
26
- def add(severity, message = nil, progname = nil)
27
- loc = caller_locations(1, 1)[0]
28
- add_internal(severity, message, progname, loc)
28
+ def add(severity, message = nil, progname = nil, loc, &block)
29
+ path = get_loc_path(loc)
30
+ path = "#{@prefix}#{@prefix && '.'}#{path}"
31
+
32
+ log(message, path, progname, severity, &block)
29
33
  end
30
34
 
31
- def add_internal(severity, message = nil, progname = nil, loc, &block)
32
- path = get_loc_path(loc)
33
- log_internal(message, path, progname, severity, &block)
35
+ def log_internal(message, path = nil, progname, severity, &block)
36
+ if path
37
+ path = "#{INTERNAL_PREFIX}.#{path}"
38
+ else
39
+ path = INTERNAL_PREFIX
40
+ end
41
+
42
+ log(message, path, progname, severity, &block)
34
43
  end
35
44
 
36
- def log_internal(message, path, progname, severity, &block)
37
- level = level_of(path)
38
- progname = "#{path}: #{progname}"
45
+ def log(message, path, progname, severity, &block)
39
46
  severity ||= Logger::UNKNOWN
40
- if @logdev.nil? || severity < level || @silences[local_log_id]
47
+ if @logdev.nil? || severity < level_of(path) || @silences[local_log_id]
41
48
  return true
42
49
  end
43
- if progname.nil?
44
- progname = @progname
45
- end
50
+
51
+ progname = "#{path}: #{progname || @progname}"
52
+
46
53
  if message.nil?
47
54
  if block_given?
48
55
  message = yield
@@ -51,29 +58,30 @@ module Prefab
51
58
  progname = @progname
52
59
  end
53
60
  end
61
+
54
62
  @logdev.write(
55
63
  format_message(format_severity(severity), Time.now, progname, message))
56
64
  true
57
65
  end
58
66
 
59
67
  def debug(progname = nil, &block)
60
- add_internal(DEBUG, nil, progname, caller_locations(1, 1)[0], &block)
68
+ add(DEBUG, nil, progname, caller_locations(1, 1)[0], &block)
61
69
  end
62
70
 
63
71
  def info(progname = nil, &block)
64
- add_internal(INFO, nil, progname, caller_locations(1, 1)[0], &block)
72
+ add(INFO, nil, progname, caller_locations(1, 1)[0], &block)
65
73
  end
66
74
 
67
75
  def warn(progname = nil, &block)
68
- add_internal(WARN, nil, progname, caller_locations(1, 1)[0], &block)
76
+ add(WARN, nil, progname, caller_locations(1, 1)[0], &block)
69
77
  end
70
78
 
71
79
  def error(progname = nil, &block)
72
- add_internal(ERROR, nil, progname, caller_locations(1, 1)[0], &block)
80
+ add(ERROR, nil, progname, caller_locations(1, 1)[0], &block)
73
81
  end
74
82
 
75
83
  def fatal(progname = nil, &block)
76
- add_internal(FATAL, nil, progname, caller_locations(1, 1)[0], &block)
84
+ add(FATAL, nil, progname, caller_locations(1, 1)[0], &block)
77
85
  end
78
86
 
79
87
  def debug?
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class Options
4
5
  attr_reader :api_key
5
6
  attr_reader :logdev
7
+ attr_reader :log_prefix
6
8
  attr_reader :log_formatter
7
9
  attr_reader :stats
8
10
  attr_reader :shared_cache
@@ -17,7 +19,7 @@ module Prefab
17
19
  attr_reader :prefab_envs
18
20
 
19
21
  DEFAULT_LOG_FORMATTER = proc { |severity, datetime, progname, msg|
20
- "#{severity.ljust(5)} #{datetime}: #{progname} #{msg}\n"
22
+ "#{severity.ljust(5)} #{datetime}:#{" " if progname}#{progname} #{msg}\n"
21
23
  }
22
24
 
23
25
  module ON_INITIALIZATION_FAILURE
@@ -40,6 +42,7 @@ module Prefab
40
42
  shared_cache: NoopCache.new, # Something that quacks like Rails.cache ideally memcached
41
43
  namespace: "",
42
44
  log_formatter: DEFAULT_LOG_FORMATTER,
45
+ log_prefix: nil,
43
46
  prefab_api_url: ENV["PREFAB_API_URL"] || 'https://api.prefab.cloud',
44
47
  prefab_grpc_url: ENV["PREFAB_GRPC_URL"] || 'grpc.prefab.cloud:443',
45
48
  on_no_default: ON_NO_DEFAULT::RAISE, # options :raise, :warn_and_return_nil,
@@ -59,6 +62,7 @@ module Prefab
59
62
  @shared_cache = shared_cache
60
63
  @namespace = namespace
61
64
  @log_formatter = log_formatter
65
+ @log_prefix = log_prefix
62
66
  @prefab_api_url = prefab_api_url
63
67
  @prefab_grpc_url = prefab_grpc_url
64
68
  @on_no_default = on_no_default
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module Prefab
3
+ class SseLogger < InternalLogger
4
+ def initialize(logger)
5
+ super("sse", logger)
6
+ end
7
+
8
+ # The SSE::Client warns on a perfectly normal stream disconnect, recast to info
9
+ def warn(progname = nil, &block)
10
+ @logger.log_internal yield, @path, progname, INFO
11
+ end
12
+ end
13
+ end
@@ -13,6 +13,7 @@ require 'prefab/errors/missing_default_error'
13
13
  require 'prefab_services_pb'
14
14
  require 'prefab/options'
15
15
  require 'prefab/internal_logger'
16
+ require 'prefab/sse_logger'
16
17
  require 'prefab/config_helper'
17
18
  require 'prefab/config_loader'
18
19
  require 'prefab/config_resolver'
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: prefab-cloud-ruby 0.18.0 ruby lib
5
+ # stub: prefab-cloud-ruby 0.20.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "prefab-cloud-ruby".freeze
9
- s.version = "0.18.0"
9
+ s.version = "0.20.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Jeff Dwyer".freeze]
14
- s.date = "2022-10-14"
14
+ s.date = "2022-12-02"
15
15
  s.description = "RateLimits & Config as a service".freeze
16
16
  s.email = "jdwyer@prefab.cloud".freeze
17
17
  s.extra_rdoc_files = [
@@ -50,6 +50,7 @@ Gem::Specification.new do |s|
50
50
  "lib/prefab/noop_stats.rb",
51
51
  "lib/prefab/options.rb",
52
52
  "lib/prefab/ratelimit_client.rb",
53
+ "lib/prefab/sse_logger.rb",
53
54
  "lib/prefab_pb.rb",
54
55
  "lib/prefab_services_pb.rb",
55
56
  "prefab-cloud-ruby.gemspec",
data/test/test_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'minitest/autorun'
3
+ require "minitest/focus"
3
4
  require 'prefab-cloud-ruby'
4
5
 
5
6
  class MockBaseClient
data/test/test_logger.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'test_helper'
3
4
 
4
5
  class TestCLogger < Minitest::Test
@@ -69,19 +70,19 @@ class TestCLogger < Minitest::Test
69
70
  end
70
71
 
71
72
  def test_log_internal
72
- logger, mock_logdev = mock_logger_expecting /W, \[.*\] WARN -- test.path: : test message/
73
+ logger, mock_logdev = mock_logger_expecting(/W, \[.*\] WARN -- cloud.prefab.client.test.path: : test message/)
73
74
  logger.log_internal("test message", "test.path", "", Logger::WARN)
74
75
  mock_logdev.verify
75
76
  end
76
77
 
77
78
  def test_log_internal_unknown
78
- logger, mock_logdev = mock_logger_expecting /A, \[.*\] ANY -- test.path: : test message/
79
+ logger, mock_logdev = mock_logger_expecting(/A, \[.*\] ANY -- cloud.prefab.client.test.path: : test message/)
79
80
  logger.log_internal("test message", "test.path", "", Logger::UNKNOWN)
80
81
  mock_logdev.verify
81
82
  end
82
83
 
83
84
  def test_log_internal_silencing
84
- logger, mock_logdev = mock_logger_expecting /W, \[.*\] WARN -- test.path: : should log/, calls: 2
85
+ logger, mock_logdev = mock_logger_expecting(/W, \[.*\] WARN -- cloud.prefab.client.test.path: : should log/, calls: 2)
85
86
  logger.silence do
86
87
  logger.log_internal("should not log", "test.path", "", Logger::WARN)
87
88
  end
@@ -89,6 +90,81 @@ class TestCLogger < Minitest::Test
89
90
  mock_logdev.verify
90
91
  end
91
92
 
93
+ def test_log
94
+ logger, mock_logdev = mock_logger_expecting(/W, \[.*\] WARN -- test.path: : test message/)
95
+ logger.log("test message", "test.path", "", Logger::WARN)
96
+ mock_logdev.verify
97
+ end
98
+
99
+ def test_log_unknown
100
+ logger, mock_logdev = mock_logger_expecting(/A, \[.*\] ANY -- test.path: : test message/)
101
+ logger.log("test message", "test.path", "", Logger::UNKNOWN)
102
+ mock_logdev.verify
103
+ end
104
+
105
+ def test_log_silencing
106
+ logger, mock_logdev = mock_logger_expecting(/W, \[.*\] WARN -- test.path: : should log/, calls: 2)
107
+ logger.silence do
108
+ logger.log("should not log", "test.path", "", Logger::WARN)
109
+ end
110
+ logger.log("should log", "test.path", "", Logger::WARN)
111
+ mock_logdev.verify
112
+ end
113
+
114
+ def test_logging_with_prefix
115
+ prefix = 'my.own.prefix'
116
+ message = 'this is a test'
117
+
118
+ prefab, io = captured_logger(log_prefix: prefix)
119
+
120
+ prefixed_logger = prefab.log
121
+ prefixed_logger.error message
122
+
123
+ assert_logged io, 'ERROR', "#{prefix}.test.test_logger.test_logging_with_prefix", message
124
+ end
125
+
126
+ def test_logging_without_a_progname
127
+ prefab, io = captured_logger
128
+ message = "MY MESSAGE"
129
+
130
+ prefab.log.error message
131
+
132
+ assert_logged io, 'ERROR', "test.test_logger.test_logging_without_a_progname", message
133
+ end
134
+
135
+ def test_logging_without_a_progname_or_message
136
+ prefab, io = captured_logger
137
+
138
+ prefab.log.error
139
+
140
+ assert_logged io, 'ERROR', "test.test_logger.test_logging_without_a_progname_or_message", ""
141
+ end
142
+
143
+ def test_logging_with_a_progname
144
+ prefab, io = captured_logger
145
+ message = "MY MESSAGE"
146
+
147
+ prefab.log.progname = "MY_PROGNAME"
148
+ prefab.log.error message
149
+
150
+ assert_logged io, 'ERROR', "MY_PROGNAME test.test_logger.test_logging_with_a_progname", message
151
+ end
152
+
153
+ def test_logging_with_a_progname_and_no_message
154
+ prefab, io = captured_logger
155
+
156
+ prefab.log.progname = "MY_PROGNAME"
157
+ prefab.log.error
158
+
159
+ assert_logged io, 'ERROR', "MY_PROGNAME test.test_logger.test_logging_with_a_progname_and_no_message", "MY_PROGNAME"
160
+ end
161
+
162
+ private
163
+
164
+ def assert_logged(logged_io, level, path, message)
165
+ assert_match(/#{level} \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-\+]?\d+: #{path}: #{message}\n/, logged_io.string)
166
+ end
167
+
92
168
  def mock_logger_expecting pattern, configs = {}, calls: 1
93
169
  mock_logdev = Minitest::Mock.new
94
170
  mock_logdev.expect :write, nil do |arg|
@@ -104,4 +180,15 @@ class TestCLogger < Minitest::Test
104
180
  logger.set_config_client(MockConfigClient.new(configs))
105
181
  [logger, mock_logdev]
106
182
  end
183
+
184
+ def captured_logger(options = {})
185
+ io = StringIO.new
186
+ options = Prefab::Options.new(**options.merge(
187
+ logdev: io,
188
+ prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY
189
+ ))
190
+ prefab = Prefab::Client.new(options)
191
+
192
+ return [prefab, io]
193
+ end
107
194
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prefab-cloud-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dwyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-14 00:00:00.000000000 Z
11
+ date: 2022-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -237,6 +237,7 @@ files:
237
237
  - lib/prefab/noop_stats.rb
238
238
  - lib/prefab/options.rb
239
239
  - lib/prefab/ratelimit_client.rb
240
+ - lib/prefab/sse_logger.rb
240
241
  - lib/prefab_pb.rb
241
242
  - lib/prefab_services_pb.rb
242
243
  - prefab-cloud-ruby.gemspec