HookDecorator

open class HookDecorator : Hook

A hook that wraps another hook, forwarding every stage to it. A subclass adds behavior to a hook without changing it, and is registered in place of the hook it wraps.

Every stage forwards to the wrapped hook, so a subclass overrides only the stages it changes, and calls super to forward the ones it does. The stages it leaves alone still reach the wrapped hook.

An override that never calls super stops forwarding that stage. For the identify and track stages that means a decorator swallows something it has no reason to: a DedupingHook inside such an override is never told to forget what it has reported, and goes on suppressing evaluations across an identify.

class FlagFilteringHook: HookDecorator {
    private let flagKeys: Set<LDFlagKey>

    init(_ delegate: Hook, flagKeys: Set<LDFlagKey>) {
        self.flagKeys = flagKeys
        super.init(delegate)
    }

    override func beforeEvaluation(seriesContext: EvaluationSeriesContext,
                                   seriesData: EvaluationSeriesData) -> EvaluationSeriesData {
        guard flagKeys.contains(seriesContext.flagKey)
        else { return seriesData }
        return super.beforeEvaluation(seriesContext: seriesContext, seriesData: seriesData)
    }
}

That hook filters evaluations and still forwards identify and track, which it never mentions.

DedupingHook is the decorator the SDK ships: it forwards an evaluation series only when the flag’s result is one its hook has not just been told about.

Decorators stack, so a hook may be wrapped in as many as it needs, each wrapping the one inside it:

config.hooks = [DedupingHook(FlagFilteringHook(ObservabilityHook(), flagKeys: myFlagKeys))]

A decorator reports the wrapped hook’s metadata as its own, so the SDK names the hook that a stage belongs to rather than the wrappers around it.

A decorator that suppresses a stage must suppress the whole evaluation series, because hooks pair their stages: an observability hook opens a span in beforeEvaluation and closes it in afterEvaluation, so suppressing only the after stage leaves that span open. To carry the decision from one stage to the other, return series data the after stage recognizes, the way DedupingHook does.

A decorator that does that belongs outermost, because the series data it returns replaces what it was given: a decorator outside it does not get back what it stored in its own before stage.

This class is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. It is experimental.