Documentation
¶
Overview ¶
Package quonfig provides a client for fetching configuration and feature flags from the Quonfig API.
Index ¶
- Constants
- Variables
- func ContextWithContextSet(ctx context.Context, cs *ContextSet) context.Context
- func ParseISO8601Duration(s string) (time.Duration, error)
- type Client
- func (c *Client) Close()
- func (c *Client) ConnectionState() ConnectionState
- func (c *Client) EvaluateDetails(key string, ctx *ContextSet) EvaluationDetails
- func (c *Client) EvaluateKey(key string, ctx *ContextSet) (*Value, EvalReason, bool, error)
- func (c *Client) FallbackPollerActive() bool
- func (c *Client) FeatureIsOn(key string, ctx *ContextSet) (bool, bool)
- func (c *Client) GetBoolValue(key string, ctx *ContextSet) (bool, bool, error)
- func (c *Client) GetDurationValue(key string, ctx *ContextSet) (time.Duration, bool, error)
- func (c *Client) GetFloatValue(key string, ctx *ContextSet) (float64, bool, error)
- func (c *Client) GetIntValue(key string, ctx *ContextSet) (int64, bool, error)
- func (c *Client) GetJSONValue(key string, ctx *ContextSet) (interface{}, bool, error)
- func (c *Client) GetStringSliceValue(key string, ctx *ContextSet) ([]string, bool, error)
- func (c *Client) GetStringValue(key string, ctx *ContextSet) (string, bool, error)
- func (c *Client) Keys() []string
- func (c *Client) LastSuccessfulRefresh() time.Time
- func (c *Client) Refresh() error
- func (c *Client) ShouldLog(configKey string, desiredLevel string, ctx *ContextSet) bool
- func (c *Client) ShouldLogPath(loggerPath string, desiredLevel string, ctx *ContextSet) bool
- func (c *Client) WithContext(ctx *ContextSet) *ContextBoundClient
- type ConfigEnvelope
- type ConfigEvaluator
- type ConfigResponse
- type ConfigType
- type ConnectionState
- type ContextBoundClient
- func (cb *ContextBoundClient) FeatureIsOn(key string) (bool, bool)
- func (cb *ContextBoundClient) GetBoolValue(key string) (bool, bool, error)
- func (cb *ContextBoundClient) GetDurationValue(key string) (time.Duration, bool, error)
- func (cb *ContextBoundClient) GetFloatValue(key string) (float64, bool, error)
- func (cb *ContextBoundClient) GetIntValue(key string) (int64, bool, error)
- func (cb *ContextBoundClient) GetJSONValue(key string) (interface{}, bool, error)
- func (cb *ContextBoundClient) GetStringSliceValue(key string) ([]string, bool, error)
- func (cb *ContextBoundClient) GetStringValue(key string) (string, bool, error)
- func (cb *ContextBoundClient) ShouldLog(configKey string, desiredLevel string) bool
- func (cb *ContextBoundClient) ShouldLogPath(loggerPath string, desiredLevel string) bool
- func (cb *ContextBoundClient) WithContext(ctx *ContextSet) *ContextBoundClient
- type ContextSet
- type ContextTelemetryMode
- type Criterion
- type EnvLookupFunc
- type Environment
- type ErrorCode
- type EvalReason
- type EvalResult
- type EvaluationDetails
- type LogLevel
- type Meta
- type NamedContext
- type OnInitFailure
- type Option
- func WithAPIKey(key string) Option
- func WithAPIURLs(urls []string) Option
- func WithAllTelemetryDisabled() Option
- func WithCollectEvaluationSummaries(enabled bool) Option
- func WithContextTelemetryMode(mode ContextTelemetryMode) Option
- func WithDataDir(path string) Option
- func WithDataDirAutoReload(enabled bool) Option
- func WithDataDirAutoReloadDebounce(d time.Duration) Option
- func WithEnvLookup(fn EnvLookupFunc) Option
- func WithEnvironment(environment string) Option
- func WithFallbackPoll(enabled bool, interval time.Duration) Option
- func WithGlobalContext(ctx *ContextSet) Option
- func WithHTTPClient(client *http.Client) Option
- func WithInitTimeout(d time.Duration) Option
- func WithLogger(logger *slog.Logger) Option
- func WithLoggerKey(key string) Option
- func WithOnConfigUpdate(fn func()) Option
- func WithOnInitFailure(f OnInitFailure) Option
- func WithQuonfigUserContext(enabled bool) Option
- func WithRefreshInterval(d time.Duration) Optiondeprecated
- func WithSSE(enabled bool) Option
- func WithSSEStateCallback(fn func(connected bool)) Option
- func WithTelemetrySyncInterval(d time.Duration) Option
- func WithTelemetryURL(url string) Option
- type Options
- type ProvidedData
- type QuonfigHandler
- type QuonfigLeveler
- type Rule
- type RuleSet
- type SchemaData
- type Value
- func (v Value) BoolValue() bool
- func (v Value) DoubleValue() float64
- func (v Value) IntValue() int64
- func (v Value) ProvidedValue() *ProvidedData
- func (v Value) StringListValue() []string
- func (v Value) StringValue() string
- func (v *Value) UnmarshalJSON(data []byte) error
- func (v Value) WeightedValuesValue() *WeightedValuesData
- type ValueResolver
- type ValueType
- type WeightedValue
- type WeightedValuesData
Constants ¶
const DefaultDataDirAutoReloadDebounce = 200 * time.Millisecond
DefaultDataDirAutoReloadDebounce is the default debounce window used to coalesce filesystem-event bursts (atomic-rename saves, git pull, etc.).
const DefaultDomain = "quonfig.com"
DefaultDomain is the production domain used when QUONFIG_DOMAIN is unset and no explicit URL options are provided.
const DefaultFallbackPollInterval = 60 * time.Second
DefaultFallbackPollInterval is the cadence used once Layer 2 has engaged. Matches the legacy WithRefreshInterval recommendation; callers can override.
const DefaultFallbackPollThreshold = 120 * time.Second
DefaultFallbackPollThreshold is the disconnect window before Layer 2 engages. The cross-SDK spec calls for 120s; tests inject smaller values.
const QuonfigSDKLoggingContextName = "quonfig-sdk-logging"
QuonfigSDKLoggingContextName is the top-level context name used by the ShouldLogPath convenience to inject the logger path for per-logger rule evaluation. It is load-bearing for api-telemetry's example-context auto-capture, so do not rename without updating the matching constants in the other SDKs.
Variables ¶
var ErrInitializationTimeout = errors.New("initialization_timeout")
ErrInitializationTimeout is returned when the client could not finish its initial fetch before the configured timeout.
var ErrMissingEnvVar = errors.New("missing_env_var")
ErrMissingEnvVar is returned when an ENV_VAR-provided config references a missing environment variable.
var ErrNotFound = errors.New("config not found")
ErrNotFound is returned when a config key does not exist.
var ErrUnableToCoerce = errors.New("unable_to_coerce_env_var")
ErrUnableToCoerce is returned when an ENV_VAR-provided config cannot be coerced to the target type.
var ErrUnableToDecrypt = errors.New("unable_to_decrypt")
ErrUnableToDecrypt is returned when a confidential value cannot be decrypted.
Functions ¶
func ContextWithContextSet ¶
func ContextWithContextSet(ctx context.Context, cs *ContextSet) context.Context
ContextWithContextSet returns a derived context carrying the given *ContextSet. QuonfigHandler.Handle pulls this ContextSet out and passes it to Client.ShouldLogPath, on top of the Client's GlobalContext. nil is a valid value and clears any previously attached ContextSet.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the main Quonfig SDK client.
func NewClient ¶
NewClient creates a new Quonfig client with the given options. If an API key is configured, the client begins an initial config download and wires local evaluation automatically. Background refresh is opt-in via WithFallbackPoll (the legacy WithRefreshInterval is preserved as a shim).
func (*Client) Close ¶
func (c *Client) Close()
Close stops the supervised background workers, shuts down the SSE stream, and flushes pending telemetry.
func (*Client) ConnectionState ¶ added in v0.0.21
func (c *Client) ConnectionState() ConnectionState
ConnectionState reports the SDK's customer-visible transport state. Values match the cross-SDK spec in project/plans/sdk-hardening-and-verification.md: initializing, connected, disconnected, falling_back. Returns "initializing" when background workers are disabled (e.g. WithDataDir, no API key).
func (*Client) EvaluateDetails ¶ added in v0.0.20
func (c *Client) EvaluateDetails(key string, ctx *ContextSet) EvaluationDetails
EvaluateDetails resolves a config key and returns a full EvaluationDetails record including typed ErrorCode, ErrorMessage, Variant, and FlagMetadata. This is the recommended API for OpenFeature providers and any caller that needs structured evaluation metadata.
func (*Client) EvaluateKey ¶
func (c *Client) EvaluateKey(key string, ctx *ContextSet) (*Value, EvalReason, bool, error)
EvaluateKey resolves a config key and returns the resolved value, evaluation reason, and ok flag. Retained for backward compatibility; new code should prefer EvaluateDetails which returns the full EvaluationDetails record (typed ErrorCode, Variant, FlagMetadata).
func (*Client) FallbackPollerActive ¶ added in v0.0.21
FallbackPollerActive reports whether the Layer 2 fallback poller is currently engaged (i.e. SSE has been down past the engagement threshold and the SDK is polling instead). Returns false when fallback polling is disabled or has not engaged.
func (*Client) FeatureIsOn ¶
func (c *Client) FeatureIsOn(key string, ctx *ContextSet) (bool, bool)
FeatureIsOn returns whether a feature flag is on. Returns false if the key is not found.
func (*Client) GetBoolValue ¶
GetBoolValue returns the bool value for a config key.
func (*Client) GetDurationValue ¶
GetDurationValue returns the time.Duration value for a config key. The stored value should be an ISO 8601 duration string (e.g., "PT90S", "PT1.5M", "P1DT6H2M1.5S").
func (*Client) GetFloatValue ¶
GetFloatValue returns the float64 value for a config key.
func (*Client) GetIntValue ¶
GetIntValue returns the int64 value for a config key.
func (*Client) GetJSONValue ¶
func (c *Client) GetJSONValue(key string, ctx *ContextSet) (interface{}, bool, error)
GetJSONValue returns the parsed JSON value for a config key. Values are stored natively (object/array/number/boolean/null); this is a direct pass-through of Value.Value.
func (*Client) GetStringSliceValue ¶
GetStringSliceValue returns the []string value for a config key.
func (*Client) GetStringValue ¶
GetStringValue returns the string value for a config key.
func (*Client) LastSuccessfulRefresh ¶ added in v0.0.21
LastSuccessfulRefresh returns the wall-clock time of the most recent successful config install (either path). Zero value before the first install or when background workers are disabled.
func (*Client) ShouldLog ¶
func (c *Client) ShouldLog(configKey string, desiredLevel string, ctx *ContextSet) bool
ShouldLog returns true if a message at desiredLevel should be logged for the given configKey. The caller must pass the full stored key (e.g. "log-level.my-app") — the SDK does not auto-prefix "log-level.". desiredLevel is case-insensitive (e.g. "debug", "INFO"). Returns true if no config is found (log everything by default).
func (*Client) ShouldLogPath ¶
func (c *Client) ShouldLogPath(loggerPath string, desiredLevel string, ctx *ContextSet) bool
ShouldLogPath returns true if a message at desiredLevel should be logged for the given loggerPath. It is a higher-level convenience on top of ShouldLog: it uses the Client's LoggerKey (set via WithLoggerKey or Options.LoggerKey) as the underlying config key, and injects loggerPath into ctx under contexts["quonfig-sdk-logging"] = { "key": loggerPath } so a single log-level config can drive per-logger overrides via the normal rule engine.
loggerPath is passed through verbatim — the SDK does not normalize it, so "MyApp::Services::Auth" stays as "MyApp::Services::Auth". 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.
Panics if the Client has no LoggerKey set. Use the existing ShouldLog(configKey, ...) primitive directly if you need a different error-handling policy or want to evaluate an ad-hoc config key.
func (*Client) WithContext ¶
func (c *Client) WithContext(ctx *ContextSet) *ContextBoundClient
WithContext returns a ContextBoundClient that merges the given context into every call.
type ConfigEnvelope ¶
type ConfigEnvelope struct {
Configs []ConfigResponse `json:"configs"`
Meta Meta `json:"meta"`
}
ConfigEnvelope is the response wrapper for config downloads.
type ConfigEvaluator ¶
type ConfigEvaluator interface {
// EvaluateConfigResponse evaluates a ConfigResponse for the given environment and context.
// Returns the full evaluation result including match metadata for telemetry and reasons.
EvaluateConfigResponse(cfg *ConfigResponse, envID string, ctx *ContextSet) *EvalResult
}
ConfigEvaluator evaluates a config against a context. This interface breaks the import cycle between quonfig and internal/eval.
type ConfigResponse ¶
type ConfigResponse struct {
ID string `json:"id"`
Key string `json:"key"`
Type ConfigType `json:"type"`
ValueType ValueType `json:"valueType"`
SendToClientSDK bool `json:"sendToClientSdk"`
Default RuleSet `json:"default"`
Environment *Environment `json:"environment,omitempty"`
}
ConfigResponse is a single config in the download response, filtered to one environment.
type ConfigType ¶
type ConfigType string
ConfigType represents the type of a config entry.
const ( ConfigTypeFeatureFlag ConfigType = "feature_flag" ConfigTypeConfig ConfigType = "config" ConfigTypeSegment ConfigType = "segment" ConfigTypeLogLevel ConfigType = "log_level" ConfigTypeSchema ConfigType = "schema" )
type ConnectionState ¶ added in v0.0.21
type ConnectionState string
ConnectionState is the customer-visible health surface; values match the cross-SDK spec in project/plans/sdk-hardening-and-verification.md.
const ( // ConnStateInitializing is the pre-Start state and the state during the // first connection attempt before any worker has reported success. ConnStateInitializing ConnectionState = "initializing" // ConnStateConnected means an SSE stream (Layer 1) is live. ConnStateConnected ConnectionState = "connected" // ConnStateDisconnected means the Layer 1 worker is between connection // attempts (after a drop, before the next reconnect succeeds). ConnStateDisconnected ConnectionState = "disconnected" // ConnStateFallingBack means Layer 1 is unable to maintain a connection // and the Layer 2 fallback poller is active. ConnStateFallingBack ConnectionState = "falling_back" )
type ContextBoundClient ¶
type ContextBoundClient struct {
// contains filtered or unexported fields
}
ContextBoundClient is a Client bound to a specific context.
func (*ContextBoundClient) FeatureIsOn ¶
func (cb *ContextBoundClient) FeatureIsOn(key string) (bool, bool)
FeatureIsOn returns whether a feature flag is on using the bound context.
func (*ContextBoundClient) GetBoolValue ¶
func (cb *ContextBoundClient) GetBoolValue(key string) (bool, bool, error)
GetBoolValue returns the bool value for a config key using the bound context.
func (*ContextBoundClient) GetDurationValue ¶
GetDurationValue returns the time.Duration value for a config key using the bound context.
func (*ContextBoundClient) GetFloatValue ¶
func (cb *ContextBoundClient) GetFloatValue(key string) (float64, bool, error)
GetFloatValue returns the float64 value for a config key using the bound context.
func (*ContextBoundClient) GetIntValue ¶
func (cb *ContextBoundClient) GetIntValue(key string) (int64, bool, error)
GetIntValue returns the int64 value for a config key using the bound context.
func (*ContextBoundClient) GetJSONValue ¶
func (cb *ContextBoundClient) GetJSONValue(key string) (interface{}, bool, error)
GetJSONValue returns the parsed JSON value for a config key using the bound context.
func (*ContextBoundClient) GetStringSliceValue ¶
func (cb *ContextBoundClient) GetStringSliceValue(key string) ([]string, bool, error)
GetStringSliceValue returns the []string value for a config key using the bound context.
func (*ContextBoundClient) GetStringValue ¶
func (cb *ContextBoundClient) GetStringValue(key string) (string, bool, error)
GetStringValue returns the string value for a config key using the bound context.
func (*ContextBoundClient) ShouldLog ¶
func (cb *ContextBoundClient) ShouldLog(configKey string, desiredLevel string) bool
ShouldLog returns true if a message at desiredLevel should be logged for the given configKey, using the bound context.
func (*ContextBoundClient) ShouldLogPath ¶
func (cb *ContextBoundClient) ShouldLogPath(loggerPath string, desiredLevel string) bool
ShouldLogPath returns true if a message at desiredLevel should be logged for the given loggerPath, using the bound context. See Client.ShouldLogPath for full semantics.
func (*ContextBoundClient) WithContext ¶
func (cb *ContextBoundClient) WithContext(ctx *ContextSet) *ContextBoundClient
WithContext returns a new ContextBoundClient with the given context merged in.
type ContextSet ¶
type ContextSet struct {
// contains filtered or unexported fields
}
ContextSet is a set of named contexts used for config evaluation.
func ContextSetFromContext ¶
func ContextSetFromContext(ctx context.Context) *ContextSet
ContextSetFromContext returns the *ContextSet previously attached with ContextWithContextSet, or nil if none is attached.
func Merge ¶
func Merge(sets ...*ContextSet) *ContextSet
Merge returns a new ContextSet that combines all provided context sets. Later sets take precedence over earlier ones for the same context name.
func (*ContextSet) GetContextValue ¶
func (cs *ContextSet) GetContextValue(propertyName string) (interface{}, bool)
GetContextValue looks up a value by dotted property name. The part before the first dot is the context name; the part after is the key within that context. If there is no dot, the unnamed ("") context is searched.
func (*ContextSet) SetNamedContext ¶
func (cs *ContextSet) SetNamedContext(nc *NamedContext)
SetNamedContext adds or replaces a named context.
func (*ContextSet) WithNamedContextValues ¶
func (cs *ContextSet) WithNamedContextValues(name string, values map[string]interface{}) *ContextSet
WithNamedContextValues adds or replaces a named context with the given values, returning the ContextSet for chaining.
type ContextTelemetryMode ¶
type ContextTelemetryMode string
ContextTelemetryMode controls what context data the SDK sends to the telemetry backend.
const ( // ContextTelemetryNone disables context telemetry. ContextTelemetryNone ContextTelemetryMode = "" // ContextTelemetryShapes sends only context field names and types. ContextTelemetryShapes ContextTelemetryMode = "shapes" // ContextTelemetryPeriodicExample sends context shapes and periodic example values. ContextTelemetryPeriodicExample ContextTelemetryMode = "periodic_example" )
type Criterion ¶
type Criterion struct {
PropertyName string `json:"propertyName,omitempty"`
Operator string `json:"operator"`
ValueToMatch *Value `json:"valueToMatch,omitempty"`
}
Criterion is a single condition in a rule.
type EnvLookupFunc ¶
EnvLookupFunc looks up an environment variable by name. Returns the value and whether it was found.
type Environment ¶
Environment is an environment-specific rule set.
type ErrorCode ¶ added in v0.0.20
type ErrorCode string
ErrorCode is a typed enumeration of evaluation error categories. Values mirror the OpenFeature spec's error codes so providers can forward them without inferring meaning from error message text.
const ( // ErrorCodeNone indicates a successful evaluation (no error). ErrorCodeNone ErrorCode = "" // ErrorCodeFlagNotFound indicates the requested key is not present in the store. ErrorCodeFlagNotFound ErrorCode = "FLAG_NOT_FOUND" // ErrorCodeTypeMismatch indicates a value could not be coerced to the requested type. ErrorCodeTypeMismatch ErrorCode = "TYPE_MISMATCH" // ErrorCodeProviderNotReady indicates the SDK has not finished initialization. ErrorCodeProviderNotReady ErrorCode = "PROVIDER_NOT_READY" // ErrorCodeGeneral covers errors that don't fit the more specific categories // (missing env vars, decryption failures, etc.). ErrorCodeGeneral ErrorCode = "GENERAL" )
type EvalReason ¶
type EvalReason int
EvalReason describes why a particular value was returned from evaluation. Maps to OpenFeature evaluation reasons and the telemetry payload's reason field.
const ( // ReasonUnknown is the zero value; used when reason is not determined. ReasonUnknown EvalReason = 0 // ReasonStatic means the config has no targeting rules -- just a static value. ReasonStatic EvalReason = 1 // ReasonTargetingMatch means a rule's criteria matched the evaluation context. ReasonTargetingMatch EvalReason = 2 // ReasonSplit means a weighted value (A/B test) was resolved. ReasonSplit EvalReason = 3 // ReasonDefault means the SDK-provided default was returned (no match or error). ReasonDefault EvalReason = 4 // ReasonError means evaluation failed (type mismatch, missing config, etc.). ReasonError EvalReason = 5 )
func (EvalReason) String ¶
func (r EvalReason) String() string
String returns the OpenFeature-compatible reason string.
type EvalResult ¶
type EvalResult struct {
Value *Value
ConfigID string
ConfigKey string
ConfigType ConfigType
RuleIndex int
WeightedValueIndex int
Reason EvalReason
IsMatch bool
}
EvalResult is the internal result of evaluating a config, carrying full metadata needed for telemetry reporting and (future) OpenFeature evaluation details.
type EvaluationDetails ¶ added in v0.0.20
type EvaluationDetails struct {
// Value is the resolved value, or nil on error / not-found.
Value *Value
// Reason describes why this value was returned.
Reason EvalReason
// ErrorCode is the typed error category. Empty (ErrorCodeNone) on success.
ErrorCode ErrorCode
// ErrorMessage is a human-readable error description. Empty on success.
ErrorMessage string
// Variant is the OpenFeature-style variant identifier (e.g. "static",
// "targeting:0", "split:1", "default"). Always set, never empty.
Variant string
// FlagMetadata carries provider-specific data (configId, configType,
// environment, ruleIndex, weightedValueIndex). Always non-nil; keys
// follow camelCase (Go idiom) per the cross-SDK spec.
FlagMetadata map[string]any
}
EvaluationDetails is the public, OpenFeature-shaped record of an evaluation. It bundles the resolved Value with the reason, typed error code, variant, and flagMetadata so callers (and OpenFeature providers) can populate ProviderResolutionDetail without inferring fields from error message text.
type Meta ¶
type Meta struct {
Version string `json:"version"`
Environment string `json:"environment"`
WorkspaceID string `json:"workspaceId,omitempty"`
}
Meta holds response metadata.
type NamedContext ¶
NamedContext is a named context providing key-value data about a user, team, device, etc.
type OnInitFailure ¶
type OnInitFailure int
OnInitFailure controls behavior when initialization times out.
const ( // ReturnError causes getter methods to return an error if initialization times out. ReturnError OnInitFailure = iota // ReturnZeroValue causes getter methods to return zero values if initialization times out. ReturnZeroValue )
type Option ¶
Option is a functional option for configuring the Client.
func WithAPIKey ¶
WithAPIKey sets the API key for authentication.
func WithAPIURLs ¶
WithAPIURLs sets an ordered list of base URLs for the Quonfig API. The client tries each URL in order, falling back to the next on failure. Setting this option is treated as an explicit override and takes precedence over the QUONFIG_DOMAIN env var.
func WithAllTelemetryDisabled ¶
func WithAllTelemetryDisabled() Option
WithAllTelemetryDisabled disables all telemetry collection.
func WithCollectEvaluationSummaries ¶
WithCollectEvaluationSummaries enables or disables evaluation summary telemetry.
func WithContextTelemetryMode ¶
func WithContextTelemetryMode(mode ContextTelemetryMode) Option
WithContextTelemetryMode sets the context telemetry mode.
func WithDataDir ¶
WithDataDir sets the local Quonfig workspace directory to load from disk.
func WithDataDirAutoReload ¶ added in v0.0.24
WithDataDirAutoReload enables filesystem watching for the configured DataDir. Default false — datadir mode is silent until you opt in.
When enabled, the SDK walks the resolved datadir at startup, registers every subdirectory with fsnotify, debounces filesystem-event bursts (default DefaultDataDirAutoReloadDebounce, 200ms — tune with WithDataDirAutoReloadDebounce), then re-reads the workspace, parses it, and atomically swaps in the new envelope on success. The existing OnConfigUpdate callback fires on each successful swap; on parse failure the SDK keeps serving the previous envelope and the callback is NOT fired.
Symlinks are resolved once at Start via filepath.EvalSymlinks — editing the file the symlink points at is detected, but atomic flips that retarget the symlink itself are not.
Graceful degrade: if watch registration fails (read-only filesystem, immutable container, missing directory, EMFILE), the SDK logs at WARN via the configured WithLogger and continues serving the envelope it loaded at NewClient. It never panics on a watcher failure and NewClient does not return an error from a failed registration.
Shutdown: Client.Close stops the watcher goroutine, releases the underlying fsnotify handle, and clears any pending debounce timer. There is no separate handle to manage — the watcher lifecycle is tied to the client.
func WithDataDirAutoReloadDebounce ¶ added in v0.0.24
WithDataDirAutoReloadDebounce tunes how long the watcher waits after the most recent filesystem event before re-reading the datadir. Bursts of events (atomic-rename editor saves, `git pull` touching dozens of files) coalesce into a single re-read inside this window.
Defaults to DefaultDataDirAutoReloadDebounce (200ms) — long enough to absorb the 3–5 events typical editors emit in <50ms, short enough that interactive edits feel immediate. Raise it if you have a noisy producer (continuously regenerating files) and would rather see one reload per second than per save. Lower it only if you have measured 200ms is meaningfully too slow.
Has no effect unless WithDataDirAutoReload(true) is also set. A negative duration is rejected at option-apply time; zero falls back to the default.
func WithEnvLookup ¶
func WithEnvLookup(fn EnvLookupFunc) Option
WithEnvLookup sets a custom environment variable lookup function. By default, os.LookupEnv is used. This is useful for testing.
func WithEnvironment ¶
WithEnvironment sets the environment ID/name used when loading from a local data dir.
func WithFallbackPoll ¶ added in v0.0.21
WithFallbackPoll configures the Layer 2 fallback poller. The poller is idle while the SSE stream is connected; it engages only after SSE has been disconnected for the default 120s threshold, and ticks at the given interval until SSE recovers. Pass enabled=false to disable Layer 2 entirely (the default).
Replaces the deprecated WithRefreshInterval, which ran parallel polling on top of SSE.
func WithGlobalContext ¶
func WithGlobalContext(ctx *ContextSet) Option
WithGlobalContext sets the global context that is merged into every evaluation.
func WithHTTPClient ¶
WithHTTPClient overrides the HTTP client used for config downloads.
func WithInitTimeout ¶
WithInitTimeout sets how long to wait for initial config loading before applying the OnInitFailure policy.
func WithLogger ¶
WithLogger sets the *slog.Logger the SDK uses to emit warnings. When unset, the SDK falls back to slog.Default(). Symmetric with WithHTTPClient: pass the highest-level convenience type so callers who want a custom handler can do slog.New(myHandler) themselves.
Note: this is distinct from WithLoggerKey, which configures the per-logger log-level config key consumed by ShouldLogPath.
func WithLoggerKey ¶
WithLoggerKey sets the config key used by ShouldLogPath to look up a per-logger level rule (e.g. "log-level.my-app"). When set, callers can use ShouldLogPath(loggerPath, desiredLevel, ctx) and the SDK evaluates LoggerKey with contexts["quonfig-sdk-logging"] = { "key": loggerPath } merged into ctx. The existing ShouldLog(configKey, ...) primitive does not require this option.
func WithOnConfigUpdate ¶
func WithOnConfigUpdate(fn func()) Option
WithOnConfigUpdate sets a callback function that is called whenever the client receives and installs a new config envelope. This is useful for OpenFeature providers and other integrations that need to emit change events.
func WithOnInitFailure ¶
func WithOnInitFailure(f OnInitFailure) Option
WithOnInitFailure sets the behavior when initialization times out.
func WithQuonfigUserContext ¶
WithQuonfigUserContext enables (or disables) injecting quonfig-user.email from ~/.quonfig/tokens.json into GlobalContext on NewClient. Customer-supplied GlobalContext keys win on collision. Default off; the env var QUONFIG_DEV_CONTEXT=true also enables it when no explicit option is set.
func WithRefreshInterval
deprecated
WithRefreshInterval enables background polling refreshes.
Deprecated: prior to v0.0.21 this option ran PARALLEL polling on top of SSE. As of v0.0.21 the SDK polls fallback-only — the poller is idle while SSE is connected and engages only after SSE has been disconnected for >=120s. WithRefreshInterval(d) is preserved as a thin shim over WithFallbackPoll(true, d); new code should call WithFallbackPoll directly. A one-shot deprecation warning is logged at NewClient time so deployers can spot the call site.
func WithSSE ¶
WithSSE enables or disables the background SSE streaming client. Default is true. When disabled, the SDK relies on the initial HTTP fetch plus any polling configured via WithFallbackPoll. Note that fallback polling only engages after sustained SSE disconnect — with SSE disabled it effectively starts immediately, but you typically still want WithFallbackPoll(true, …) to make poll cadence explicit.
func WithSSEStateCallback ¶
WithSSEStateCallback registers a function that is invoked whenever the background SSE stream transitions between connected and disconnected. The callback receives true when a stream is live and false when it is not. Useful for emitting accurate connection-health metrics.
func WithTelemetrySyncInterval ¶
WithTelemetrySyncInterval sets how often telemetry is submitted to the backend.
func WithTelemetryURL ¶
WithTelemetryURL sets the telemetry ingestion endpoint. Setting this option is treated as an explicit override and takes precedence over the QUONFIG_DOMAIN env var.
type Options ¶
type Options struct {
APIKey string
APIURLs []string
DataDir string
Environment string
GlobalContext *ContextSet
InitTimeout time.Duration
OnInitFailure OnInitFailure
EnvLookup EnvLookupFunc
HTTPClient *http.Client
// FallbackPollEnabled controls whether the Layer 2 fallback poller is
// allowed to engage. The poller is idle while SSE is connected; it
// engages only after SSE has been disconnected for FallbackPollThreshold
// (default 120s) and ticks at FallbackPollInterval until SSE recovers.
//
// Default false: an SSE-only deployment trusts the stream and accepts
// degraded freshness during outages. Set true (and pick an interval) to
// guarantee a poll-based refresh path during sustained disconnects.
FallbackPollEnabled bool
// FallbackPollInterval is how often the Layer 2 poller fetches once
// engaged. Must be >0 when FallbackPollEnabled is true. Defaults to 60s.
FallbackPollInterval time.Duration
// Logger is the *slog.Logger used by the SDK to emit warnings (e.g. the
// dev-context tokens loader). Defaults to slog.Default() when not set via
// WithLogger. Internal helpers/goroutines that may emit warnings should
// read from this field rather than calling slog.Default() directly so a
// host app can route SDK output through its own handler.
Logger *slog.Logger
// OnConfigUpdate is called whenever the client installs a new config envelope
// (i.e. after a successful fetch or data-dir load). It is called with the
// client's internal mutex NOT held, so it is safe to call client methods
// from within the callback.
OnConfigUpdate func()
// DataDirAutoReload enables filesystem watching when DataDir is set. The
// SDK re-reads the datadir whenever a file inside changes, atomically
// swaps the envelope on a successful parse, and fires OnConfigUpdate.
// Default false — opt in for dev / git-pull workflows.
DataDirAutoReload bool
// DataDirAutoReloadDebounce coalesces filesystem-event bursts (atomic-rename
// editor saves, git pull touching dozens of files). The SDK waits this long
// after the most recent event before re-reading. Zero means use
// DefaultDataDirAutoReloadDebounce (200ms).
DataDirAutoReloadDebounce time.Duration
// SSEEnabled controls whether a background SSE streamer is opened after
// initialization. Default true. Set false for pure HTTP-poll behavior.
// When DataDir is set (local dev) or no APIKey is configured, SSE is a
// no-op regardless of this flag.
SSEEnabled bool
// OnSSEStateChange, if non-nil, is invoked whenever the background SSE
// connection transitions between connected=true and connected=false.
// Useful for emitting accurate "stream is up" metrics on the caller's
// side (see load-gen's load_gen.sse_connected gauge). The callback may
// run on any goroutine and should be cheap / non-blocking.
OnSSEStateChange func(connected bool)
// LoggerKey is the config key used by Client.ShouldLogPath to look up a
// per-logger level rule (e.g. "log-level.my-app"). When set, callers can
// use the higher-level ShouldLogPath(loggerPath, ...) convenience, which
// injects loggerPath into the evaluation context as
// contexts["quonfig-sdk-logging"] = { "key": loggerPath } so a single
// log-level config can drive per-logger overrides.
LoggerKey string
// EnableQuonfigUserContext, when true, makes NewClient read
// ~/.quonfig/tokens.json (written by `qfg login`) and merge
// { "quonfig-user": { "email": <userEmail> } } into GlobalContext under
// any caller-supplied keys. Default false. The env var
// QUONFIG_DEV_CONTEXT=true also enables it. Production servers do not
// have the tokens file, so this is a no-op there by construction.
EnableQuonfigUserContext bool
// Telemetry options
CollectEvaluationSummaries bool
ContextTelemetryMode ContextTelemetryMode
TelemetrySyncInterval time.Duration
TelemetryURL string
// contains filtered or unexported fields
}
Options holds all client configuration.
func (*Options) TelemetryEnabled ¶
TelemetryEnabled returns true if a TelemetryURL is configured and any telemetry collection is enabled.
type ProvidedData ¶
ProvidedData holds the source info for ENV_VAR-provided values.
type QuonfigHandler ¶
type QuonfigHandler struct {
// contains filtered or unexported fields
}
QuonfigHandler is a slog.Handler that gates records through Quonfig's dynamic per-logger level configuration. It wraps another slog.Handler (supplied by the caller, e.g. slog.NewJSONHandler(os.Stdout, nil)) and suppresses records whose level is below the Quonfig-configured level for the handler's loggerPath.
Enabled, WithAttrs, and WithGroup delegate to the inner handler; Handle consults Client.ShouldLogPath before forwarding.
func NewQuonfigHandler ¶
func NewQuonfigHandler(client *Client, inner slog.Handler, loggerPath string) *QuonfigHandler
NewQuonfigHandler returns a QuonfigHandler bound to the given client and loggerPath. The loggerPath is passed through verbatim to ShouldLogPath — no normalization is applied, so rules may match the caller's native identifier shape (dotted, colon-delimited, slashed, etc.).
Panics if client.opts.LoggerKey is empty. Configure it with quonfig.WithLoggerKey("log-level.my-app") when constructing the Client.
func (*QuonfigHandler) Enabled ¶
Enabled reports whether the handler should process a record at the given level. It consults Quonfig via ShouldLogPath; if Quonfig says no, slog will skip record construction entirely, which is the cheap pre-filter the slog API is designed around.
func (*QuonfigHandler) Handle ¶
Handle forwards a record to the inner handler if Quonfig says this record's level should log. This is belt-and-suspenders with Enabled: a caller that builds records by hand or bypasses slog.Logger still gets gated.
type QuonfigLeveler ¶
type QuonfigLeveler struct {
// contains filtered or unexported fields
}
QuonfigLeveler is a slog.Leveler backed by Quonfig's dynamic per-logger level configuration. Hand it to slog.HandlerOptions.Level to have slog's built-in handlers pre-filter based on the current Quonfig-configured level for loggerPath.
Level() is called on every record, so every record sees fresh configuration — flipping a level in the Quonfig UI takes effect immediately after the client's next config refresh, with no logger rebuild needed.
func NewQuonfigLeveler ¶
func NewQuonfigLeveler(client *Client, loggerPath string) *QuonfigLeveler
NewQuonfigLeveler returns a QuonfigLeveler bound to the given client and loggerPath. Panics if client.opts.LoggerKey is empty.
Note: QuonfigLeveler does NOT thread a context.Context through to the Quonfig evaluator — slog.HandlerOptions.Level is contextless. If your rules depend on per-request context (tenant, user, etc.), use QuonfigHandler instead and attach a ContextSet via ContextWithContextSet.
func (*QuonfigLeveler) Level ¶
func (l *QuonfigLeveler) Level() slog.Level
Level returns the current slog.Level for the bound loggerPath, derived by reading the Client's LoggerKey config with the logger-path context injected. Unknown/missing config falls back to INFO.
type RuleSet ¶
type RuleSet struct {
Rules []Rule `json:"rules"`
}
RuleSet is a collection of rules (tried top to bottom, first match wins).
type SchemaData ¶
SchemaData holds schema validation data.
type Value ¶
type Value struct {
Type ValueType `json:"type"`
Value interface{} `json:"value"`
Confidential bool `json:"confidential,omitempty"`
DecryptWith string `json:"decryptWith,omitempty"`
}
Value is the universal value wrapper.
func (Value) DoubleValue ¶
DoubleValue returns the value as float64, or 0.
func (Value) ProvidedValue ¶
func (v Value) ProvidedValue() *ProvidedData
ProvidedValue returns the provided data, or nil.
func (Value) StringListValue ¶
StringListValue returns the value as []string, or nil.
func (Value) StringValue ¶
StringValue returns the value as string, or "".
func (*Value) UnmarshalJSON ¶
UnmarshalJSON handles the polymorphic value field.
func (Value) WeightedValuesValue ¶
func (v Value) WeightedValuesValue() *WeightedValuesData
WeightedValuesValue returns the weighted values data, or nil.
type ValueResolver ¶
type ValueResolver interface {
// ResolveValue resolves a matched value, handling ENV_VAR provided values and decryption.
// The configKey and valueType are used for coercion and error messages.
ResolveValue(val *Value, configKey string, valueType ValueType, envID string, ctx *ContextSet) (*Value, error)
}
ValueResolver resolves a matched value (e.g., ENV_VAR lookup, decryption).
type ValueType ¶
type ValueType string
ValueType represents the type of a config value.
const ( ValueTypeBool ValueType = "bool" ValueTypeInt ValueType = "int" ValueTypeDouble ValueType = "double" ValueTypeString ValueType = "string" ValueTypeJSON ValueType = "json" ValueTypeStringList ValueType = "string_list" ValueTypeLogLevel ValueType = "log_level" ValueTypeWeightedValues ValueType = "weighted_values" ValueTypeSchema ValueType = "schema" ValueTypeProvided ValueType = "provided" ValueTypeDuration ValueType = "duration" )
type WeightedValue ¶
WeightedValue is a single entry in a weighted distribution.
type WeightedValuesData ¶
type WeightedValuesData struct {
WeightedValues []WeightedValue `json:"weightedValues"`
HashByPropertyName string `json:"hashByPropertyName,omitempty"`
}
WeightedValuesData holds weighted distribution data for A/B tests.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package evalcore provides the shared evaluation engine used by sdk-go and api-delivery.
|
Package evalcore provides the shared evaluation engine used by sdk-go and api-delivery. |
|
internal
|
|
|
resolver
Package resolver handles post-evaluation value resolution including environment variable lookup, type coercion, and decryption of confidential values.
|
Package resolver handles post-evaluation value resolution including environment variable lookup, type coercion, and decryption of confidential values. |
|
version
Package version exposes the SDK module version for telemetry and HTTP headers.
|
Package version exposes the SDK module version for telemetry and HTTP headers. |