confeature 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +26 -4
- data/lib/confeature/client.rb +397 -0
- data/lib/confeature/evaluation_details.rb +89 -0
- data/lib/confeature/flag_overrides.rb +186 -0
- data/lib/confeature/hooks.rb +84 -0
- data/lib/confeature/internal/cache.rb +166 -0
- data/lib/confeature/internal/comparators.rb +483 -0
- data/lib/confeature/internal/config_fetcher.rb +254 -0
- data/lib/confeature/internal/eval_log.rb +334 -0
- data/lib/confeature/internal/eval_logger.rb +140 -0
- data/lib/confeature/internal/evaluator.rb +866 -0
- data/lib/confeature/internal/hashing.rb +89 -0
- data/lib/confeature/internal/override_eval.rb +184 -0
- data/lib/confeature/internal/poll_service.rb +218 -0
- data/lib/confeature/internal/prerequisites.rb +88 -0
- data/lib/confeature/internal/sdk_key.rb +121 -0
- data/lib/confeature/internal/segments.rb +79 -0
- data/lib/confeature/internal/semver.rb +163 -0
- data/lib/confeature/log_level.rb +20 -0
- data/lib/confeature/logger.rb +59 -0
- data/lib/confeature/polling_mode.rb +62 -0
- data/lib/confeature/snapshot.rb +158 -0
- data/lib/confeature/user.rb +52 -0
- data/lib/confeature/version.rb +11 -0
- data/lib/confeature.rb +39 -1
- metadata +70 -7
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
module Confeature
|
|
6
|
+
module Internal
|
|
7
|
+
# Evaluation logger surface (ADR 0003 / epic #494, Ruby slice of #501).
|
|
8
|
+
#
|
|
9
|
+
# The WARN / ERROR / INFO lines the federated evaluator emits during a trace,
|
|
10
|
+
# ported from `packages/sdk-shared/src/logger.ts` (the `LoggerWrapper`
|
|
11
|
+
# helpers `userObjectIsMissing` / `userObjectAttributeIsMissing` /
|
|
12
|
+
# `userObjectAttributeIsMissingForPercentage` / `userObjectAttributeIsInvalid`
|
|
13
|
+
# / `comparisonValueIsInvalid` / `circularDependency`) and the INFO 5000 trace
|
|
14
|
+
# emission point in `evaluator.ts`. Mirrors the Go / Python ports so the
|
|
15
|
+
# federation ports stay consistent.
|
|
16
|
+
#
|
|
17
|
+
# The strings are ported VERBATIM from logger.ts (Principle II —
|
|
18
|
+
# byte-identical to the canonical). The capture format the parity test
|
|
19
|
+
# reconstructs is `"<LEVEL>: [<eventId>] <message>"` per emitted call, joined
|
|
20
|
+
# by "\n", with the INFO 5000 entry carrying the multi-line indented trace.
|
|
21
|
+
#
|
|
22
|
+
# This trace-logging seam is intentionally distinct from the public
|
|
23
|
+
# `Confeature::Logger`: a customer-supplied logger has the
|
|
24
|
+
# `error/warning/info/debug` shape, while the trace test taps a structured
|
|
25
|
+
# `(level, event_id, message)` recorder. Keeping them separate matches the Go
|
|
26
|
+
# / Python factoring and keeps the no-trace hot path zero-cost.
|
|
27
|
+
module EvalLogger
|
|
28
|
+
# Mirrors configcat-common's numeric ordering (logger.ts `LogLevel`). Level
|
|
29
|
+
# filtering ("Info and above") works identically across SDKs. Distinct from
|
|
30
|
+
# the public `Confeature::LogLevel` (stdlib ordering), used ONLY for the
|
|
31
|
+
# trace seam so the gating matches the canonical reference exactly.
|
|
32
|
+
module TraceLevel
|
|
33
|
+
OFF = -1
|
|
34
|
+
ERROR = 1
|
|
35
|
+
WARN = 2
|
|
36
|
+
INFO = 3
|
|
37
|
+
DEBUG = 4
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Internal logger adapter threaded through the evaluation context. Mirrors
|
|
41
|
+
# logger.ts `LoggerWrapper`: a `nil` inner means tracing is off (zero
|
|
42
|
+
# cost), and every helper is level-gated at the boundary.
|
|
43
|
+
#
|
|
44
|
+
# The injected `inner` is any object responding to `level` (→ a
|
|
45
|
+
# `TraceLevel`) and `log(level, event_id, message)` — the seam the parity
|
|
46
|
+
# test's capture logger implements.
|
|
47
|
+
class TraceLog
|
|
48
|
+
def initialize(inner)
|
|
49
|
+
@inner = inner
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def enabled?(level)
|
|
53
|
+
return false if @inner.nil?
|
|
54
|
+
|
|
55
|
+
threshold = @inner.level
|
|
56
|
+
return false if threshold == TraceLevel::OFF
|
|
57
|
+
|
|
58
|
+
level <= threshold
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# WARN 3001 (verbatim from logger.ts `userObjectIsMissing`).
|
|
62
|
+
def user_object_is_missing(key)
|
|
63
|
+
emit(
|
|
64
|
+
TraceLevel::WARN, "3001",
|
|
65
|
+
"cannot evaluate targeting rules and % options for setting '#{key}' " \
|
|
66
|
+
"(User Object is missing); you should pass a User Object to the evaluation " \
|
|
67
|
+
"methods like `getValue()` in order to make targeting work properly; read more: " \
|
|
68
|
+
"https://configcat.com/docs/advanced/user-object/"
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# WARN 3003 (verbatim from logger.ts `userObjectAttributeIsMissing`).
|
|
73
|
+
def user_object_attribute_is_missing(key, attribute_name)
|
|
74
|
+
emit(
|
|
75
|
+
TraceLevel::WARN, "3003",
|
|
76
|
+
"cannot evaluate certain targeting rules of setting '#{key}' " \
|
|
77
|
+
"(the User.#{attribute_name} attribute is missing); you should set the " \
|
|
78
|
+
"User.#{attribute_name} attribute in order to make targeting work properly; " \
|
|
79
|
+
"read more: https://configcat.com/docs/advanced/user-object/"
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# WARN 3003, % options variant (verbatim from logger.ts).
|
|
84
|
+
def user_object_attribute_is_missing_for_percentage(key, attribute_name)
|
|
85
|
+
emit(
|
|
86
|
+
TraceLevel::WARN, "3003",
|
|
87
|
+
"cannot evaluate % options for setting '#{key}' " \
|
|
88
|
+
"(the User.#{attribute_name} attribute is missing); you should set the " \
|
|
89
|
+
"User.#{attribute_name} attribute in order to make targeting work properly; " \
|
|
90
|
+
"read more: https://configcat.com/docs/advanced/user-object/"
|
|
91
|
+
)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# WARN 3004 (verbatim from logger.ts `userObjectAttributeIsInvalid`).
|
|
95
|
+
def user_object_attribute_is_invalid(key, attribute_name, reason)
|
|
96
|
+
emit(
|
|
97
|
+
TraceLevel::WARN, "3004",
|
|
98
|
+
"cannot evaluate certain targeting rules of setting '#{key}' " \
|
|
99
|
+
"(the User.#{attribute_name} attribute is invalid (#{reason})); please check the " \
|
|
100
|
+
"User.#{attribute_name} attribute and make sure that its value corresponds to the " \
|
|
101
|
+
"comparison operator"
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# WARN 3004, malformed config operand (#509). Note there is NO "please
|
|
106
|
+
# check the User.<attr>…" suffix (verbatim from logger.ts
|
|
107
|
+
# `comparisonValueIsInvalid`). `inner_message` is the full
|
|
108
|
+
# `comparison value '<v>' is invalid (<reason>)` text.
|
|
109
|
+
def comparison_value_is_invalid(key, inner_message)
|
|
110
|
+
emit(
|
|
111
|
+
TraceLevel::WARN, "3004",
|
|
112
|
+
"cannot evaluate certain targeting rules of setting '#{key}' (#{inner_message})"
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# ERROR 1002 (verbatim from logger.ts `circularDependency`).
|
|
117
|
+
def circular_dependency(key, cycle)
|
|
118
|
+
emit(
|
|
119
|
+
TraceLevel::ERROR, "1002",
|
|
120
|
+
"failed to evaluate setting '#{key}' (circular dependency detected between the " \
|
|
121
|
+
"following depending flags: [#{cycle}])"
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# INFO line (the 5000 trace). Mirrors logger.ts `LoggerWrapper.info`.
|
|
126
|
+
def info(event_id, message)
|
|
127
|
+
emit(TraceLevel::INFO, event_id, message)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def emit(level, event_id, message)
|
|
133
|
+
return unless enabled?(level)
|
|
134
|
+
|
|
135
|
+
@inner.log(level, event_id, message)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|