Class: Quonfig::Client
- Inherits:
-
Object
- Object
- Quonfig::Client
- Defined in:
- lib/quonfig/client.rb
Overview
Public Quonfig SDK client.
Wires the JSON stack: Quonfig::ConfigStore + Quonfig::Evaluator + Quonfig::Resolver. Three modes are supported:
-
datadir:(offline) – load a workspace from the local filesystem. -
store:(test harness) – caller-supplied ConfigStore, no I/O. -
network mode (default) – HTTP fetch from
api_urlspopulates the ConfigStore, then (if enabled) an SSE subscription keeps it live.
Network mode is the happy path for production SDK usage. The protobuf stack was retired in qfg-dk6.32; HTTP + SSE were wired back through Client in qfg-s7h.
Constant Summary collapse
- LOG =
Quonfig::InternalLogger.new(self)
Instance Attribute Summary collapse
-
#config_loader ⇒ Object
readonly
Returns the value of attribute config_loader.
-
#evaluator ⇒ Object
readonly
Returns the value of attribute evaluator.
-
#instance_hash ⇒ Object
readonly
Returns the value of attribute instance_hash.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#resolver ⇒ Object
readonly
Returns the value of attribute resolver.
-
#store ⇒ Object
readonly
Returns the value of attribute store.
Instance Method Summary collapse
- #defined?(key) ⇒ Boolean
- #enabled?(feature_name, jit_context = NO_DEFAULT_PROVIDED) ⇒ Boolean
- #fork ⇒ Object
-
#get(key, default = NO_DEFAULT_PROVIDED, jit_context = NO_DEFAULT_PROVIDED) ⇒ Object
—- Lookup ——————————————————–.
- #get_bool(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
- #get_duration(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
- #get_float(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
- #get_int(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
- #get_json(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
- #get_string(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
- #get_string_list(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
-
#in_context(properties) ⇒ Object
—- Context binding ———————————————-.
-
#initialize(options = nil, store: nil, **option_kwargs) ⇒ Client
constructor
A new instance of Client.
- #inspect ⇒ Object
- #keys ⇒ Object
-
#logger_key ⇒ Object
The configured
logger_keyfrom Options — the Quonfig config key the higher-levelshould_log?helper evaluates per-logger. - #on_update(&block) ⇒ Object
-
#semantic_logger_filter(config_key:) ⇒ Object
—- Filters & helpers ——————————————–.
-
#should_log?(logger_path:, desired_level:, contexts: {}) ⇒ Boolean
Higher-level log-level check — a convenience on top of the primitive
get. -
#stdlib_formatter(logger_name: nil) ⇒ Proc
Build a formatter Proc for Ruby’s built-in
::Logger. - #stop ⇒ Object
- #with_context(properties, &block) ⇒ Object
Constructor Details
#initialize(options = nil, store: nil, **option_kwargs) ⇒ Client
Returns a new instance of Client.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/quonfig/client.rb', line 26 def initialize( = nil, store: nil, **option_kwargs) @options = if .is_a?(Quonfig::Options) elsif .is_a?(Hash) Quonfig::Options.new(.merge(option_kwargs)) else Quonfig::Options.new(option_kwargs) end @global_context = normalize_context(@options.global_context) @instance_hash = SecureRandom.uuid @store = store || Quonfig::ConfigStore.new @evaluator = Quonfig::Evaluator.new(@store, env_id: @options.environment) @resolver = Quonfig::Resolver.new(@store, @evaluator) @semantic_logger_filters = {} @sse_client = nil @poll_thread = nil @stopped = false # If the caller injected a store, we're in test/bootstrap mode; skip I/O. return if store if @options.datadir load_datadir_into_store else initialize_network_mode end end |
Instance Attribute Details
#config_loader ⇒ Object (readonly)
Returns the value of attribute config_loader.
23 24 25 |
# File 'lib/quonfig/client.rb', line 23 def config_loader @config_loader end |
#evaluator ⇒ Object (readonly)
Returns the value of attribute evaluator.
23 24 25 |
# File 'lib/quonfig/client.rb', line 23 def evaluator @evaluator end |
#instance_hash ⇒ Object (readonly)
Returns the value of attribute instance_hash.
23 24 25 |
# File 'lib/quonfig/client.rb', line 23 def instance_hash @instance_hash end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
23 24 25 |
# File 'lib/quonfig/client.rb', line 23 def @options end |
#resolver ⇒ Object (readonly)
Returns the value of attribute resolver.
23 24 25 |
# File 'lib/quonfig/client.rb', line 23 def resolver @resolver end |
#store ⇒ Object (readonly)
Returns the value of attribute store.
23 24 25 |
# File 'lib/quonfig/client.rb', line 23 def store @store end |
Instance Method Details
#defined?(key) ⇒ Boolean
98 99 100 |
# File 'lib/quonfig/client.rb', line 98 def defined?(key) !@store.get(key).nil? end |
#enabled?(feature_name, jit_context = NO_DEFAULT_PROVIDED) ⇒ Boolean
93 94 95 96 |
# File 'lib/quonfig/client.rb', line 93 def enabled?(feature_name, jit_context = NO_DEFAULT_PROVIDED) value = get(feature_name, false, jit_context) value == true || value == 'true' end |
#fork ⇒ Object
228 229 230 |
# File 'lib/quonfig/client.rb', line 228 def fork self.class.new(@options.for_fork) end |
#get(key, default = NO_DEFAULT_PROVIDED, jit_context = NO_DEFAULT_PROVIDED) ⇒ Object
—- Lookup ——————————————————–
57 58 59 60 61 62 63 |
# File 'lib/quonfig/client.rb', line 57 def get(key, default = NO_DEFAULT_PROVIDED, jit_context = NO_DEFAULT_PROVIDED) ctx = build_context(jit_context) result = @resolver.get(key, ctx) return handle_missing(key, default) if result.nil? result.unwrapped_value end |
#get_bool(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
77 78 79 |
# File 'lib/quonfig/client.rb', line 77 def get_bool(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) typed_get(key, :bool, default: default, context: context) end |
#get_duration(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
85 86 87 |
# File 'lib/quonfig/client.rb', line 85 def get_duration(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) typed_get(key, :duration, default: default, context: context) end |
#get_float(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
73 74 75 |
# File 'lib/quonfig/client.rb', line 73 def get_float(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) typed_get(key, Float, default: default, context: context) end |
#get_int(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
69 70 71 |
# File 'lib/quonfig/client.rb', line 69 def get_int(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) typed_get(key, Integer, default: default, context: context) end |
#get_json(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
89 90 91 |
# File 'lib/quonfig/client.rb', line 89 def get_json(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) typed_get(key, :json, default: default, context: context) end |
#get_string(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
65 66 67 |
# File 'lib/quonfig/client.rb', line 65 def get_string(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) typed_get(key, String, default: default, context: context) end |
#get_string_list(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) ⇒ Object
81 82 83 |
# File 'lib/quonfig/client.rb', line 81 def get_string_list(key, default: NO_DEFAULT_PROVIDED, context: NO_DEFAULT_PROVIDED) typed_get(key, :string_list, default: default, context: context) end |
#in_context(properties) ⇒ Object
—- Context binding ———————————————-
108 109 110 111 |
# File 'lib/quonfig/client.rb', line 108 def in_context(properties) bound = Quonfig::BoundClient.new(self, properties) block_given? ? yield(bound) : bound end |
#inspect ⇒ Object
232 233 234 |
# File 'lib/quonfig/client.rb', line 232 def inspect "#<Quonfig::Client:#{object_id} environment=#{@options.environment.inspect}>" end |
#keys ⇒ Object
102 103 104 |
# File 'lib/quonfig/client.rb', line 102 def keys @store.keys end |
#logger_key ⇒ Object
The configured logger_key from Options — the Quonfig config key the higher-level should_log? helper evaluates per-logger. nil if the client was not configured for dynamic log levels.
154 155 156 |
# File 'lib/quonfig/client.rb', line 154 def logger_key @options.logger_key end |
#on_update(&block) ⇒ Object
210 211 212 |
# File 'lib/quonfig/client.rb', line 210 def on_update(&block) @on_update = block end |
#semantic_logger_filter(config_key:) ⇒ Object
—- Filters & helpers ——————————————–
123 124 125 126 |
# File 'lib/quonfig/client.rb', line 123 def semantic_logger_filter(config_key:) @semantic_logger_filters[config_key] ||= Quonfig::SemanticLoggerFilter.new(self, config_key: config_key) end |
#should_log?(logger_path:, desired_level:, contexts: {}) ⇒ Boolean
Higher-level log-level check — a convenience on top of the primitive get. Evaluates the client’s logger_key config and returns whether a message at desired_level should be emitted for logger_path.
The SDK injects logger_path under the quonfig-sdk-logging named context with property key so a single log-level config can drive per-logger overrides via the normal rule engine (e.g. PROP_STARTS_WITH_ONE_OF “MyApp::Services::”).
logger_path is passed through verbatim — the SDK does not normalize it. Callers may pass any identifier shape their host language prefers (dotted, colon, slash, etc.) and author matching rules in the config against that exact shape.
Parallels sdk-node’s shouldLog({loggerPath}) and sdk-go’s ShouldLogPath.
Raises Quonfig::Error if logger_key was not set on the client —use semantic_logger_filter(config_key:) directly if you want to evaluate a specific key without declaring it at init time.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/quonfig/client.rb', line 185 def should_log?(logger_path:, desired_level:, contexts: {}) unless logger_key raise Quonfig::Error, 'logger_key must be set at init to use should_log?(logger_path:, ...). ' \ 'Pass `logger_key:` to Quonfig::Options.new, or call ' \ 'semantic_logger_filter(config_key:) / get(config_key) directly.' end logger_context = { Quonfig::SemanticLoggerFilter::LOGGER_CONTEXT_NAME => { Quonfig::SemanticLoggerFilter::LOGGER_CONTEXT_KEY_PROP => logger_path } } merged = merge_contexts(normalize_context(contexts), logger_context) configured = get(logger_key, nil, merged) return true if configured.nil? desired_severity = Quonfig::SemanticLoggerFilter::LEVELS[normalize_log_level(desired_level)] || Quonfig::SemanticLoggerFilter::LEVELS[:debug] min_severity = Quonfig::SemanticLoggerFilter::LEVELS[normalize_log_level(configured)] || Quonfig::SemanticLoggerFilter::LEVELS[:debug] desired_severity >= min_severity end |
#stdlib_formatter(logger_name: nil) ⇒ Proc
Build a formatter Proc for Ruby’s built-in ::Logger. The returned proc honors dynamic log levels from the client’s logger_key config: for each log call, it evaluates should_log? and either formats the record or returns an empty string (suppressing output).
Matches ReforgeHQ’s stdlib_formatter API name (snake_case).
Usage:
logger = ::Logger.new($stdout)
logger.formatter = client.stdlib_formatter # uses progname
logger.formatter = client.stdlib_formatter(logger_name: 'MyApp') # fixed name
Raises Quonfig::Error if logger_key was not set at init — parallels should_log?‘s behavior.
147 148 149 |
# File 'lib/quonfig/client.rb', line 147 def stdlib_formatter(logger_name: nil) Quonfig::StdlibFormatter.build(self, logger_name: logger_name) end |
#stop ⇒ Object
214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/quonfig/client.rb', line 214 def stop @stopped = true begin @sse_client&.close rescue StandardError => e LOG.debug "Error closing SSE client: #{e.}" end @sse_client = nil thread = @poll_thread @poll_thread = nil thread&.kill end |
#with_context(properties, &block) ⇒ Object
113 114 115 116 117 118 119 |
# File 'lib/quonfig/client.rb', line 113 def with_context(properties, &block) if block_given? in_context(properties, &block) else Quonfig::BoundClient.new(self, properties) end end |