package ffclient import ( "context" "errors" "log" "log/slog" "sync" "time" "github.com/thomaspoignant/go-feature-flag/notifier" "github.com/thomaspoignant/go-feature-flag/retriever" "github.com/thomaspoignant/go-feature-flag/utils/fflog" ) // Config is the configuration of go-feature-flag. // You should also have a retriever to specify where to read the flags file. type Config struct { // PollingInterval (optional) Poll every X time // The minimum possible is 1 second // Default: 60 seconds PollingInterval time.Duration // EnablePollingJitter (optional) set to true if you want to avoid having true periodicity when // retrieving your flags. It is useful to avoid having spike on your flag configuration storage // in case your application is starting multiple instance at the same time. // We ensure a deviation that is maximum + or - 10% of your polling interval. // Default: false EnablePollingJitter bool // DisableNotifierOnInit (optional) set to true if you do not want to call any notifier // when the flags are loaded. // This is useful if you do not want a Slack/Webhook notification saying that // the flags have been added every time you start the application. // Default is set to false for backward compatibility. // Default: false DisableNotifierOnInit bool // Deprecated: Use LeveledLogger instead // Logger (optional) logger use by the library // Default: No log Logger *log.Logger // LeveledLogger (optional) logger use by the library // Default: No log LeveledLogger *slog.Logger // Context (optional) used to call other services (HTTP, S3 ...) // Default: context.Background() Context context.Context // Environment (optional) can be checked in feature flag rules // Default: "" Environment string // Retriever is the component in charge to retrieve your flag file Retriever retriever.Retriever // Retrievers is the list of components in charge to retrieving your flag files. // We are dealing with config files in order, if you have the same flag name in multiple files it will be override // based of the order of the retrievers in the slice. // // Note: If both Retriever and Retrievers are set, we will start by calling the Retriever and, // after we will use the order of Retrievers. Retrievers []retriever.Retriever // Notifiers (optional) is the list of notifiers called when a flag change Notifiers []notifier.Notifier // FileFormat (optional) is the format of the file to retrieve (available YAML, TOML and JSON) // Default: YAML FileFormat string // DataExporter (optional) is the configuration where we store how we should output the flags variations results DataExporter DataExporter // StartWithRetrieverError (optional) If true, the SDK will start even if we did not get any flags from the retriever. // It will serve only default values until all the retrievers returns the flags. // The init method will not return any error if the flag file is unreachable. // Default: false StartWithRetrieverError bool // Offline (optional) If true, the SDK will not try to retrieve the flag file and will not export any data. // No notification will be sent neither. // Default: false Offline bool // EvaluationContextEnrichment (optional) will be merged with the evaluation context sent during the evaluation. // It is useful to add common attributes to all the evaluation, such as a server version, environment, ... // // All those fields will be included in the custom attributes of the evaluation context, // if in the evaluation context you have a field with the same name, it will override the common one. // Default: nil EvaluationContextEnrichment map[string]interface{} // PersistentFlagConfigurationFile (optional) if set GO Feature Flag will store flags configuration in this file // to be able to serve the flags even if none of the retrievers is available during starting time. // // By default, the flag configuration is not persisted and stays on the retriever system. By setting a file here, // you ensure that GO Feature Flag will always start with a configuration but which can be out-dated. PersistentFlagConfigurationFile string // offlineMutex is a mutex to protect the Offline field. offlineMutex *sync.RWMutex // internalLogger is the logger used by the library everywhere // this logger is a superset of the logging system to be able to migrate easily to slog. internalLogger *fflog.FFLogger } // GetRetrievers returns a retriever.Retriever configure with the retriever available in the config. func (c *Config) GetRetrievers() ([]retriever.Retriever, error) { if c.Retriever == nil && len(c.Retrievers) == 0 { return nil, errors.New("no retriever in the configuration, impossible to get the flags") } retrievers := make([]retriever.Retriever, 0) // If we have both Retriever and Retrievers fields configured, we are 1st looking at what is available // in Retriever before looking at what is in Retrievers. if c.Retriever != nil { retrievers = append(retrievers, c.Retriever) } if len(c.Retrievers) > 0 { retrievers = append(retrievers, c.Retrievers...) } return retrievers, nil } // SetOffline set GO Feature Flag in offline mode. func (c *Config) SetOffline(control bool) { if c.offlineMutex == nil { c.offlineMutex = &sync.RWMutex{} } c.offlineMutex.Lock() defer c.offlineMutex.Unlock() c.Offline = control } // IsOffline return if the GO Feature Flag is in offline mode. func (c *Config) IsOffline() bool { if c.offlineMutex == nil { c.offlineMutex = &sync.RWMutex{} } c.offlineMutex.RLock() defer c.offlineMutex.RUnlock() return c.Offline }