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. - #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
205 206 207 |
# File 'lib/quonfig/client.rb', line 205 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
209 210 211 |
# File 'lib/quonfig/client.rb', line 209 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.
131 132 133 |
# File 'lib/quonfig/client.rb', line 131 def logger_key @options.logger_key end |
#on_update(&block) ⇒ Object
187 188 189 |
# File 'lib/quonfig/client.rb', line 187 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.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/quonfig/client.rb', line 162 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 |
#stop ⇒ Object
191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/quonfig/client.rb', line 191 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 |