diff --git a/featureflag/config.go b/featureflag/config.go index 8cd14e8..0cef4e7 100644 --- a/featureflag/config.go +++ b/featureflag/config.go @@ -17,4 +17,8 @@ type Config struct { // Set when using the Launch Darkly Relay proxy RelayHost string `json:"relay_host" yaml:"relay_host" mapstructure:"relay_host" split_words:"true"` + + // DefaultUserAttrs are custom LaunchDarkly user attributes that are added to every + // feature flag check + DefaultUserAttrs map[string]string `json:"default_user_attrs" yaml:"default_user_attrs"` } diff --git a/featureflag/featureflag.go b/featureflag/featureflag.go index eae85a4..bea8d1f 100644 --- a/featureflag/featureflag.go +++ b/featureflag/featureflag.go @@ -5,15 +5,16 @@ import ( "github.com/sirupsen/logrus" + "gopkg.in/launchdarkly/go-sdk-common.v1/ldvalue" ld "gopkg.in/launchdarkly/go-server-sdk.v4" "gopkg.in/launchdarkly/go-server-sdk.v4/ldlog" ) type Client interface { - Enabled(key, userID string) bool + Enabled(key, userID string, attrs ...Attr) bool EnabledUser(key string, user ld.User) bool - Variation(key, defaultVal, userID string) string + Variation(key, defaultVal, userID string, attrs ...Attr) string VariationUser(key string, defaultVal string, user ld.User) string AllEnabledFlags(key string) []string @@ -22,7 +23,8 @@ type Client interface { type ldClient struct { *ld.LDClient - log logrus.FieldLogger + log logrus.FieldLogger + defaultAttrs []Attr } var _ Client = &ldClient{} @@ -55,11 +57,16 @@ func NewClient(cfg *Config, logger logrus.FieldLogger) (Client, error) { if err != nil { logger.WithError(err).Error("Unable to construct LD client") } - return &ldClient{inner, logger}, err + + var defaultAttrs []Attr + for k, v := range cfg.DefaultUserAttrs { + defaultAttrs = append(defaultAttrs, StringAttr(k, v)) + } + return &ldClient{inner, logger, defaultAttrs}, err } -func (c *ldClient) Enabled(key string, userID string) bool { - return c.EnabledUser(key, ld.NewUser(userID)) +func (c *ldClient) Enabled(key string, userID string, attrs ...Attr) bool { + return c.EnabledUser(key, c.userWithAttrs(userID, attrs)) } func (c *ldClient) EnabledUser(key string, user ld.User) bool { @@ -70,8 +77,8 @@ func (c *ldClient) EnabledUser(key string, user ld.User) bool { return res } -func (c *ldClient) Variation(key, defaultVal, userID string) string { - return c.VariationUser(key, defaultVal, ld.NewUser(userID)) +func (c *ldClient) Variation(key, defaultVal, userID string, attrs ...Attr) string { + return c.VariationUser(key, defaultVal, c.userWithAttrs(userID, attrs)) } func (c *ldClient) VariationUser(key string, defaultVal string, user ld.User) string { @@ -103,6 +110,26 @@ func (c *ldClient) AllEnabledFlagsUser(key string, user ld.User) []string { return flags } +func (c *ldClient) userWithAttrs(id string, attrs []Attr) ld.User { + b := ld.NewUserBuilder(id) + for _, attr := range c.defaultAttrs { + b.Custom(attr.Name, attr.Value) + } + for _, attr := range attrs { + b.Custom(attr.Name, attr.Value) + } + return b.Build() +} + +type Attr struct { + Name string + Value ldvalue.Value +} + +func StringAttr(name, value string) Attr { + return Attr{Name: name, Value: ldvalue.String(value)} +} + func configureLogger(ldLogger *ldlog.Loggers, log logrus.FieldLogger) { if log == nil { l := logrus.New() diff --git a/featureflag/global.go b/featureflag/global.go index a733d30..8630666 100644 --- a/featureflag/global.go +++ b/featureflag/global.go @@ -34,10 +34,10 @@ func Init(conf Config, log logrus.FieldLogger) error { return nil } -func Enabled(key, userID string) bool { - return GetGlobalClient().Enabled(key, userID) +func Enabled(key, userID string, attrs ...Attr) bool { + return GetGlobalClient().Enabled(key, userID, attrs...) } -func Variation(key, defaultVal, userID string) string { - return GetGlobalClient().Variation(key, defaultVal, userID) +func Variation(key, defaultVal, userID string, attrs ...Attr) string { + return GetGlobalClient().Variation(key, defaultVal, userID, attrs...) } diff --git a/featureflag/mock.go b/featureflag/mock.go index 4ae0168..929c847 100644 --- a/featureflag/mock.go +++ b/featureflag/mock.go @@ -11,7 +11,7 @@ type MockClient struct { var _ Client = MockClient{} -func (c MockClient) Enabled(key, userID string) bool { +func (c MockClient) Enabled(key, userID string, _ ...Attr) bool { return c.EnabledUser(key, ld.NewUser(userID)) } @@ -19,7 +19,7 @@ func (c MockClient) EnabledUser(key string, _ ld.User) bool { return c.BoolVars[key] } -func (c MockClient) Variation(key string, defaultVal string, userID string) string { +func (c MockClient) Variation(key string, defaultVal string, userID string, _ ...Attr) string { return c.VariationUser(key, defaultVal, ld.NewUser(userID)) }