From 7953ea984853029b43f582ecf9c26e06d792a65b Mon Sep 17 00:00:00 2001 From: Parth Suthar Date: Thu, 18 Apr 2024 11:46:12 -0400 Subject: [PATCH] chore: add client date --- api/model_bucketed_user_config.go | 1 + bucketing/bucketing.go | 26 ++++++++++++++------------ bucketing/bucketing_test.go | 11 +++++++---- bucketing/config_manager.go | 2 +- bucketing/datamanager_platform.go | 8 ++++++++ bucketing/event_queue.go | 28 ++++++++++++++++++++-------- bucketing/event_queue_test.go | 10 ++++++++-- bucketing/model_config_body.go | 4 ++-- client.go | 12 ++++++++++++ client_native_bucketing.go | 10 ++++++---- configmanager.go | 17 +++++++++++++++-- event_manager.go | 9 +++++---- example/cloud/main.go | 2 +- example/local/main.go | 24 ++++++++++++++++++------ 14 files changed, 118 insertions(+), 46 deletions(-) diff --git a/api/model_bucketed_user_config.go b/api/model_bucketed_user_config.go index 536b76df..09c2e915 100644 --- a/api/model_bucketed_user_config.go +++ b/api/model_bucketed_user_config.go @@ -8,6 +8,7 @@ type BucketedUserConfig struct { VariableVariationMap map[string]FeatureVariation `json:"variableVariationMap"` Variables map[string]ReadOnlyVariable `json:"variables"` KnownVariableKeys []float64 `json:"knownVariableKeys"` + ETag string `json:"eTag"` User *User `json:"-"` } diff --git a/bucketing/bucketing.go b/bucketing/bucketing.go index f4d1bd19..9cdf0d08 100644 --- a/bucketing/bucketing.go +++ b/bucketing/bucketing.go @@ -209,13 +209,14 @@ func GenerateBucketedConfig(sdkKey string, user api.PopulatedUser, clientCustomD FeatureVariationMap: featureVariationMap, VariableVariationMap: variableVariationMap, Variables: variableMap, + ETag: config.eTag, }, nil } func VariableForUser(sdkKey string, user api.PopulatedUser, variableKey string, expectedVariableType string, eventQueue *EventQueue, clientCustomData map[string]interface{}) (variableType string, variableValue any, err error) { - variableType, variableValue, featureId, variationId, err := generateBucketedVariableForUser(sdkKey, user, variableKey, clientCustomData) + variableType, variableValue, featureId, variationId, clientUUID, configEtag, err := generateBucketedVariableForUser(sdkKey, user, variableKey, clientCustomData) if err != nil { - eventErr := eventQueue.QueueVariableDefaultedEvent(variableKey, BucketResultErrorToDefaultReason(err)) + eventErr := eventQueue.QueueVariableDefaultedEvent(variableKey, BucketResultErrorToDefaultReason(err), clientUUID, configEtag) if eventErr != nil { util.Warnf("Failed to queue variable defaulted event: %s", eventErr) } @@ -224,16 +225,17 @@ func VariableForUser(sdkKey string, user api.PopulatedUser, variableKey string, if !isVariableTypeValid(variableType, expectedVariableType) && expectedVariableType != "" { err = ErrInvalidVariableType - eventErr := eventQueue.QueueVariableDefaultedEvent(variableKey, BucketResultErrorToDefaultReason(err)) + eventErr := eventQueue.QueueVariableDefaultedEvent(variableKey, BucketResultErrorToDefaultReason(err), clientUUID, configEtag) if eventErr != nil { util.Warnf("Failed to queue variable defaulted event: %s", eventErr) } return "", nil, err } - eventErr := eventQueue.QueueVariableEvaluatedEvent(variableKey, featureId, variationId) + eventErr := eventQueue.QueueVariableEvaluatedEvent(variableKey, featureId, variationId, clientUUID, configEtag) if eventErr != nil { util.Warnf("Failed to queue variable evaluated event: %s", eventErr) + } return @@ -252,37 +254,37 @@ func isVariableTypeValid(variableType string, expectedVariableType string) bool return true } -func generateBucketedVariableForUser(sdkKey string, user api.PopulatedUser, key string, clientCustomData map[string]interface{}) (variableType string, variableValue any, featureId string, variationId string, err error) { +func generateBucketedVariableForUser(sdkKey string, user api.PopulatedUser, key string, clientCustomData map[string]interface{}) (variableType string, variableValue any, featureId string, variationId string, clientUUID string, configEtag string, err error) { config, err := getConfig(sdkKey) if err != nil { util.Warnf("Variable called before client initialized, returning default value") - return "", nil, "", "", ErrConfigMissing + return "", nil, "", "",clientCustomData["clientUUID"].(string), "", ErrConfigMissing } variable := config.GetVariableForKey(key) if variable == nil { err = ErrMissingVariable - return "", nil, "", "", err + return "", nil, "", "",clientCustomData["clientUUID"].(string), config.eTag, err } featForVariable := config.GetFeatureForVariableId(variable.Id) if featForVariable == nil { err = ErrMissingFeature - return "", nil, "", "", err + return "", nil, "", "", clientCustomData["clientUUID"].(string), config.eTag,err } th, err := doesUserQualifyForFeature(config, featForVariable, user, clientCustomData) if err != nil { - return "", nil, "", "", err + return "", nil, "", "", clientCustomData["clientUUID"].(string), config.eTag,err } variation, err := bucketUserForVariation(featForVariable, th) if err != nil { - return "", nil, "", "", err + return "", nil, "", "", clientCustomData["clientUUID"].(string), config.eTag, err } variationVariable := variation.GetVariableById(variable.Id) if variationVariable == nil { err = ErrMissingVariableForVariation - return "", nil, "", "", err + return "", nil, "", "",clientCustomData["clientUUID"].(string), config.eTag, err } - return variable.Type, variationVariable.Value, featForVariable.Id, variation.Id, nil + return variable.Type, variationVariable.Value, featForVariable.Id, variation.Id, clientCustomData["clientUUID"].(string), config.eTag, nil } func BucketResultErrorToDefaultReason(err error) (defaultReason string) { diff --git a/bucketing/bucketing_test.go b/bucketing/bucketing_test.go index 084eb783..3b75ad57 100644 --- a/bucketing/bucketing_test.go +++ b/bucketing/bucketing_test.go @@ -472,7 +472,9 @@ func TestClientData(t *testing.T) { // Ensure bucketed config has a feature variation map that's empty bucketedUserConfig, err := GenerateBucketedConfig("test", user, nil) require.NoError(t, err) - _, _, _, _, err = generateBucketedVariableForUser("test", user, "num-var", nil) + SetClientCustomData("test",map[string]interface{}{"clientUUID": "clientuuid"}) + + _, _, _, _,_,_, err = generateBucketedVariableForUser("test", user, "num-var", map[string]interface{}{"clientUUID": "clientuuid"}) require.ErrorContainsf(t, err, "does not qualify", "does not qualify") require.Equal(t, map[string]string{}, bucketedUserConfig.FeatureVariationMap) @@ -481,6 +483,7 @@ func TestClientData(t *testing.T) { clientCustomData := map[string]interface{}{ "favouriteFood": "NOT PIZZA!!", "favouriteDrink": "coffee", + "clientUUID":"clientuuid", } bucketedUserConfig, err = GenerateBucketedConfig("test", user, clientCustomData) @@ -489,7 +492,7 @@ func TestClientData(t *testing.T) { "614ef6aa473928459060721a": "615357cf7e9ebdca58446ed0", "614ef6aa475928459060721a": "615382338424cb11646d7667", }, bucketedUserConfig.FeatureVariationMap) - variableType, value, featureId, variationId, err := generateBucketedVariableForUser("test", user, "num-var", clientCustomData) + variableType, value, featureId, variationId, _, _, err := generateBucketedVariableForUser("test", user, "num-var", clientCustomData) require.Equal(t, VariableTypesNumber, variableType) require.Equal(t, "614ef6aa473928459060721a", featureId) require.Equal(t, "615357cf7e9ebdca58446ed0", variationId) @@ -512,7 +515,7 @@ func TestClientData(t *testing.T) { "614ef6aa473928459060721a": "615357cf7e9ebdca58446ed0", "614ef6aa475928459060721a": "615382338424cb11646d7667", }, bucketedUserConfig.FeatureVariationMap) - variableType, value, featureId, variationId, err = generateBucketedVariableForUser("test", userWithPrivateCustomData, "num-var", clientCustomData) + variableType, value, featureId, variationId, _,_, err = generateBucketedVariableForUser("test", userWithPrivateCustomData, "num-var", clientCustomData) require.Equal(t, VariableTypesNumber, variableType) require.Equal(t, "614ef6aa473928459060721a", featureId) require.Equal(t, "615357cf7e9ebdca58446ed0", variationId) @@ -573,7 +576,7 @@ func TestVariableForUser(t *testing.T) { err := SetConfig(test_config, "test", "") require.NoError(t, err) - variableType, value, featureId, variationId, err := generateBucketedVariableForUser("test", user, "json-var", nil) + variableType, value, featureId, variationId, _, _, err := generateBucketedVariableForUser("test", user, "json-var", map[string]interface{}{"clientUUID": "clientuuid"}) require.NoError(t, err) require.Equal(t, VariableTypesJSON, variableType) require.Equal(t, "614ef6aa473928459060721a", featureId) diff --git a/bucketing/config_manager.go b/bucketing/config_manager.go index 6bbfd74b..d98f2183 100644 --- a/bucketing/config_manager.go +++ b/bucketing/config_manager.go @@ -23,7 +23,7 @@ func GetEtag(sdkKey string) string { if err != nil { return "" } - return config.etag + return config.eTag } func GetRawConfig(sdkKey string) []byte { diff --git a/bucketing/datamanager_platform.go b/bucketing/datamanager_platform.go index c5e077f9..c90cddeb 100644 --- a/bucketing/datamanager_platform.go +++ b/bucketing/datamanager_platform.go @@ -13,3 +13,11 @@ func GetClientCustomData(sdkKey string) map[string]interface{} { func SetClientCustomData(sdkKey string, data map[string]interface{}) { clientCustomData[sdkKey] = data } + +func GetConfigEtag(sdkKey string) string { + config, err := getConfig(sdkKey) + if err != nil { + return "" + } + return config.eTag +} \ No newline at end of file diff --git a/bucketing/event_queue.go b/bucketing/event_queue.go index a97d031b..8c63f2bf 100644 --- a/bucketing/event_queue.go +++ b/bucketing/event_queue.go @@ -23,6 +23,8 @@ type aggEventData struct { featureId string variationId string defaultReason string + metaData map[string]interface{} + } type userEventData struct { @@ -53,7 +55,7 @@ func (u *UserEventQueue) BuildBatchRecords() []api.UserEventsBatchRecord { return records } -func (agg *AggregateEventQueue) BuildBatchRecords(platformData *api.PlatformData) api.UserEventsBatchRecord { +func (agg *AggregateEventQueue) BuildBatchRecords(platformData *api.PlatformData, clientUUID string, configEtag string) api.UserEventsBatchRecord { var aggregateEvents []api.Event userId, err := os.Hostname() if err != nil { @@ -82,6 +84,8 @@ func (agg *AggregateEventQueue) BuildBatchRecords(platformData *api.PlatformData "_feature": feature, } } + metaData["clientUUID"] = clientUUID + metaData["configEtag"] = configEtag event := api.Event{ Type_: _type, @@ -184,7 +188,8 @@ func (eq *EventQueue) MergeAggEventQueueKeys(config *configBody) { } } -func (eq *EventQueue) queueAggregateEventInternal(variableKey, featureId, variationId, eventType string, defaultReason string) error { + +func (eq *EventQueue) queueAggregateEventInternal(variableKey, featureId, variationId, eventType string, defaultReason string, clientUUID string, configEtag string) error { if eq.options != nil && eq.options.IsEventLoggingDisabled(eventType) { return nil } @@ -200,6 +205,10 @@ func (eq *EventQueue) queueAggregateEventInternal(variableKey, featureId, variat featureId: featureId, variationId: variationId, defaultReason: defaultReason, + metaData: map[string]interface{}{ + "clientUUID": clientUUID, + "configEtag": configEtag, + }, }: default: eq.eventsDropped.Add(1) @@ -224,30 +233,32 @@ func (eq *EventQueue) QueueEvent(user api.User, event api.Event) error { return nil } -func (eq *EventQueue) QueueVariableEvaluatedEvent(variableKey, featureId, variationId string) error { +func (eq *EventQueue) QueueVariableEvaluatedEvent(variableKey, featureId, variationId string, clientUUID string, configEtag string) error { + if eq.options.DisableAutomaticEventLogging { return nil } - return eq.queueAggregateEventInternal(variableKey, featureId, variationId, api.EventType_AggVariableEvaluated, "") + return eq.queueAggregateEventInternal(variableKey, featureId, variationId, api.EventType_AggVariableEvaluated, "", clientUUID , configEtag ) } -func (eq *EventQueue) QueueVariableDefaultedEvent(variableKey, defaultReason string) error { +func (eq *EventQueue) QueueVariableDefaultedEvent(variableKey, defaultReason string, clientUUID string, configEtag string) error { if eq.options.DisableAutomaticEventLogging { return nil } - return eq.queueAggregateEventInternal(variableKey, "", "", api.EventType_AggVariableDefaulted, defaultReason) + return eq.queueAggregateEventInternal(variableKey, "", "", api.EventType_AggVariableDefaulted, defaultReason, clientUUID, configEtag) } -func (eq *EventQueue) FlushEventQueue() (map[string]api.FlushPayload, error) { +func (eq *EventQueue) FlushEventQueue(clientUUID string, configEtag string) (map[string]api.FlushPayload, error) { eq.stateMutex.Lock() defer eq.stateMutex.Unlock() var records []api.UserEventsBatchRecord - records = append(records, eq.aggEventQueue.BuildBatchRecords(eq.platformData)) + records = append(records, eq.aggEventQueue.BuildBatchRecords(eq.platformData, clientUUID, configEtag)) records = append(records, eq.userEventQueue.BuildBatchRecords()...) + fmt.Println("****Records", records) eq.aggEventQueue = make(AggregateEventQueue) eq.userEventQueue = make(UserEventQueue) eq.userEventQueueCount = 0 @@ -269,6 +280,7 @@ func (eq *EventQueue) FlushEventQueue() (map[string]api.FlushPayload, error) { } payload.AddBatchRecordForUser(record, eq.options.EventRequestChunkSize) payload.EventCount = len(payload.Records) + fmt.Println("Payload", payload) if payload.EventCount == 0 { continue } diff --git a/bucketing/event_queue_test.go b/bucketing/event_queue_test.go index 25d3ed87..6f17300d 100644 --- a/bucketing/event_queue_test.go +++ b/bucketing/event_queue_test.go @@ -87,6 +87,9 @@ func TestEventQueue_ProcessUserEvent(t *testing.T) { }, } err := SetConfig(test_config, "dvc_server_token_hash", "") + SetClientCustomData("dvc_server_token_hash", map[string]interface{}{ + "clientUUID": "clientuuid", + }) require.NoError(t, err) eq, err := NewEventQueue("dvc_server_token_hash", &api.EventQueueOptions{}, (&api.PlatformData{}).Default()) require.NoError(t, err) @@ -129,7 +132,7 @@ func TestEventQueue_AddToAggQueue(t *testing.T) { require.NoError(t, err) eq, err := NewEventQueue("dvc_server_token_hash", &api.EventQueueOptions{FlushEventsInterval: time.Hour}, (&api.PlatformData{}).Default()) require.NoError(t, err) - err = eq.QueueVariableEvaluatedEvent("somevariablekey", "featureId", "variationId") + err = eq.QueueVariableEvaluatedEvent("somevariablekey", "featureId", "variationId","","") require.NoError(t, err) require.Eventually(t, func() bool { return eq.aggQueueLength() == 1 }, 10*time.Second, time.Millisecond) } @@ -174,6 +177,9 @@ func TestEventQueue_QueueAndFlush(t *testing.T) { } err := SetConfig(test_config, "dvc_server_token_hash", "") require.NoError(t, err) + SetClientCustomData("dvc_server_token_hash", map[string]interface{}{ + "clientUUID": "clientuuid", + }) eq, err := NewEventQueue("dvc_server_token_hash", &api.EventQueueOptions{ FlushEventsInterval: time.Hour, }, api.PlatformData{}.Default()) @@ -197,7 +203,7 @@ func TestEventQueue_QueueAndFlush(t *testing.T) { require.Equal(t, 2, len(eq.userEventQueue)) require.Equal(t, 0, len(eq.userEventQueueRaw)) - payloads, err := eq.FlushEventQueue() + payloads, err := eq.FlushEventQueue("","" ) require.NoError(t, err) require.Equal(t, 2, len(payloads)) require.Equal(t, 0, len(eq.userEventQueue)) diff --git a/bucketing/model_config_body.go b/bucketing/model_config_body.go index 00a4a446..ac66d684 100644 --- a/bucketing/model_config_body.go +++ b/bucketing/model_config_body.go @@ -30,7 +30,7 @@ type configBody struct { Environment api.Environment `json:"environment" validate:"required"` Features []*ConfigFeature `json:"features" validate:"required"` Variables []*Variable `json:"variables" validate:"required,dive"` - etag string // TODO: remove etag + eTag string // TODO: remove etag variableIdMap map[string]*Variable variableKeyMap map[string]*Variable variableIdToFeatureMap map[string]*ConfigFeature @@ -95,7 +95,7 @@ func (c *configBody) compile(etag string) { c.variableIdToFeatureMap = variableIdToFeatureMap c.variableIdMap = variableIdMap c.variableKeyMap = variableKeyMap - c.etag = etag + c.eTag = etag // Sort the feature distributions by "_variation" attribute in descending alphabetical order for _, feature := range c.Features { diff --git a/client.go b/client.go index 4fc798d3..1056e124 100644 --- a/client.go +++ b/client.go @@ -17,6 +17,8 @@ import ( "strings" "time" + "github.com/google/uuid" + "github.com/devcyclehq/go-server-sdk/v2/util" "github.com/devcyclehq/go-server-sdk/v2/api" @@ -55,6 +57,7 @@ type Client struct { // Set to true when the client has been initialized, regardless of whether the config has loaded successfully. isInitialized bool internalOnInitializedChannel chan bool + clientUUID string } type LocalBucketing interface { @@ -151,6 +154,8 @@ func (c *Client) IsLocalBucketing() bool { func (c *Client) handleInitialization() { c.isInitialized = true + c.clientUUID = uuid.NewString() + c.SetClientCustomData(map[string]interface{}{"clientUUID": c.clientUUID}) if c.DevCycleOptions.OnInitializedChannel != nil { go func() { c.DevCycleOptions.OnInitializedChannel <- true @@ -467,8 +472,14 @@ func (c *Client) Track(user User, event Event) (bool, error) { return false, errors.New("event type is required") } + if(event.MetaData == nil) { + event.MetaData = make(map[string]interface{}) + } + event.MetaData["clientUUID"] = c.clientUUID + if c.IsLocalBucketing() { if c.hasConfig() { + event.MetaData["configEtag"] = c.configManager.GetETag() err := c.eventQueue.QueueEvent(user, event) if err != nil { util.Errorf("Error queuing event: %v", err) @@ -533,6 +544,7 @@ func (c *Client) FlushEvents() error { } func (c *Client) SetClientCustomData(customData map[string]interface{}) error { + customData["clientUUID"] = c.clientUUID if c.IsLocalBucketing() { if c.isInitialized { return c.localBucketing.SetClientCustomData(customData) diff --git a/client_native_bucketing.go b/client_native_bucketing.go index 99476f77..02918bf1 100644 --- a/client_native_bucketing.go +++ b/client_native_bucketing.go @@ -92,7 +92,7 @@ func (n *NativeLocalBucketing) Variable(user User, variableKey string, variableT } clientCustomData := bucketing.GetClientCustomData(n.sdkKey) populatedUser := user.GetPopulatedUserWithTime(n.platformData, DEFAULT_USER_TIME) - + resultVariableType, resultValue, err := bucketing.VariableForUser(n.sdkKey, populatedUser, variableKey, variableType, n.eventQueue, clientCustomData) if err != nil { return defaultVar, nil @@ -119,8 +119,8 @@ func (n *NativeLocalBucketing) QueueEvent(user User, event Event) error { return n.eventQueue.QueueEvent(user, event) } -func (n *NativeLocalBucketing) QueueVariableDefaulted(variableKey, defaultReason string) error { - return n.eventQueue.QueueVariableDefaultedEvent(variableKey, defaultReason) +func (n *NativeLocalBucketing) QueueVariableDefaulted(variableKey, defaultReason string, clientUUID string, configEtag string) error { + return n.eventQueue.QueueVariableDefaultedEvent(variableKey, defaultReason, clientUUID, configEtag) } func (n *NativeLocalBucketing) UserQueueLength() (int, error) { @@ -128,7 +128,9 @@ func (n *NativeLocalBucketing) UserQueueLength() (int, error) { } func (n *NativeLocalBucketing) FlushEventQueue(callback EventFlushCallback) error { - payloads, err := n.eventQueue.FlushEventQueue() + clientCustomData := bucketing.GetClientCustomData(n.sdkKey) + configEtag := bucketing.GetConfigEtag(n.sdkKey) + payloads, err := n.eventQueue.FlushEventQueue(clientCustomData["clientUUID"].(string), configEtag) if err != nil { return fmt.Errorf("Error flushing event queue: %w", err) } diff --git a/configmanager.go b/configmanager.go index c9688217..b548f1d9 100644 --- a/configmanager.go +++ b/configmanager.go @@ -137,16 +137,29 @@ func (e *EnvironmentConfigManager) fetchConfig(numRetriesRemaining int) (err err func (e *EnvironmentConfigManager) setConfigFromResponse(response *http.Response) error { config, err := io.ReadAll(response.Body) + + if err != nil { + return err + } + + configMap := make(map[string]interface{}) + err = json.Unmarshal(config, &configMap) + if err != nil { + return err + } + + configMap["eTag"] = response.Header.Get("Etag") + configWithTag, err := json.Marshal(configMap) if err != nil { return err } // Check - valid := json.Valid(config) + valid := json.Valid(configWithTag) if !valid { return fmt.Errorf("invalid JSON data received for config") } - err = e.setConfig(config, response.Header.Get("ETag")) + err = e.setConfig(configWithTag, response.Header.Get("Etag")) if err != nil { return err diff --git a/event_manager.go b/event_manager.go index d71f4507..568a79a7 100644 --- a/event_manager.go +++ b/event_manager.go @@ -17,7 +17,7 @@ type EventFlushCallback func(payloads map[string]FlushPayload) (*FlushResult, er type InternalEventQueue interface { QueueEvent(user User, event Event) error - QueueVariableDefaulted(variableKey, defaultReason string) error + QueueVariableDefaulted(variableKey, defaultReason string, clientUUID string,etag string) error FlushEventQueue(EventFlushCallback) error UserQueueLength() (int, error) Metrics() (int32, int32, int32) @@ -102,6 +102,8 @@ func (e *EventManager) QueueEvent(user User, event Event) error { default: } } + fmt.Println("QueueEvent") + fmt.Println(event) err = e.internalQueue.QueueEvent(user, event) if err != nil && errors.Is(err, ErrQueueFull) { return fmt.Errorf("event queue is full, dropping event: %+v", event) @@ -109,15 +111,14 @@ func (e *EventManager) QueueEvent(user User, event Event) error { return err } -func (e *EventManager) QueueVariableDefaultedEvent(variableKey string, defaultReason string) error { - return e.internalQueue.QueueVariableDefaulted(variableKey, defaultReason) +func (e *EventManager) QueueVariableDefaultedEvent(variableKey string, defaultReason string, clientUUID string, configEtag string) error { + return e.internalQueue.QueueVariableDefaulted(variableKey, defaultReason, clientUUID, configEtag) } func (e *EventManager) FlushEvents() (err error) { e.flushMutex.Lock() defer e.flushMutex.Unlock() - util.Debugf("Started flushing events") defer func() { if r := recover(); r != nil { diff --git a/example/cloud/main.go b/example/cloud/main.go index 92b0d6fb..d5b3842d 100644 --- a/example/cloud/main.go +++ b/example/cloud/main.go @@ -17,7 +17,7 @@ func main() { if variableKey == "" { log.Fatal("DEVCYCLE_VARIABLE_KEY env var not set: set it to a variable key") } - user := devcycle.User{UserId: "test"} + user := devcycle.User{UserId: "suthar-test-user"} dvcOptions := devcycle.Options{ EnableEdgeDB: false, EnableCloudBucketing: true, diff --git a/example/local/main.go b/example/local/main.go index 4af111cb..cc3d8e25 100644 --- a/example/local/main.go +++ b/example/local/main.go @@ -14,16 +14,16 @@ func main() { if sdkKey == "" { log.Fatal("DEVCYCLE_SERVER_SDK_KEY env var not set: set it to your SDK key") } - variableKey := os.Getenv("DEVCYCLE_VARIABLE_KEY") + variableKey :="rel" if variableKey == "" { log.Fatal("DEVCYCLE_VARIABLE_KEY env var not set: set it to a variable key") } - user := devcycle.User{UserId: "test"} + user := devcycle.User{UserId: "test-user"} dvcOptions := devcycle.Options{ EnableEdgeDB: false, EnableCloudBucketing: false, - EventFlushIntervalMS: 0, + EventFlushIntervalMS: 5, ConfigPollingIntervalMS: 10 * time.Second, RequestTimeout: 10 * time.Second, DisableAutomaticEventLogging: false, @@ -32,18 +32,20 @@ func main() { client, err := devcycle.NewClient(sdkKey, &dvcOptions) time.Sleep(10 * time.Second) - fmt.Println("Error? ", err) + if(err != nil) { + log.Fatalf("Error initializing client: %v", err) + } fmt.Println(client.GetRawConfig()) log.Printf("client initialized") features, _ := client.AllFeatures(user) for key, feature := range features { - log.Printf("Key:%s, feature:%#v", key, feature) + log.Printf("features Key:%s, feature:%#v", key, feature) } variables, _ := client.AllVariables(user) for key, variable := range variables { - log.Printf("Key:%s, variable:%#v", key, variable) + log.Printf("variables Key:%s, variable:%#v", key, variable) } existingVariable, err := client.Variable(user, variableKey, "DEFAULT") @@ -70,6 +72,12 @@ func main() { log.Printf("Warning: variable %v should be defaulted", missingVariable.Key) } + anotherVariable, _ := client.Variable(user, "anotherfea", false) + if err != nil { + log.Fatalf("Error getting variable: %v", err) + } + log.Printf("variable %v: value=%v (%v) defaulted=%t", anotherVariable.Key, anotherVariable.Value, anotherVariable.Type_, anotherVariable.IsDefaulted) + event := devcycle.Event{ Type_: "customEvent", Target: "somevariable.key", @@ -78,4 +86,8 @@ func main() { if err != nil { log.Fatalf("Error tracking event: %v", err) } + + client.FlushEvents() + time.Sleep(10 * time.Second) + }